I want to make this design in flutter I have tried in row, but it's going to overflow. So, you
can help me to make this using any another way!
Ok, writing Chips with Containers like other answers suggest is not necessary. Because you actually have chips widgets in Flutter. Please check them out, they are well documented and have examples provided.
https://api.flutter.dev/flutter/material/FilterChip-class.html
https://api.flutter.dev/flutter/material/ChoiceChip-class.html
https://api.flutter.dev/flutter/material/InputChip-class.html
here is the exact coding , I used in my project, it might help u...
change according to your design..
class HomeScreen_Coffee extends StatefulWidget {
const HomeScreen_Coffee({Key? key}) : super(key: key);
#override
State<HomeScreen_Coffee> createState() => _HomeScreen_CoffeeState();
}
class _HomeScreen_CoffeeState extends State<HomeScreen_Coffee> {
List<String> titles=['All','Fav','Popular','Trending'
];
int selectedindex=0;
#override
Widget build(BuildContext context) {
return Scaffold(
body:
Container(
height: 40,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: titles.length,
itemBuilder: (context,index){
return CoffeeTile(name: titles[index], ontap: (){
selectedindex=index;
setState(() {
});
},isselected: selectedindex==index,);
}),
),
));
}
}
class CoffeeTile extends StatelessWidget {
final String name;
final bool isselected;
final VoidCallback ontap;
const CoffeeTile({Key? key,required this.name,this.isselected=false,required this.ontap}) : super(key: key);
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 12.0),
child: GestureDetector(
onTap: ontap,
child: Container(
decoration: BoxDecoration(
color: Colors.white12,
borderRadius: BorderRadius.circular(20),
),
padding: EdgeInsets.symmetric(horizontal: 20),
child: Center(
child: Text(name.toString(),style: TextStyle(
fontSize: 18,color: isselected?Colors.orange:Colors.grey,fontWeight: FontWeight.bold
),),
),
),
),
);
}
}
define variable for selected Index.
int selectedIndex = 0;
Just Put in your widget
SizedBox(
height: 40,
child: ListView.builder(
itemCount: 20,
scrollDirection: Axis.horizontal,
shrinkWrap: true,
physics: BouncingScrollPhysics(),
itemBuilder: (context, index) {
return InkWell(
onTap: () {
selectedIndex = index;
setState(() {});
},
child: Container(
margin: EdgeInsets.symmetric(horizontal: 5),
decoration: BoxDecoration(
color: selectedIndex == index ? Colors.blueAccent.shade100 : Colors.white,
borderRadius: BorderRadius.circular(30),
),
padding: EdgeInsets.symmetric(vertical: selectedIndex == index ? 12 : 10, horizontal: selectedIndex == index ? 18 : 15),
child: Text("Text $index", style: TextStyle(color: selectedIndex == index ? Colors.white : Colors.grey, fontSize: selectedIndex == index ? 15 : 12)),
),
);
},
),
)
I Hope this will solve your issue.
Related
https://www.veed.io/view/a97effbf-7aad-4c0a-8fd7-8fce2be4808e?sharingWidget=true&panel=share
I hate how when I slide between screens the layout overlaps to the next screen before rendering what's supposed to be there. How do I fix this?
This is the code for the page:
class StallPage extends StatefulWidget {
final Stall stall;
const StallPage({super.key, required this.stall});
#override
State<StallPage> createState() => _StallPageState();
}
class _StallPageState extends State<StallPage> {
var selected = 0;
final pageController = PageController();
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xff392850), //kBackground,
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CustomAppBar(
Icons.arrow_back_ios_outlined,
Icons.search_outlined,
leftCallback: () => Navigator.of(context).pop(),
rightCallback: () => Navigator.of(context).pushNamed(searchRoute),
),
StallInfo(
stall: widget.stall,
), //
FoodList(
selected,
(int index) {
setState(() {
selected = index;
});
pageController.jumpToPage(index);
},
widget.stall,
),
Expanded(
child: FoodListView(
selected,
(int index) {
setState(() {
selected = index;
});
},
pageController,
widget.stall,
),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 25),
height: 60,
child: SmoothPageIndicator(
controller: pageController,
count: widget.stall.menu.length,
effect: CustomizableEffect(
dotDecoration: DotDecoration(
width: 8,
height: 8,
color: Colors.grey.withOpacity(0.5),
borderRadius: BorderRadius.circular(8),
),
activeDotDecoration: DotDecoration(
width: 10,
height: 10,
color: kBackground,
borderRadius: BorderRadius.circular(10),
dotBorder: const DotBorder(
color: kPrimaryColor,
padding: 2,
width: 2,
),
),
),
onDotClicked: (index) => pageController.jumpToPage(index),
),
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
backgroundColor: kPrimaryColor,
elevation: 2,
child: IconButton(
icon: Icon(Icons.shopping_cart_outlined),
color: Colors.black,
onPressed: () {
Navigator.of(context).pushNamed(cartRoute);
context.read<TotalPrice>().update();
},
),
),
);
}
}
FoodList: //I'm positive the problems somewhere here
class FoodList extends StatelessWidget {
final int selected;
final Function callback;
final Stall stall;
const FoodList(this.selected, this.callback, this.stall);
#override
Widget build(BuildContext context) {
final category = stall.menu.keys.toList();
return Container(
height: 100,
padding: const EdgeInsets.symmetric(vertical: 30),
child: ListView.separated(
padding: const EdgeInsets.symmetric(horizontal: 25),
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) => GestureDetector(
onTap: () => callback(index),
child: Container(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: selected == index ? kPrimaryColor : Colors.white,
),
child: Text(
category[index],
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
),
),
separatorBuilder: (_, index) => const SizedBox(width: 20),
itemCount: category.length,
),
);
}
}
FoodListView:
class FoodListView extends StatelessWidget {
final int selected;
final Function callback;
final PageController pageController;
final Stall stall;
const FoodListView(
this.selected,
this.callback,
this.pageController,
this.stall,
);
#override
Widget build(BuildContext context) {
final category = stall.menu.keys.toList();
return Container(
padding: EdgeInsets.symmetric(horizontal: 25),
child: PageView(
controller: pageController,
onPageChanged: (index) => callback(index),
children: category
.map((e) => ListView.separated(
padding: EdgeInsets.zero,
itemBuilder: (context, index) => GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DetailPage(
stall.menu[category[selected]]![index],
),
),
);
},
child:
FoodItem(stall.menu[category[selected]]![index])),
separatorBuilder: (_, index) => const SizedBox(height: 15),
itemCount: stall.menu[category[selected]]!.length,
))
.toList()),
);
}
}
Stall:
class Stall {
String name;
String label;
String logoUrl;
String desc;
num score;
Map<String, List<Food>> menu;
Stall(
this.name,
this.label,
this.logoUrl,
this.desc,
this.score,
this.menu,
);
}
No need to pass selected to FoodListView and also FoodListView will be like following
class FoodListView extends StatelessWidget {
final Function callback;
final PageController pageController;
final Stall stall;
const FoodListView(
this.callback,
this.pageController,
this.stall,
);
#override
Widget build(BuildContext context) {
final menuList = stall.menu.values.toList();
return Container(
padding: EdgeInsets.symmetric(horizontal: 25),
child: PageView.builder(
controller: pageController,
onPageChanged: (index) => callback(index),
itemCount: menuList.length,
itemBuilder: (context, menuIndex) {
final menu = menuList[menuIndex];
return ListView.separated(
padding: EdgeInsets.zero,
itemBuilder: (context, index) => GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DetailPage(
menu[index],
),
),
);
},
child: FoodItem(menu[index])),
separatorBuilder: (_, index) => const SizedBox(height: 15),
itemCount: menu.length,
);
},
));
}
}
Remove selected where you call FoodListView
My code includes FutureBuilder(), which get data from Firestore, and its child widgets include GridView.builder and TextField widgets etc.
When I click on a TexField(focus), the codes in FutureBuilder are rebuild.
The following is the test code for this.
Can you tell me the cause and solution of this problem?
class TestRoom extends StatefulWidget {
TestRoom({Key? key}) : super(key: key);
#override
State<TestRoom> createState() => _TestRoomState();
}
class _TestRoomState extends State<TestRoom> {
List<RoomModel> _roomModels = [];
TextEditingController _textEditingController = TextEditingController();
bool _isTablet = false;
#override
void dispose() {
_textEditingController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
if (size.width >= 800) {
_isTablet = true;
} else {
_isTablet = false;
}
return Scaffold(
appBar: AppBar(),
body: Padding(
padding: EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"Test",
style: TextStyle(
fontSize: 35,
fontWeight: FontWeight.bold,
),
),
SizedBox(
height: 20,
),
FutureBuilder(
future: _getAllRoom(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
}
return Expanded(
child: TestList1(
isTablet: _isTablet,
roomModels: _roomModels,
isListStyle1: true,
));
},
),
],
),
),
);
}
// get user's models from firestore
Future _getAllRoom() async {
_roomModels.clear();
_roomModels.addAll(await RoomService().getAllRoomModel("userName"));
}
}
//
//
class TestList1 extends StatefulWidget {
final isTablet;
final List<RoomModel> roomModels;
final bool isListStyle1;
TestList1({
Key? key,
required this.isTablet,
required this.roomModels,
required this.isListStyle1,
}) : super(key: key);
#override
State<TestList1> createState() => _TestList1State();
}
class _TestList1State extends State<TestList1> {
TextEditingController _textEditingController = TextEditingController();
double _paddingSize = 40.0;
#override
void dispose() {
// _textEditingController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return GridView.builder(
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: widget.isTablet ? 6 : 3,
childAspectRatio: 1 / 1.5,
mainAxisSpacing: _paddingSize,
crossAxisSpacing: 10,
),
itemBuilder: (context, index) {
return _buildMyRooms(widget.roomModels[index], index);
},
itemCount: widget.roomModels.length,
);
}
Widget _buildMyRooms(RoomModel roomModel, int index) {
return Column(
children: [
InkWell(
onTap: () {},
child: Container(
width: 120,
height: 168,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: Colors.blue,
width: 2.0,
),
borderRadius: const BorderRadius.all(
Radius.circular(10),
),
),
),
),
SizedBox(
height: sm_padding,
),
PopupMenuButton<int>(
color: Colors.grey[100],
itemBuilder: (context) => _fileMenuItemLust(roomModel),
onSelected: _onSeletedFileMenu,
child: Column(
children: [
Container(
width: 130,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Flexible(
child: Text(
roomModel.roomName,
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: const TextStyle(
color: Colors.blue,
fontSize: 15,
),
),
),
const Icon(
Icons.arrow_drop_down_outlined,
color: Colors.blue,
),
],
),
),
],
),
)
],
);
}
// 파일 메뉴 아이템
List<PopupMenuEntry<int>> _fileMenuItemLust(RoomModel roomModel) {
_textEditingController.text = roomModel.roomName;
return [
// 파일명
PopupMenuItem(
enabled: false,
// TODO textfield
child: TextField(
controller: _textEditingController,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
maxLines: 1,
decoration: InputDecoration(
border: _textFieldBorder(),
enabledBorder: _textFieldBorder(),
disabledBorder: _textFieldBorder(),
focusedBorder: _textFieldBorder(),
focusColor: Colors.white60,
filled: true,
fillColor: Colors.grey.withOpacity(0.3),
isDense: true, // padding 조절을 위해 추가
contentPadding: EdgeInsets.all(sm_padding),
)),
),
const PopupMenuDivider(),
PopupMenuItem(
value: 0,
child: Row(
children: [
const Icon(
Icons.copy,
),
SizedBox(
width: sm_padding,
),
const Text(
"Menu Item1",
),
],
),
),
];
}
void _onSeletedFileMenu(value) {}
OutlineInputBorder _textFieldBorder() {
return OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(20)),
borderSide: BorderSide(
color: Colors.grey.withOpacity(0.3),
width: 1,
),
);
}
}
// ======================
I modified the code based on Yeasin Sheikh's answer.
The existing problem has been solved, but a new problem has arisen.
I'm going to update the Firestore using onSubmitted() of TextField and then update my list using stream builder and future builder.
This is a modified part of the code above to solve an existing problem
class _TestRoomState extends State<TestRoom> {
late final myFuture = _getAllRoom(); // new
FutureBuilder(
future: myFuture, //_getAllRoom(), // change
The problem of constantly rebuilding the text field according to the focus has disappeared, but there is a problem that getAllRoom() is called only at the first time and cannot be called afterwards, so the new room list cannot be updated.
Here future: _getAllRoom() calls the api on every state changes.
Create a state variable for future
late final myFuture = _getAllRoom();
#override
Widget build(BuildContext context) {
And use
FutureBuilder(
future:myFuture ,
You can check Fixing a common FutureBuilder and StreamBuilder problem
i have a simple survey page lists questions and answers, when i select a answer changes background color that answer, but here is my issue when i scroll the page and answer is out of screen its resets its state and looks not selected
this is where i fetch questions and answers then pass to card then card widget passes answers to QuestionBlock widget (second code block)
widget
Widget surveyBuilder() {
return FutureBuilder<QuerySnapshot<Map<String, dynamic>>>(
future: FirebaseFirestore.instance
.collection('surveys')
.doc(widget.docId)
.collection('sorular')
.orderBy('index', descending: false)
.get(),
builder: (context, snapshot) {
if (snapshot.hasError) {
print(snapshot.error);
return Center(
child: Text(
"Something went wrong.",
style: TextStyle(
color: ColorConstants.instance.kPrimaryColor, fontSize: 20),
textAlign: TextAlign.center,
),
);
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(
color: ColorConstants.instance.kPrimaryColor,
),
);
}
if (snapshot.data!.size > 0) {
final data = snapshot.requireData;
soruSayisi = data.size;
return ListView.builder(
itemCount: data.size,
itemBuilder: (context, index) {
return card(
question: data.docs[index]['question'],
answers: List<String>.from(data.docs[index]['answers']),
index: index);
},
);
} else {
return Center(
child: Text(
'No Survey Left',
textAlign: TextAlign.center,
style: TextStyle(
color: ColorConstants.instance.kPrimaryColor,
fontSize: 20,
),
),
);
}
},
);
}
this is my answer builder widget im passing my answer list to this page
class QuestionBlock extends StatefulWidget {
QuestionBlock({Key? key, required this.cevaplar, required this.soru})
: super(key: key);
final List<String> answers;
final String soru;
#override
State<QuestionBlock> createState() => QuestionBlockState();
}
class QuestionBlockState extends State<QuestionBlock> {
int? selectedIndex;
#override
Widget build(BuildContext context) {
return ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: widget.cevaplar.length,
itemBuilder: ((context, index) {
return answerCard(widget.answers[index], index);
}),
);
}
Widget answerCard(String answer, int index) {
return GestureDetector(
onTap: () {
setState(() {
selectedIndex = index;
cevaplarMap[widget.soru] = answer;
});
},
child: Container(
width: MediaQuery.of(context).size.width,
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
decoration: BoxDecoration(
color: selectedIndex == index
? ColorConstants.instance.kPrimaryColor
: Colors.white,
borderRadius: BorderRadius.circular(5),
border: Border.all(color: Colors.grey.withOpacity(.3)),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.3),
spreadRadius: 1,
blurRadius: 5,
offset: Offset(0, 3), // changes position of shadow
),
]),
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: Text(
cevap,
style: TextStyle(
color: selectedIndex == index ? Colors.white : Colors.black,
fontFamily: 'Roboto',
fontSize: 16),
),
),
);
}
}
I'm new to flutter, may I know how to get different outputs when I click on each item? I have total of 3 lists, for each item, I want to get their respective output and now I only can get the same outputs for each item. How to get different outputs when I click on it? Thanks all.
this is my ListView coding :
class _CatState extends State<Cat> {
List<String> categories = ["Furniture", "Lighting", "Decoration"];
int selectedIndex = 0;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 5.0),
child: SizedBox(
height: 25,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: categories.length,
itemBuilder: (context, index) => buildCategory(index),
),
));
}
Widget buildCategory(int index) {
return GestureDetector(
onTap: () {
setState(() {
selectedIndex = index;
});
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 40.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
categories[index],
style: TextStyle(
fontSize: 15,
color: selectedIndex == index ? Colors.black : Colors.black45,
),
),
Container(
margin: EdgeInsets.only(top: DefaultPadding / 4), //top padding
height: 2,
width: 50,
color: selectedIndex == index
? Colors.blueAccent[200]
: Colors.transparent,
)
],
When onTap the item:
class ItemCard extends StatelessWidget {
final Product product;
final Decor decoration;
final Light light;
final Function press;
const ItemCard({
Key key,
this.press,
this.product,
this.decoration,
this.light,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: press,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
child: Container(
padding: EdgeInsets.all(2.0),
// height: 180,
// width: 160,
child: ClipRRect(
borderRadius: BorderRadius.circular(25.0),
child: Image.asset(
product.img, // products image
)),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: DefaultPadding / 4),
child: Text(
product.name, // products name
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
),
Text(
product.price,
textAlign: TextAlign.center,
style: TextStyle(fontStyle: FontStyle.italic),
)
],
),
Use switch case if it is static. For example on itemBuilder in Gridview:
ItemCard(
product:furniture[index],
press: _onPressed(index),
)
and in onPressed method, do whatever you want:
_onPressed(int index){
switch(index):
case 0:
your code:
break;
case 1:
//code
}
so by this you can make different onTap function
Above one is requirement. Actually requirement is that first widget (Vertical List header with below list view should take full height) means if list view has 18 items. It should show 18 items. Then below that it should show horizontal scroll.
I tried in my way but due to column list view taking same height as other element due to which its not showing all item all the way. It takes half of height of screen and user need to scroll in that height itself.
Need your help to sort out it. As first listview should take full height and second widget should come below that.
Please see below code.
import 'dart:math';
import 'package:flutter/material.dart';
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Flutter test",
style: TextStyle(color: Colors.black),
),
elevation: 5,
backgroundColor: Colors.white,
),
body: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
children: [
ListHeader("Vertical List Header"),
VerticalList(),
ListHeader("Horizontal List Header"),
HorizontalList(),
ListHeader("Vertical List Header"),
VerticalList(),
ScrollUp()
],
),
);
}
}
class ScrollUp extends StatelessWidget {
const ScrollUp({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return InkWell(
child: Container(
alignment: Alignment.bottomCenter,
width: double.infinity,
height: 50,
child: Center(
child: Text(
"Click to scroll up",
style: TextStyle(
fontSize: 18,
),
),
),
),
);
}
}
class ListHeader extends StatelessWidget {
final String title;
const ListHeader(String title) : title = title;
#override
Widget build(BuildContext context) {
return Text(
title,
style: TextStyle(fontSize: 18),
);
}
}
class HorizontalList extends StatelessWidget {
const HorizontalList({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Expanded(
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: 30,
itemBuilder: (BuildContext context, int index) => Container(
margin:
const EdgeInsets.symmetric(vertical: 20, horizontal: 10),
width: 30,
height: 20,
color: Colors.grey,
)),
);
}
}
class VerticalList extends StatelessWidget {
const VerticalList({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Expanded(
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (ctx, int) {
return Container(
margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
width: double.infinity,
height: 50,
color: Colors.primaries[Random().nextInt(Colors.primaries.length)],
);
},
itemCount: 8,
),
);
}
}
Change the Column widget with a ListView widget.
And add shrinkWrap: true to its child ListView's'.
Remove the Expanded widget on both ListView.Builder
The horizontal ListView.Builder must have a Fixed height ( Link )
Add physics: NeverScrollableScrollPhysics() to the vertical ListView.Builder
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Flutter test",
style: TextStyle(color: Colors.black),
),
elevation: 5,
backgroundColor: Colors.white,
),
body: ListView(
children: [
ListHeader("Vertical List Header"),
VerticalList(),
ListHeader("Horizontal List Header"),
HorizontalList(),
ListHeader("Vertical List Header"),
VerticalList(),
ScrollUp()
],
),
);
}
}
class ScrollUp extends StatelessWidget {
const ScrollUp({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return InkWell(
child: Container(
alignment: Alignment.bottomCenter,
width: double.infinity,
height: 50,
child: Center(
child: Text(
"Click to scroll up",
style: TextStyle(
fontSize: 18,
),
),
),
),
);
}
}
class ListHeader extends StatelessWidget {
final String title;
const ListHeader(String title) : title = title;
#override
Widget build(BuildContext context) {
return Text(
title,
style: TextStyle(fontSize: 18),
);
}
}
class HorizontalList extends StatelessWidget {
const HorizontalList({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: 400,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: 30,
itemBuilder: (BuildContext context, int index) => Container(
margin:
const EdgeInsets.symmetric(vertical: 20, horizontal: 10),
width: 30,
height: 20,
color: Colors.grey,
)),
);
}
}
class VerticalList extends StatelessWidget {
const VerticalList({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (ctx, int) {
return Container(
margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
width: double.infinity,
height: 50,
color: Colors.primaries[Random().nextInt(Colors.primaries.length)],
);
},
itemCount: 8,
);
}
}
This is my solution for same kind of problem.
import 'package:flutter/material.dart';
class MealDetailsScreen extends StatelessWidget {
Widget buildSectionTitle(BuildContext context, String title) {
return Container(
margin: EdgeInsets.symmetric(vertical: 10),
child: Text(
title,
style: Theme.of(context).textTheme.bodyText1,
),
);
}
Widget buildContainer({Widget child}) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(10)),
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(10),
height: 300,
width: 300,
child: child,
);
}
#override
Widget build(BuildContext context) {
final mealId = ModalRoute.of(context).settings.arguments;
final selectedMeal =
DUMMY_MEALS.firstWhere((element) => element.id == mealId);
return Scaffold(
appBar: AppBar(
title: Text('${selectedMeal.title}'),
),
body: SingleChildScrollView(
child: Column(
children: [
Container(
height: 300,
width: double.infinity,
child: Image.network(
selectedMeal.imageUrl,
fit: BoxFit.cover,
),
),
buildSectionTitle(context, 'Ingredients'),
buildContainer(
child: ListView.builder(
itemBuilder: (ctx, index) => Card(
color: Theme.of(context).accentColor,
child: Padding(
padding:
const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
child: Text(selectedMeal.ingredients[index]),
),
),
itemCount: selectedMeal.ingredients.length,
),
),
buildSectionTitle(context, 'Steps'),
buildContainer(
child: ListView.builder(
itemBuilder: (ctx, index) => Column(
children: [
ListTile(
leading: CircleAvatar(
child: Text('# ${(index + 1)}'),
),
title: Text(selectedMeal.steps[index]),
),
Divider(),
],
),
itemCount: selectedMeal.steps.length,
),
),
],
),
),
);
}
}