I have seen the very good code in "Flutter: Searching Through List". However, I have a list for which I would like the user input to be compared char by char from the beginning of list items, and not if the input is contained somewhere in a list item. I.e. if the user inputs "abc", that should be compared to the first 3 chars only of list items. Can someone help on how to revise the code?
Following code will give you search results that starts with the string you give it:
List<String> searchResults = yourList.where((String item)=>item.startsWith('your_search_characters')).toList();
Demo that can be tried to verify your output:
void main() {
List<String> yourList = <String>[
'abcd', 'cabcd','dcabcd', 'abcdefg'
];
List<String> searchResults = yourList.where((String item)=>item.startsWith('ab')).toList();
print(searchResults);
}
Edited:
You can use this whole code just in _ListPersonPageState> build()
Replace:
if(_filteredList[i].personFirstName.toLowerCase().contains(filter.toLowerCase())) {
With:
if(_filteredList[i].personFirstName.toLowerCase().startsWith(filter.toLowerCase())) {
Following is the complete working code for your reference:
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
void main() => runApp(new AdvancedSearch());
class AdvancedSearch extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'List of People',
home: new ListPersonPage(title: 'List of People'),
);
}
}
class ListPersonPage extends StatefulWidget {
ListPersonPage({Key key, this.title}) : super(key: key);
final String title;
#override
_ListPersonPageState createState() => _ListPersonPageState();
}
class _ListPersonPageState extends State<ListPersonPage> {
List<Person> _personList = [];
List<Person> _filteredList = [];
TextEditingController controller = new TextEditingController();
String filter = "";
Widget appBarTitle = new Text("List of People");
Icon actionIcon = new Icon(Icons.search);
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
void initState() {
PersonDataBuilder pdb = new PersonDataBuilder();
List<Person> tmpList = new List<Person>();
for(int i=0; i < pdb.getPeople().length; i++) {
tmpList.add(pdb.getPeople()[i]);
}
setState(() {
_personList = tmpList;
_filteredList = _personList;
});
controller.addListener(() {
if(controller.text.isEmpty) {
setState(() {
filter = "";
_filteredList = _personList;
});
} else {
setState(() {
filter = controller.text;
});
}
});
super.initState();
}
#override
Widget build(BuildContext context) {
final appTopAppBar = AppBar(
elevation: 0.1,
title: appBarTitle,
actions: <Widget>[
new IconButton(
icon: actionIcon,
onPressed: () {
setState(() {
if (this.actionIcon.icon == Icons.search) {
this.actionIcon = new Icon(Icons.close);
this.appBarTitle = new TextField(
controller: controller,
decoration: new InputDecoration(
prefixIcon: new Icon(Icons.search, color: Colors.white),
hintText: "Search...",
hintStyle: new TextStyle(color: Colors.white),
),
style: new TextStyle(
color: Colors.white,
),
autofocus: true,
cursorColor: Colors.white,
);
} else {
this.actionIcon = new Icon(Icons.search);
this.appBarTitle = new Text("List of People");
_filteredList = _personList;
controller.clear();
}
});
},
),
],
);
ListTile personListTile(Person person) => ListTile(
title: Text(
person.personFirstName + " " + person.personLastName,
style: TextStyle(color: Colors.black45, fontWeight: FontWeight.bold),
),);
Card personCard(Person person) => Card(
child: Container(
decoration: BoxDecoration(color: Colors.grey[300]),
child: personListTile(person),
),
);
if((filter.isNotEmpty)) {
List<Person> tmpList = new List<Person>();
for(int i = 0; i < _filteredList.length; i++) {
if(_filteredList[i].personFirstName.toLowerCase().startsWith(filter.toLowerCase())) {
tmpList.add(_filteredList[i]);
}
}
_filteredList = tmpList;
}
final appBody = Container(
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: _personList == null ? 0 : _filteredList.length,
itemBuilder: (BuildContext context, int index) {
return personCard(_filteredList[index]);
},
),
);
return Scaffold(
appBar: appTopAppBar,
body: appBody,
);
}
}
class PersonDataBuilder {
List getPeople() {
return [
Person(
personFirstName: "John",
personLastName: "Smith"
),
Person(
personFirstName: "Alex",
personLastName: "Johnson"
),
Person(
personFirstName: "Jane",
personLastName: "Doe"
),
Person(
personFirstName: "Eric",
personLastName: "Johnson"
),
Person(
personFirstName: "Michael",
personLastName: "Eastwood"
),
Person(
personFirstName: "Benjamin",
personLastName: "Woods"
),
Person(
personFirstName: "Abraham",
personLastName: "Atwood"
),
Person(
personFirstName: "Anna",
personLastName: "Clack"
),
Person(
personFirstName: "Clark",
personLastName: "Phonye"
),
Person(
personFirstName: "Kerry",
personLastName: "Mirk"
),
Person(
personFirstName: "Eliza",
personLastName: "Wu"
),
Person(
personFirstName: "Jackey",
personLastName: "Lee"
),
Person(
personFirstName: "Kristin",
personLastName: "Munson"
),
Person(
personFirstName: "Oliver",
personLastName: "Watson"
),
];
}
}
class Person {
String personFirstName;
String personLastName;
Person(
{this.personFirstName, this.personLastName}
);
}
I hope this helps, in case of any doubts please comment.
If this answer helps you, don't forget to accept and up-vote the answer.
Related
I have the following code where I generate a list of items(data is taken from Firebase). I would like to implement a functionality to remove items but I don't know how to access the list and how to remove items:
class _MyOfferState extends State<MyOffer> {
List<Widget> items = [];
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
...
body: SingleChildScrollView(
child: Column(
children: [
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('Offers')
builder: (BuildContext context, snapshot) {
snapshot.data.docs.forEach((element) {
element.get('items').forEach((item) {
String _name = element['name'];
String _category = item['category'];
items.add(offer(name, category, context,...));
});
}
);
}
return new Column(
children: List.unmodifiable(() sync* {
yield* items;
}()),
);
},
),
}
}
This is a dynamic class where I have GestureDetector. The item should be deleted when a user clicks on the it.
dynamic offer(name, category, context,) {
return GestureDetector(
child: Container(
child: Row(
children: [
Text(name),
Text(category),
],
),
),
),
onTap: () {
// remove item should be here
},
);
}
Removing the offer from within itself is not the best practice but you can accomplish it in a number of ways. The first I can think of is to pass a function that removes it when creating the offer like this:
items.add(offer(name, category, context,..., () {
setState(() {
FirebaseFirestore.instance
.collection('Offers')
.doc(element['id'])
.delete();
items.remoev(index);
});
}));
You'll need to create the index beforehand and increase it each time but I don't recommend doing it.
The way I would done do this is change the offer to be:
dynamic offer(name, category, context,) {
return Container(
child: Row(
children: [
Text(name),
Text(category),
],
),
);
}
And when creating the offer wrap it in the GestureDetector like this:
items.add(GestureDetector(
child: offer(name, category, context,...)),
onTap: () {
setState(() {
FirebaseFirestore.instance
.collection('Offers')
.doc(element['id'])
.delete();
items.remoev(index);
});
},
);
You'll have to do the same thing with the index but I consider it a better approach since the child has no power over the parent and can't change its state which is a good practice.
you need to pass index of item and delete by index:
int index = 0;
snapshot.data.docs.forEach((element) {
element.get('items').forEach((item) {
String _name = element['name'];
String _category = item['category'];
items.add(offer(index, name, category, context,...));
index++;
});
Widget offer(int index, string name, string category, BuildContext context,) {
return GestureDetector(
child: Container(
child: Row(
children: [
Text(name),
Text(category),
],
),
),
),
onTap: () {
// remove item should be here
items.removeAt(index);
setState((){});
},
);
}
}
);
}
return new Column(
children: List.unmodifiable(() sync* {
yield* items;
}()),
);
Your list is getting build by Stream data the one you provided to your StreamBuilder, do create new list you need to change Stream value, I suggest to keep FirebaseFirestore.instance.collection('Offers') instance in a stream and modify the stream.
class _MyOfferState extends State<MyOffer> {
List<Widget> items = [];
StreamController _controller = StreamController();
#override
void initState() {
super.initState();
_controller.addStream( FirebaseFirestore.instance
.collection('Offers').snapshots());
}
// dont forgot to close stream
#override
void dispose() {
_controller.close();
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
...
body: SingleChildScrollView(
child: Column(
children: [
StreamBuilder<QuerySnapshot>(
stream: _controller.stream,
builder: (BuildContext context, snapshot) {
snapshot.data.docs.forEach((element) {
element.get('items').forEach((item) {
String _name = element['name'];
String _category = item['category'];
items.add(offer(name, category, context,(){
// remove function is here
snapshot.data.docs.removeWhere((e) => e.id == element.id);
_controller.add(snapshot.data);
});
});
}
);
}
return new Column(
children: List.unmodifiable(() sync* {
yield* items;
}()),
);
},
),
}
}
Also pass onTap to your widget function
dynamic offer(name, category, context, onTap) {
return GestureDetector(
child: Container(
child: Row(
children: [
Text(name),
Text(category),
],
),
),
),
onTap: onTap,
);
}
I want to create a list, those people location = "Barishal". That's why, I created a function and try to push data ( which data I obtained from getSpecific() function ) to a new list ( myList ). But It created a problem ....
here is my code-
class BookData extends ChangeNotifier {
List<MyModel> data = [
MyModel(name: "Abir", location: "Dhaka"),
MyModel(name: "Shuvro", location: "Barishal"),
MyModel(name: "Anik", location: "Barishal")
];
List<MyModel> get getMydata{
return data;
}
getSpecific (){
for(int i=0;i<data.length;i++){
if(data[i].location=="Barishal"){
print(data[i]);
return data[i];
}
}
}
List myList = getSpecific();
}
How can I fix this problem ?
You can copy paste run full code below
You can provide search string and use UnmodifiableListView<MyModel> and filter with _myData.where
code snippet
class BookData extends ChangeNotifier {
final List<MyModel> _myData = [
MyModel(name: "Abir", location: "Dhaka"),
MyModel(name: "Shuvro", location: "Barishal"),
MyModel(name: "Anik", location: "Barishal")
];
String _searchString = "";
UnmodifiableListView<MyModel> get books => _searchString.isEmpty
? UnmodifiableListView(_myData)
: UnmodifiableListView(
_myData.where((dog) => dog.location.contains(_searchString)));
void getSpecific(String searchString) {
_searchString = searchString;
print(_searchString);
notifyListeners();
}
}
working demo
full code
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'dart:collection';
import 'package:provider/provider.dart';
class BookData extends ChangeNotifier {
final List<MyModel> _myData = [
MyModel(name: "Abir", location: "Dhaka"),
MyModel(name: "Shuvro", location: "Barishal"),
MyModel(name: "Anik", location: "Barishal")
];
String _searchString = "";
UnmodifiableListView<MyModel> get books => _searchString.isEmpty
? UnmodifiableListView(_myData)
: UnmodifiableListView(
_myData.where((dog) => dog.location.contains(_searchString)));
void getSpecific(String searchString) {
_searchString = searchString;
print(_searchString);
notifyListeners();
}
}
class MyModel {
final String name;
final String location;
MyModel({this.name, this.location});
}
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => BookData(),
child: MyApp(),
),
);
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final _controller = TextEditingController();
String _searchText;
#override
void initState() {
_controller.addListener(
() {
setState(() {
_searchText = _controller.text;
});
},
);
super.initState();
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Example',
home: Scaffold(
appBar: AppBar(
title: Text('Example'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
TextField(
controller: _controller,
decoration: InputDecoration(
hintText: "Search",
prefixIcon: Icon(Icons.search),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(4.0),
),
),
),
onChanged: (value) {
Provider.of<BookData>(context, listen: false)
.getSpecific(value);
},
),
Consumer<BookData>(builder: (context, bookData, child) {
print(bookData.books.toString());
return Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: bookData.books.length,
itemBuilder: (context, index) => Card(
elevation: 3,
child: ListTile(
title: Text(bookData.books[index].name),
),
)),
);
}),
],
),
),
);
}
}
When you need to filter a list, you can use the where method.
Here's a simple example.
List<MyModel> myNewList = data.where((item) => item.location == "Barishal").toList();
Anyway, your code seems to be returning just the first item, not a list.
I fixed your code like below
List<MyModel> getSpecific (){
List<MyModel> result = [];
for(int i=0;i<data.length;i++){
if(data[i].location=="Barishal"){
print(data[i]);
result.add(data[i]);
}
}
return result;
}
I'm trying to sort my list alphabetically by item before showing it in a ListView.builder, and I'm not having any luck doing so. Here's my code:
class GlossaryItem {
String item;
String definition;
GlossaryItem({String i, String d}) {
item = i;
definition = d;
}
}
class Glossary {
int _glossaryNumber = 0;
List<GlossaryItem> _glossaryBank = [
GlossaryItem(
i: 'item a',
d: 'definition a',
),
GlossaryItem(
i: 'item d',
d: 'definition d',
),
GlossaryItem(
i: 'item b',
d: 'definition b',
),
GlossaryItem(
i: 'item c',
d: 'definition c',
),
];
_glossaryBank.sort((a, b) {
int compare = a.item.compareTo(b.item);
return compare;
});
int getCount() {
return _glossaryBank.length;
}
String getSpecificItem(index) {
return _glossaryBank[index].item;
}
String getSpecificDefinition(index) {
return _glossaryBank[index].definition;
}
}
I get an error on _glossaryBank.sort() saying "The name of the constructor must match the name of the enclosing class." I have gone through many pages and can't seem to get this to work.
EDIT: I changed it the following and now I don't get an error on that page:
void sort() {
_glossaryBank.sort((a, b) {
int compare = a.item.compareTo(b.item);
return compare;
});
However, when trying to initiate it, I get other errors. Here is my other page where I initiate it:
import 'package:flutter/material.dart';
import '../dictionary/glossarylist.dart';
//Call glossary
var glossary = Glossary();
glossary.sort();
class GlossaryPage extends StatefulWidget {
GlossaryPage({
Key key,
});
#override
_GlossaryPageState createState() => _GlossaryPageState();
}
class _GlossaryPageState extends State<GlossaryPage> {
Widget printDefinitions() {
return ListView.builder(
itemCount: glossary.getCount(),
itemBuilder: (BuildContext context, int index) {
// return row
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(
glossary.getSpecificItem(index) + ':',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
Text(
glossary.getSpecificDefinition(index),
style: TextStyle(
fontStyle: FontStyle.italic,
),
),
],
),
);
},
shrinkWrap: true,
physics: ClampingScrollPhysics(),
);
}
#override
Widget build(BuildContext context) {
return Container(
color: Colors.teal[300],
child: SafeArea(
child: Scaffold(
appBar: [omitted code...]
body: Padding(
padding: const EdgeInsets.all(15.0),
child: printDefinitions(),
),
),
),
);
}
}
The problem is that you have the _glossaryBank outside of a running method. You have to write something where you can execute the code.
class Glossary {
int _glossaryNumber = 0;
List<GlossaryItem> _glossaryBank = [
GlossaryItem(
i: 'item a',
d: 'definition a',
),
GlossaryItem(
i: 'item d',
d: 'definition d',
),
GlossaryItem(
i: 'item b',
d: 'definition b',
),
GlossaryItem(
i: 'item c',
d: 'definition c',
),
];
void sort() {
_glossaryBank.sort((a, b) {
int compare = a.item.compareTo(b.item);
return compare;
});
}
}
and wherever you initiate the class, you have to use it
var glossary = Glossary();
glossary.sort();
I created a small CodePen about how it could work.
https://codepen.io/md-weber/pen/bGVjdap
In the 'Categories' class I have a list of elements. This list will be completed with more categories from Firebase. I want to read this list in another view (showCategories.dart) and thus output it in the other (showCategories.dart) view.
How can I pass the list to another view and access the elements of the list in this other view?
Code for categories.dart
class Categories with ChangeNotifier {
List<Category> _cats = [
Category(
id: 'c1',
titel: 'Kategorie #1',
bezeichnung: 'Erste Kategorie',
gruppe: '1',
),
Category(
id: 'c2',
titel: 'Kategorie #2',
bezeichnung: 'Zweite Kategorie',
gruppe: '2',
),
Category(
id: 'c3',
titel: 'Kategorie #3',
bezeichnung: 'Dritte Kategorie',
gruppe: '3',
),
];
List<Category> get cats {
return [..._cats];
}
get length => null;
Category findById(String id) {
return _cats.firstWhere(
(prod) => prod.id == id
);
}
Future<void> fetchAndSetCategories() async {
const url = 'https://....firebaseio.com/categories.json';
//print(_cats);
try {
final response = await http.get(url);
final extractedData = json.decode(response.body) as Map<String, dynamic>;
final List<Category> loadedCategories = [];
extractedData.forEach((catId, catData) {
loadedCategories.add(Category(
id: catId,
titel: catData['titel'],
bezeichnung: catData['bezeichnung'],
gruppe: catData['gruppe'],
));
});
_cats = loadedCategories;
notifyListeners();
} catch(error) {
throw error;
}
}
}
Code for viewCategories.dart
class ViewCategories extends StatefulWidget {
#override
_ViewCategoriesState createState() => _ViewCategoriesState();
}
class _ViewCategoriesState extends State<ViewCategories> {
#override
void initState() {
Provider.of<Categories>(context, listen: false).fetchAndSetCategories();
super.initState();
}
}
You can copy paste run full code below
You can directly use Consumer to access data of your model
code snippet
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => Categories(),
child: MyApp(),
),
);
}
...
return Scaffold(
body: Consumer<Categories>(builder: (context, categoryData, child) {
print(categoryData.cats.toString());
return ListView.builder(
shrinkWrap: true,
itemCount: categoryData.cats.length,
itemBuilder: (context, index) => Card(
elevation: 3,
child: ListTile(
title: Text(categoryData.cats[index].titel),
),
));
}),
);
working demo
full code
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:provider/provider.dart';
import 'dart:convert';
class ViewCategories extends StatefulWidget {
#override
_ViewCategoriesState createState() => _ViewCategoriesState();
}
class _ViewCategoriesState extends State<ViewCategories> {
#override
void initState() {
//Provider.of<Categories>(context, listen: false).fetchAndSetCategories();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Consumer<Categories>(builder: (context, categoryData, child) {
print(categoryData.cats.toString());
return ListView.builder(
shrinkWrap: true,
itemCount: categoryData.cats.length,
itemBuilder: (context, index) => Card(
elevation: 3,
child: ListTile(
title: Text(categoryData.cats[index].titel),
),
));
}),
);
}
}
class Category {
String id;
String titel;
String bezeichnung;
String gruppe;
Category({this.id, this.titel, this.bezeichnung, this.gruppe});
}
class Categories with ChangeNotifier {
List<Category> _cats = [
Category(
id: 'c1',
titel: 'Kategorie #1',
bezeichnung: 'Erste Kategorie',
gruppe: '1',
),
Category(
id: 'c2',
titel: 'Kategorie #2',
bezeichnung: 'Zweite Kategorie',
gruppe: '2',
),
Category(
id: 'c3',
titel: 'Kategorie #3',
bezeichnung: 'Dritte Kategorie',
gruppe: '3',
),
];
List<Category> get cats {
return [..._cats];
}
get length => null;
Category findById(String id) {
return _cats.firstWhere((prod) => prod.id == id);
}
Future<void> fetchAndSetCategories() async {
const url = 'https://....firebaseio.com/categories.json';
//print(_cats);
try {
/*final response = await http.get(url);
final extractedData = json.decode(response.body) as Map<String, dynamic>;
final List<Category> loadedCategories = [];
extractedData.forEach((catId, catData) {
loadedCategories.add(Category(
id: catId,
titel: catData['titel'],
bezeichnung: catData['bezeichnung'],
gruppe: catData['gruppe'],
));
});*/
final List<Category> loadedCategories = [];
loadedCategories.add(Category(
id: "c9",
titel: 'c9 titel',
bezeichnung: 'c9 bezeichnung',
gruppe: 'c9 gruppe',
));
loadedCategories.add(Category(
id: "c19",
titel: 'c19 titel',
bezeichnung: 'c19 bezeichnung',
gruppe: 'c19 gruppe',
));
_cats = loadedCategories;
notifyListeners();
} catch (error) {
throw error;
}
}
}
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => Categories(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Demo'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Consumer<Categories>(builder: (context, categoryData, child) {
print(categoryData.cats.toString());
return Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: categoryData.cats.length,
itemBuilder: (context, index) => Card(
elevation: 3,
child: ListTile(
title: Text(categoryData.cats[index].titel),
),
)),
);
}),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Provider.of<Categories>(context, listen: false).fetchAndSetCategories();
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ViewCategories()),
);
},
child: Icon(Icons.navigation),
backgroundColor: Colors.green,
));
}
}
I am new to programming with flutter and Im trying to create a pizza app. first you create the pizza, choosing the ingredients, then you get a list of your order. The list works and the qr generator as well but they are from separate tutorials and I am having issues connecting them. I cant seem to pass the order list to the generator.
import 'package:flutter/material.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:flutter/services.dart';
import 'dart:async';
import 'dart:typed_data';
import 'dart:ui';
import 'dart:io';
import 'package:flutter/rendering.dart';
import 'package:path_provider/path_provider.dart';
import 'package:pizza_app/screens/review.dart';
import 'package:pizza_app/code/pizza.dart';
class GenerateQR extends StatefulWidget {
List<String> _list = new List<String>();
#override
State<StatefulWidget> createState() => GenerateQRState();
GenerateQR(list){
_list = list;
}
}
class GenerateQRState extends State<GenerateQR> {
static const double _topSectionTopPadding = 50.0;
static const double _topSectionBottomPadding = 20.0;
static const double _topSectionHeight = 50.0;
GlobalKey globalKey = new GlobalKey();
List<String> _dataList = new List<String>();
//String _dataString = "Hello from this QR";
String _inputErrorText;
final TextEditingController _textController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('QR Code Generator'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.share),
onPressed: _captureAndSharePng,
)
],
),
body: _contentWidget(),
);
}
Future<void> _captureAndSharePng() async {
try {
RenderRepaintBoundary boundary = globalKey.currentContext.findRenderObject();
var image = await boundary.toImage();
ByteData byteData = await image.toByteData(format: ImageByteFormat.png);
Uint8List pngBytes = byteData.buffer.asUint8List();
final tempDir = await getTemporaryDirectory();
final file = await new File('${tempDir.path}/image.png').create();
await file.writeAsBytes(pngBytes);
final channel = const MethodChannel('channel:me.alfian.share/share');
channel.invokeMethod('shareFile', 'image.png');
} catch(e) {
print(e.toString());
}
}
_contentWidget() {
final bodyHeight = MediaQuery.of(context).size.height - MediaQuery.of(context).viewInsets.bottom;
return Container(
color: const Color(0xFFFFFFFF),
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(
top: _topSectionTopPadding,
left: 20.0,
right: 10.0,
bottom: _topSectionBottomPadding,
),
child: Container(
height: _topSectionHeight,
child: Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: TextField(
controller: _textController,
decoration: InputDecoration(
hintText: "Enter a custom message",
errorText: _inputErrorText,
),
),
),
Padding(
padding: const EdgeInsets.only(left: 10.0),
child: FlatButton(
child: Text("SUBMIT"),
onPressed: () {
setState((){
_dataList.add(_list); // This must be wrong
_inputErrorText = null;
});
},
),
)
],
),
),
),
Expanded(
child: Center(
child: RepaintBoundary(
key: globalKey,
child: QrImage(
data: _dataList,// I think that there is an error here too
size: 0.5 * bodyHeight,
onError: (ex) {
print("[QR] ERROR - $ex");
setState((){
_inputErrorText = "Error! Maybe your input value is too long?";
});
},
),
),
),
),
],
),
);
}
}
Use Iterable.Join() to join your list of strings into a single string, using a suitable separator like the pipe (|) symbol:
Handle the case where somebody types the | character into the TextField.
The code that reads the QR code can use String.split() to split the string into a list of strings again.