Im very new to flutter, Im trying to do scrolling vertically and show horizontal cuisines and vertical restaurants list, for horizontal list it works fine but I don't know how to do this for the vertical list, please advice me with which is the best way to do it if I will have a huge number of restaurants in this list
SliverToBoxAdapter(//horizontal list
child: RestaurantsSlide(title: 'Featured Restaurants',),
),
SliverList(
delegate: SliverChildListDelegate(
[
//How to call the list here
],
),
),
this is the function to return the list of restaurants
void restaurantCardList() {
List<dynamic> restaurantsList = RESTAURANT_DATA;
List<Widget> listItems = [];
restaurantsList.forEach((restaurant) {
listItems.add(
Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10, bottom: 25),
child: RestaurantCard(restaurant: restaurant),
)
);
}
);
}
Related
How can you create a loop where the scrolled amount in pixels get displayed using ScrollPosition
Let's say the user scrolls up and down through the screen where he does the following,
Assume that the view is 10,000 pixels
Goes around halfway in the screen, Come backs to the top and goes somewhere around 3/4 of the view. Can you use ScrollPosition to get create a loop to get the total distance scrolled in pixels, so a number will display as, 5000+5000+7500 = 17500 pixels. Any ideas would be appreciated.
Code:
body: TabBarView(
children: [
new ListView.separated(
separatorBuilder: (context, index) => Divider(),
itemCount: 10,
itemBuilder: (context, index) => ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage("assets/images/avatar.jpg"),
),
title: Text("List Index is $index"),
),
),
])
You could create a state
double totalScrolled = 0;
in your widget definition and wrap your ListView in a NotificationListener<ScrollUpdateNotification>
NotificationListener<ScrollUpdateNotification>(
child: ListView(
),
onNotification: (notif) {
totalScrolled +=notif.scrollDelta.abs();
},
),
then simply add the absolute value of the scrollDelta to your totalScrolled
I want to add a button at the end of my GridView. I viewed another similar problem but the code given in the answer does not scroll. Here is the link to that answer.
My design has a similar. Here is a rough sketch.
Also just for clarification, I want the button to appear once the user has scrolled to the end of the grid view.
I am still new to flutter so your help would be much appreciated :)
The thing which you need is ScrollController class.
WHY SCROLLCONTROLLER?
It keeps track of what are we doing with scrolling, that is, scrolling, reached bottom, or top
HOW CAN WE USE IT?
You need to use it inside GridView, to get your things up and running
// Simply initialise your controller in your project
ScrollController _controller = new ScrollController();
// add listener to the controller to find out the scrolling event
_controller.addListener((){});
// pass this into your GridView.
// We we will add it to GridView. ScrollController is for every scrolling widget
// in Flutter
GridView.builder(
controller: _controller,
)
DISCLAIMER: Please do not look at the UI aspect, since we care about the scrolling event tracking and show/hide our button
I have referred to your given link only for creating the UI => Your Provided Link
Also, I have added scrolling event to identify whether we're scrolling or not, but it is commented
The project currently show the button when we reach the bottom, and hide it when we are the top
CODE
class _MyHomePageState extends State<MyHomePage> {
List<String> homeList = [];
//to check whether we have reached bottom
bool isBottom = false;
ScrollController _controller = new ScrollController();
#override
void initState() {
super.initState();
homeList = List.generate(10, (ind) => 'Item $ind').toList();
// adding controller to check whether the page is
// at the bottom
_controller.addListener((){
// reached bottom
if (_controller.offset >= _controller.position.maxScrollExtent &&
!_controller.position.outOfRange) {
setState(() => isBottom = true);
}
// IS SCROLLING
// if (_controller.offset >= _controller.position.minScrollExtent &&
// _controller.offset < _controller.position.maxScrollExtent && !_controller.position.outOfRange) {
// setState(() {
// isBottom = false;
// });
// }
// REACHED TOP
if (_controller.offset <= _controller.position.minScrollExtent &&
!_controller.position.outOfRange) {
setState(() => isBottom = false);
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
height: MediaQuery.of(context).size.height,
child: Stack(
children: [
GridView.builder(
shrinkWrap: true,
controller: _controller,
itemCount: homeList.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, crossAxisSpacing: 20),
itemBuilder: (ctx, i) {
return GestureDetector(
onTap: () => print(i),
child: Container(
margin: EdgeInsets.only(bottom: 20.0),
decoration: BoxDecoration(
color: Colors.indigo[300],
borderRadius: BorderRadius.circular(15.0)
)
)
);
}
),
// if we are bottom we show the button
// else empty container, which is nothing but
// hiding technique in Flutter
isBottom ? Positioned(
bottom: 20,
left: 18,
right: 18,
child: Container(
alignment: Alignment.center,
height: 50,
decoration: BoxDecoration(
color: Colors.orangeAccent,
borderRadius: BorderRadius.circular(15),
),
child: Text('Your widget at the end')
)
) : Container()
]
)
)
);
}
}
RESULT
I've been designing an App where the User searches a term and a GridView is displayed containing all the images related to that term. All of these images are made Draggable.
In another GridView on the same page, I have placed 40 Dragtargets. So the user can Drag a searched up image and place it in one of the DragTargets, thus being able to select 40 images.
The issue is that when I drag one image to the Dragtarget grid, all 40 of the dragtargets are filled up with the same image. I think this is because every Dragtarget has the same key since it was generated in an itemBuilder. But i don't know how to set a different key to each Dragtarget while generating it. Would appreciate alternative solutions in implementing the same scenarios as well !
The code for Draggable Images:
SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 350,
mainAxisSpacing: 10,
crossAxisSpacing: 10),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
child: LongPressDraggable<String>(
data: imageLinks[index],
feedback: Image(
image: NetworkImage(imageLinks[index])),
child: Image(
image: NetworkImage(imageLinks[index])),
onDragStarted: () {
panelController.close();
},
),
);
The Code of GridView and DragTargets :
GridView.builder(
itemCount: 40,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 5,),
itemBuilder: (context,index){
return Container(
padding: EdgeInsets.only(top:5,right:5,bottom:5,left:5),
child: DragTarget<String>(
builder: (context, List<String> candidateData, rejectedData) {
if (dragged == true) {
return Container(
height: 50.0,
width: 50.0,
child: Image(
image: NetworkImage(draggedImage),
),
);
} else {
return Container(
height: 50.0,
width: 50.0,
color: Colors.yellow,
);
}
},
onWillAccept: (data) {
return true;
},
onAccept: (data) {
setState(() {
dragged = true;
draggedImage = data;
//panelController.open();
});
}
),
);}
),
The problem is that you are using single variable for all dragtarget elements.
Let Me Explain in code.
onAccept: (data) {
setState(() {
dragged = true;
draggedImage = data;
//panelController.open();
});
}
In above code you set dragged value true and draggedImage value true, so every widget build with same value.
I hope i clear issue.
Solution:
To solve this issue, you can create a list of bool(if you want to keep that bool value different for all the dragtarget element also) and List of draggedImage while hold the draggedImage for each individual element, so all will not change when you change one.
I am trying to build a sample with reorderable listview that has expansion tile as its child.
Upon expanding the tile, it will present a listview to the user as follow
Expanded tile with listview nested inside
When all expansion tile are collapsed, i have no issue reordering the tiles by long pressing and moving it. But if one of the tiles are expanded, and user try to reorder the tiles, flutter will throw the following error and the expanded tile will not be able to collapse until hot reload
ScrollController attached to multiple scroll views.
'package:flutter/src/widgets/scroll_controller.dart':
Failed assertion: line 111 pos 12: '_positions.length == 1'
Not Collapsible listview
How should I go about fixing it? The issue seems to stem from having a scroll controller nested in another scroll controller. Is there a way of forcing all expansion tile to collapse upon long pressing it?
Thanks in advance
List<int> a = [1, 2, 3];
class _BlankPageState extends State<BlankPage> {
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Padding(
padding: EdgeInsets.all(10),
child: ReorderableListView(
onReorder: (oldIndex, newIndex) {
print('now');
setState(
() {
if (newIndex > oldIndex) {
newIndex -= 1;
}
final int item = a.removeAt(oldIndex);
a.insert(newIndex, item);
},
);
},
children: a.map((index) {
return ExpansionTile(
backgroundColor: Colors.grey,
key: Key('$index'),
title: Text('Tile' + '${index.toString()}'),
children: <Widget>[
Container(
height: 100,
child: ListView(children: <Widget>[
Text('This is a test' + '$index'),
Text('This is a test' + '$index'),
]),
)
],
);
}).toList()),
),
),
);
I was able to solve the above issue with the new release of Flutter 1.17 which introduced the following
Change log for Flutter 1.17.0
49148 Exposed optional scrollController property in ReorderableListView
By adding a scroll controller in my reorderablelistview, I no longer encounter the multiple scroll views error above when a list view is nested inside a reorderablelistview widget
ReorderableListView(
scrollController: ScrollController(initialScrollOffset: 50),
I have dynamic lists inside the dynamic list, My need is to save option with their attributes. I tried so many ways to show drop down of attributes for every option but DropDownMenuitem Widgets does not handle dynamic list in the stable version of flutter, so I have to use Expandable List for this purpose. When I select an attribute of an option then how can I reflect the selection of a particular option in the header or how can I save the selection of dynamic attribute
This is how i build my list
ListView.builder(
shrinkWrap: true,
itemCount: opAtrrList.length>0?opAtrrList.length:0,
itemBuilder: (context, i) {
return ExpansionTile(
title:optionTitle(width,height,opAtrrList[i].groupname,selectedAttr),
children: <Widget>[
new Column(
children: _buildExpandableContent(opAtrrList[i]),
),
],
);
},
),
This is my expandable item Attribute selectedAttr;
_buildExpandableContent(OptionAttribute oa) {
List<Widget> columnContent = [];
for(int i=0;i<oa.attrlist.length;i++){
columnContent.add(
new ListTile(
onTap: (){
setState(() {
selectedAttr=oa.attrlist[i];
});
},
title: new Text(oa.attrlist[i].attributename, style: TextStyle(fontFamily: 'medium',color: MyColors.colorPrimaryDark)),
),
);
}
return columnContent;
}
Please see the below gif.