I'm trying to create a ListView and would only want the first item to be padded. Here is the code:
Expanded(
child: ListView.builder(
padding: EdgeInsets.all(16),
itemCount: card.length,
itemBuilder: (context, index) {
if (index == 0) {
return MyCard.buildRecordCard(
card[index], context);
} else {
return MyCard.buildRecordsCards(
card[index], context, index);
}
},
),
);
The output looks as follows:
but I want cards 2...n (i.e. index != 0) not to be padded and to stretch out to the end of the screen. Something like this:
if (index == 0) {
padding: EdgeInsets.all(16),
return MyCard.buildRecordCard(
card[index], context);
} else {
padding: 0,
return MyCard.buildRecordsCards(
card[index], context, index);
}
but that obviously doesn't work.
You just needed to wrap the widget with Padding.
simply you can use ternary like
itemBuilder: (context, index) {
return Padding(
padding: index == 0 ? EdgeInsets.all(16) : EdgeInsets.zero,
child: MyCard.buildRecordCard(card[index], context));
},
Solved.
I just added the padding to the item I was building by wrapping it in a container as follows:
Container(
padding: EdgeInsets.fromLTRB(16, 16, 16, 0),
child: ...ListTile...
Related
I have a ListView I'm initializing with ListView.builder() and it seems to be loading all items at once. This is the code:
ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (context, index) {
if (index == length) {
Future.delayed(Duration(seconds: 2)).then((value) {
setState(() => length += 10);
});
return Center(child: CircularProgressIndicator());
}
return Container(
color: Colors.red,
padding: EdgeInsets.all(24.0),
margin: EdgeInsets.all(12.0),
child: Text(index.toString()),
);
},
itemCount: length + 1,
)
This ListView is wrapped in another ListView. I'm trying to make a network call to load more items once I hit the bottom of the list, but it just gets called over and over again even when I haven't scrolled to the bottom. Is this because I have it nested in a second ListView?
Desired Layout Current Layout I've been trying to play around with Rows and Columns but it's not giving me the desired layout. I'm stumped with how to make the bottom row overlap with the top. I'm using a ListView.builder to generate these containers dynamically. This is my code for the ListView.builder:
ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: moduleCount,
itemBuilder: (BuildContext context, int index) {
/*
Makes graphicModule decrease in size as more
modules are being displayed
*/
if (moduleCount > 6) {
containerWidth = 112.5;
} else {
containerWidth = 150;
}
if (index.isEven) {
return Column(
children: <Widget>[
makeGraphicModule(
index + 1, containerWidth, moduleCount),
SizedBox(
height: 50,
),
],
);
} else {
return Column(
children: <Widget>[
SizedBox(
height: 50,
),
makeGraphicModule(
index + 1, containerWidth, moduleCount),
],
);
}
},
),
Use margin top for the odd containers
ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: moduleCount,
itemBuilder: (BuildContext context, int index) {
if (moduleCount > 6) {containerWidth = 112.5;}
else {containerWidth = 150;}
return Container(
margin: EdgeInsets.only(top: index.isEven ? 0 : 50),
child: makeGraphicModule(
index + 1, containerWidth, moduleCount),
);,
}
),
The ListView looks the way I was hoping but I haven't found an option for the else statement that will let me end it there. Right now I can put a Text widget there but it continues to generate these infinite times when the user scrolls vertically. I'd like to be able to stop the ListView after the singleChildScrollView.
Have tried empty Container, SizedBox.shrink. and SizedBox with height and width of 0.0.
child: ListView.builder(itemBuilder: (context, index) {
if (index == 0) {
return Container(
margin: EdgeInsets.all(20.0),
alignment: Alignment.center,
child: Image.file(photos[0].name),
);
}
else if (index == 1) {
var singleChildScrollView = SingleChildScrollView(
child: Row(
children: pics,
),
scrollDirection: Axis.horizontal,
);
return singleChildScrollView;
}
else {
return Text('empty space');
}
}),
try adding to the listview an itemCount, for example:
child: ListView.builder(
itemCount: 3,
itemBuilder: (context, index) {
if (index == 0) {
return Container(
margin: EdgeInsets.all(20.0),
alignment: Alignment.center,
child: Image.file(photos[0].name),
);
}
else if (index == 1) {
var singleChildScrollView = SingleChildScrollView(
child: Row(
children: pics,
),
scrollDirection: Axis.horizontal,
);
return singleChildScrollView;
}
else {
return Text('empty space');
}
}),
Change to:
child: ListView.builder(
itemCount: 3,
itemBuilder: (context, index) {
if (index == 0) {
return Container(
margin: EdgeInsets.all(20.0),
alignment: Alignment.center,
child: Image.file(photos[0].name),
);
}
else if (index == 1) {
var singleChildScrollView = SingleChildScrollView(
child: Row(
children: pics,
),
scrollDirection: Axis.horizontal,
);
return singleChildScrollView;
}
else {
return Text('empty space');
}
}),
Using flutter, what is the easiest and cleanest way to place a separator not only between the rows, but also as the first and last row ?
I am able to do so by faking the itemCount and adding to extra rows.
...
child: ListView.separated(
// Offset itemCount to start with separator
itemCount: sortedList.length + 2,
itemBuilder: (context, index) {
if (index == 0) {
return SizedBox(height: 0.0);
}
if (index == sortedList.length + 1) {
return SizedBox(height: 0.0);
}
return ListItem(...);
},
separatorBuilder: (context, index) {
return SizedBox(height: 10.0);
}))),
I'm afraid this is as clean as we can get with ListView.separated
ListView.separated(
separatorBuilder: (context, index) => const Divider(height: 1.0,),
itemCount: 2 + boardList.length,
itemBuilder: (context, index) {
if (index == 0 || index == boardList.length + 1) return const SizedBox.shrink();
return MenuItem(
board: boardList[index - 1],
isSelected: boardList[index].id == selectedBoardId
);
},
);
Another way is to use ListView.builder and wrap your item a container with border bottom
ListView.builder(
itemCount: boardList.length,
itemBuilder: (context, index) {
return Container(
decoration: BoxDecoration(
color: (widget.isSelected) ? Colors.grey[50] : color,
border: Border(
top: (index == 0) ? BorderSide(color: Theme.of(context).dividerColor) : BorderSide.none
bottom: BorderSide(color: Theme.of(context).dividerColor)
)
)
),
},
);
You can wrap your ListView.serarated in another ListView and then put your Dividers before and after the ListView.separated. But you need to define the scrollDirection and shrinkWrap as shown in the example. Otherwise, you will get an error for unbounded hight. As separators, I used the Divider-Widget but you can use whatever you want.
ListView(
children: <Widget>[
Divider(),
ListView.separated(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemBuilder: // ...
separatorBuilder: // ...
itemCount: // ...
),
Divider(),
],
),
I have RefreshIndicator, there's a ListView inside。When the content of the ListView doesn't exceed the viewPort,(which means it's not scrollable yet), RefreshIndicator isn't available。
Amazingly, RefreshIndicator works when I remove the controller and physics
But my code has to listen on _scrollController, so it can't be deleted, so is there any other solution
child: RefreshIndicator(
color: WColors.theme_color,
child: ListView.builder(
controller: _scrollController,
physics: BouncingScrollPhysics(),
shrinkWrap: false,
itemBuilder: (BuildContext context, int index) {
if (datas == null || datas.length == 0) {
return Container(
height: pt(400),
alignment: Alignment.center,
child: datas == null
? CupertinoActivityIndicator()
: Text(
res.allEmpty,
style: TextStyle(fontSize: 18),
),
);
} else {
if (index != datas.length) {
return TodoItem(
index,
datas[index],
);
} else {
return Container(
width: double.infinity,
height: pt(45),
alignment: Alignment.center,
child: (currentPage < totalPage)
? CupertinoActivityIndicator()
: Text(
res.isBottomst,
style: TextStyle(color: WColors.hint_color),
),
);
}
}
},
itemCount:
(datas == null || datas.length == 0) ? 1 : datas.length + 1,
),
onRefresh: _refreshAuto),
);
If you want to use the RefreshIndicator always , even when your List is small, you just have to replace the physics you are using by AlwaysScrollableScrollPhysics().
ListView.builder(
controller: _scrollController,
physics: const AlwaysScrollableScrollPhysics()
shrinkWrap: false,
itemBuilder: (BuildContext context, int index) {