First of all, I have class CheckList, in it I have list checkLists and many other variablse like name,position and others, in this list i have CheckList objects.
So in Dismissible key i pass CheckList.checkLists[index] but i got this error
The argument type 'CheckList' can't be assigned to the parameter type 'Key'
Scaffold(
body: Container(
padding: EdgeInsets.all(14.0),
child: ListView.separated(
itemCount: CheckList.checkLists.length,
itemBuilder: (BuildContext Context, int index){
return Dismissible(
key: CheckList.checkLists[index],
child: InkWell(
),
);
},
separatorBuilder: (BuildContext context, int index) {
return Container(
height: 14,
);
}),
),
);
what i need to pass into key?
Second question
Item in ListView must looks like this. This is item from other ListView in my app but i need same with other data in new ListView item
Will my Dismissble item dismiss normaly with this type of code?
Scaffold(
body:
Container(
padding: EdgeInsets.all(14.0),
child: ListView.separated(
itemCount: CheckList.checkListtemplateXmlList.length,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: (){
CheckList checkList = CheckList();
CheckList.addCheckList(index,checkList);
showDialog(context: context, builder: (BuildContext context){
return AlertDialog(
title: Text('Добавить описание'),
content: TextField(
onChanged: (String value) async{
checkList.description = value;
},
),
actions: [
ElevatedButton(onPressed: () async{
await checkList.writeToFile();
setState(() {
CheckList.checkLists.add(checkList);
});
Navigator.pushNamedAndRemoveUntil(context, '/',(route) => false );
},
child: Text('Добавить'))
],
);
});
},
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: Color.fromARGB(255, 141, 166, 255), width: 1),
borderRadius: BorderRadius.circular(10)),
width: 50,
height: 80,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"${CheckList.checkListTempaltexmlNameList[index]}",
style: TextStyle(fontSize: 40),
)
],
),
),
);
},
separatorBuilder: (BuildContext context, int index) {
return Container(
height: 14,
);
}),
),
);
The key parameter needs a Key object.
You can either pass
UniqueKey() which will generate a unique key automatically for you
ValueKey(dynamic value) if you want to generate one from some variable. In you case that would be ValueKey(CheckList.checkLists[index]).
Related
I am trying to list out a few texts after a bottom sheet opens, this is dynamic and comes from an API. Once the bottom sheet function is triggered, the API is called and the list view updates. In this list view I used CheckboxListTile, the problem is I am not able to do multiple selections (nor single select) on the checkboxes.
This is what I have so far:
var selectedIndex = [];
The above code is in the _MainScreenState and the function for the bottom screen is triggered in one of the buttons as:
...
onPressed: () {
_showModalBottomSheet(context).then((value) => setState(() {
index = value;
}));
}
...
Bottom sheet code
Future<AllApps?> _showModalBottomSheet(BuildContext context) {
return showModalBottomSheet<AllApps>(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
clipBehavior: Clip.antiAliasWithSaveLayer,
context: context,
isScrollControlled: true,
builder: (context) {
return FractionallySizedBox(
heightFactor: 0.9,
child: Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(150.0, 20.0, 150.0, 20.0),
child: Container(
height: 8.0,
width: 80.0,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(20.0),
),
),
),
FutureBuilder<AllApps>(
future: getAllApps(), // <- API call
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
shrinkWrap: true,
physics: const ScrollPhysics(),
itemCount: snapshot.data?.data.length,
itemBuilder: (context, index) {
final app = snapshot.data?.data[index];
return CheckboxListTile(
enableFeedback: true,
title: Text(app!.name),
value: selectedIndex.contains(app.id),
onChanged: (_) {
if (selectedIndex.contains(app.id)) {
setState(() {
selectedIndex.remove(app.id);
});
} else {
setState(() {
selectedIndex.add(app.id);
});
}
},
);
},
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return const Center(child: CircularProgressIndicator());
},
),
Padding(
padding: const EdgeInsets.only(top: 20.0, right: 5.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.only(right: 8.0),
child: ElevatedButton(
child: const Text('Cancel'),
onPressed: () {
Navigator.pop(context);
},
),
),
ElevatedButton(
child: const Text('Save'),
onPressed: () {
Navigator.pop(context);
},
),
],
),
)
],
),
);
});
}
I am able to see the lists being built but I am not able to select any one of them (gif screenshot):
How should I enable multiple selections?
In order to apply changes in the state to the modal, use StateFulBuilder:
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (context) {
return StatefulBuilder( // this is new
builder: (BuildContext context, StateSetter setState) {
return FractionallySizedBox(
heightFactor: 0.9,
child: Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(150.0, 20.0, 150.0, 20.0),
child: Container(
height: 8.0,
width: 80.0,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(20.0),
),
),
),
FutureBuilder<AllApps>(
future: getAllApps(), // <- API call
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
shrinkWrap: true,
physics: const ScrollPhysics(),
itemCount: snapshot.data?.data.length,
itemBuilder: (context, index) {
final app = snapshot.data?.data[index];
return CheckboxListTile(
enableFeedback: true,
title: Text(app!.name),
value: selectedIndex.contains(app.id),
onChanged: (_) {
if (selectedIndex.contains(app.id)) {
setState(() {
selectedIndex.remove(app.id);
});
} else {
setState(() {
selectedIndex.add(app.id);
});
}
},
);
},
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return const Center(child: CircularProgressIndicator());
},
),
Padding(
padding: const EdgeInsets.only(top: 20.0, right: 5.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.only(right: 8.0),
child: ElevatedButton(
child: const Text('Cancel'),
onPressed: () {
Navigator.pop(context);
},
),
),
ElevatedButton(
child: const Text('Save'),
onPressed: () {
Navigator.pop(context);
},
),
],
),
)
],
),
);
});
});
You can use StatefulBuilder for providing setState in bottom sheet. Try as follows:
return StatefulBuilder(
builder:(BuildContext context,setState){
return FractionallySizedBox(....);
})
In documentation of Hive we have delete method for deleting something from database, but this method don't delete from database and it only do null on index of found data and it cause some problem when we want to listen to database changes or making ListView with null data,
another problem is .values that return non-nullable data and when we try to make a ListView we get null error
late Box<Sal> _sal;
useEffect((){
_sal = Hive.box<Sal>('sal') ;
});
// ...
ValueListenableBuilder(
valueListenable: _sal.listenable(),
builder: (_, Box<Sal> sal, __) => ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.zero,
itemBuilder: (context, index) {
return Container(
height: 50.0,
margin: EdgeInsets.symmetric(vertical: 0.0),
child: Card(
color: DefaultColors.$lightBrown,
child: Row(
children: [
CText(
text: _sal.get(index)!.salName,
color: Colors.white,
style: AppTheme.of(context).thinCaption(),
).pOnly(right: 16.0),
const Spacer(),
IconButton(
icon: Icon(
Icons.edit,
color: Colors.yellow,
),
onPressed: () => showGeneralDialog(
//...
),
),
IconButton(
icon: Icon(
Icons.delete,
color: Colors.white,
),
onPressed: () => showGeneralDialog(
//...
),
),
],
),
),
);
},
itemCount: _sal.values.length,
),
).pSymmetric(
h: 16,
),
//...
}
I found solution for this problem
late Box<Sal> _sal;
late List<Sal> _data;
useEffect(() {
_sal = Hive.box<Sal>('sal');
_data = _sal.values.toList();
});
//...
ValueListenableBuilder(
valueListenable: Hive.box<Sal>('sal').listenable(),
builder: (_, Box<Sal> sal, __) {
_data = _sal.values.toList();
return ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.zero,
itemBuilder: (context, index) {
return Container(
height: 50.0,
margin: EdgeInsets.symmetric(vertical: 0.0),
);
},
itemCount: _data.length,
);
},
),
//...
I have a simple json parser and listing the news and their categories
now I am trying to do some optimisations on ListTile because I would like to use the news Images bigger and put the news title under but ListTile provide only trailing which it is unusable for me. But I can't add any styling in whole code (new child, Row, etc gives error.) Is it possible to do that in this structure or should I make a customListTile on another page and link the current mechanism to new page?
any help would be really nice
body: Container(
padding: const EdgeInsets.all(
10.0,
),
child: FutureBuilder<Articles>(
future: _futureArticles,
builder: (BuildContext context, AsyncSnapshot<Articles> snapshot) {
if (snapshot.hasData) {
final articles = snapshot.data?.data;
return ListView.builder(
padding: const EdgeInsets.all(
10.0,
),
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: articles!.length,
itemBuilder: (BuildContext context, int index) {
return Card(
elevation: 4.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: ListTile(
title: Text(
'Title: ${articles[index].title}',
),
subtitle:
Text('Category: ${articles[index].category?.name}'),
trailing: Image.network(articles[index].imageUrl!),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NewsViewDetail(
id: articles[index].id!,
),
fullscreenDialog: true,
),
);
},
),
);
},
);
} else if (snapshot.hasError) {
return NewsError(
errorMessage: '${snapshot.hasError}',
);
} else {
return const NewsLoading(
text: 'Loading...',
);
}
},
),
),
);
}
}
Try below answer hope its help to you ,use GridView.builder() instead of ListView.builder()
Container(
padding: EdgeInsets.all(10),
child: GridView.builder(
itemCount: 5,//use your length here(articles!.length)
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 1),
itemBuilder: (context, index) {
return Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade200),
),
margin: EdgeInsets.all(5),
padding: EdgeInsets.all(5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Image.network(
'your network image here',
fit: BoxFit.fill,
),
),
SizedBox(
height: 15,
),
Text(
'Your headline here',
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
],
),
);
},
),
);
your screen look like ->
I have 2 specific Widget which the first One has a RaisedButton which should be clicked and the widget with the RaisedButton will be substitute with another one.
this is my code:
Widget FundsWidget() {
return Container(
height: 200,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Devi acquistare dei crediti per poter vedere i Post di ${widget.user.name}',
style: TextStyle(fontSize: 12),
),
RaisedButton(
elevation: 10,
color: Colors.blue,
child: Text('Acquista Crediti'),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => PostGrid(),
),
),
),
],
),
);
}
and this is called into the main build method, once RaisedButton is clicked, should be substited by another one
Widget PostGrid() {
return Container(
height: 291,
child: GridView.builder(
controller: controller,
itemCount: widget.user.imageUrl.length + 1,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
),
itemBuilder: (BuildContext context, int index) {
if (index == widget.user.imageUrl.length) {}
return GestureDetector(
onTap: () => showDialog(
context: context,
builder: (context) => AlertDialog(
actions: [
Image.asset(widget.user.imageUrl),
Text(widget.user.name),
],
),
),
child: Card(
elevation: 5,
child: Image.asset(widget.user.imageUrl),
),
);
},
),
);
}
that at the moment is not into the build method.
how I can perform that?
I think you can use setState method inside your onPresesd and change a bool in it.
and check that bool to set suitable widget like below pattern:
class Test2 extends StatefulWidget {
#override
_Test2State createState() => _Test2State();
}
class _Test2State extends State<Test2> {
bool boolName = true;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child:boolName ?FontWeight:PostGrid ));
}
Widget FundsWidget() {
return Container(
height: 200,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Devi acquistare dei crediti per poter vedere i Post di ${widget.user.name}',
style: TextStyle(fontSize: 12),
),
RaisedButton(
elevation: 10,
color: Colors.blue,
child: Text('Acquista Crediti'),
onPressed: () {
setState(() {
boolName = false;
});
}
),
),
],
),
);
}
Widget PostGrid() {
return Container(
height: 291,
child: GridView.builder(
controller: controller,
itemCount: widget.user.imageUrl.length + 1,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
),
itemBuilder: (BuildContext context, int index) {
if (index == widget.user.imageUrl.length) {}
return GestureDetector(
onTap: () => showDialog(
context: context,
builder: (context) => AlertDialog(
actions: [
Image.asset(widget.user.imageUrl),
Text(widget.user.name),
],
),
),
child: Card(
elevation: 5,
child: Image.asset(widget.user.imageUrl),
),
);
},
),
);
}
}
I m using firestore for data and firestorage for files and images, so i m using StreamBuilder to load list as per firestore data and i want to download images as per firestore file name, but its not happening
I tried is, created a new method there I did code to get download url , but it is not working
child: StreamBuilder(
stream: Firestore.instance.collection('data').snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData)
return Container(
child: Center(child: CircularProgressIndicator()));
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Column(
children: <Widget>[
Card(
semanticContainer: true,
clipBehavior: Clip.antiAliasWithSaveLayer,
child: Image.network(
imageLoader(snapshot.data.documents[index].data['flie_ref'].toString()),
fit: BoxFit.fill,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0),
),
elevation: 0,
margin: EdgeInsets.all(10),
),
Padding(
padding: EdgeInsets.only(left: 6, right: 6),
child: Card(
elevation: 0,
child: ExpansionTile(
leading: CircleAvatar(
child: Text(snapshot
.data.documents[index].data['amount']
.toString()),
),
title: Text(
snapshot
.data.documents[index].data['desc']
.toString(),
overflow: TextOverflow.ellipsis,
),
children: <Widget>[
Text(snapshot
.data.documents[index].data['desc']
.toString()),
SizedBox(
height: 10,
),
],
),
),
),
],
),
);
});
},
),
Future imageLoader(String string) async {
var url =
await FirebaseStorage.instance.ref().child(string).getDownloadURL();
setState(() {
return url;
});
}
I expect output load respective image but the output is Error: The argument type 'Future' can't be assigned to the parameter type 'Widget'