Related
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.
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
I need to display categories in a scroll with 3X3 in grid view and it was working fine and slide also working fine but i cant able to achieve the dots for the scrolling .. I need like carousal . Is it possible to add dots with list view
SingleChildScrollView(
child: GridView.count(
physics: ScrollPhysics(),
padding: EdgeInsets.fromLTRB(16, 16, 16, 0),
primary: false,
childAspectRatio: 1.1,
shrinkWrap: true,
crossAxisSpacing: 0,
mainAxisSpacing: 0,
crossAxisCount: 4,
// mainAxisCount:2,
//scrollDirection: Axis.horizontal,
children: List.generate(categoryData.length, (index) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductCategoryPage(
categoryId: categoryData[index].id,
categoryName:
categoryData[index].name)));
},
child: Column(children: [
buildCacheNetworkImage(
width: 40,
height: 40,
url: categoryData[index].image,
plColor: Colors.transparent),
Flexible(
child: Container(
margin: EdgeInsets.fromLTRB(0, 10, 0, 0),
child: Text(
categoryData[index].name,
style: TextStyle(
color: CHARCOAL,
fontWeight: FontWeight.normal,
fontSize: 12,
),
textAlign: TextAlign.center,
),
),
)
]));
}),
),
)
I need to get the scrolling dots in the list view so how to achieve that
You should implement below way
Code :
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<String> list = [];
int perPageItem = 16;
int pageCount;
int selectedIndex = 0;
int lastPageItemLength;
PageController pageController;
#override
void initState() {
pageController = PageController(initialPage: 0);
for (int i = 1; i <= 45; i++) {
list.add('$i');
}
var num = (list.length / perPageItem);
pageCount = num.isInt ? num.toInt() : num.toInt() + 1;
var reminder = list.length.remainder(perPageItem);
lastPageItemLength = reminder == 0 ? perPageItem : reminder;
super.initState();
}
#override
void dispose() {
pageController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
children: [
SizedBox(
height: 390,
child: PageView.builder(
controller: pageController,
itemCount: pageCount,
onPageChanged: (index) {
setState(() {
selectedIndex = index;
});
},
itemBuilder: (_, pageIndex) {
return GridView.count(
physics: NeverScrollableScrollPhysics(),
padding: const EdgeInsets.fromLTRB(16, 16, 16, 0),
primary: false,
childAspectRatio: 1.1,
shrinkWrap: true,
crossAxisSpacing: 0,
mainAxisSpacing: 0,
crossAxisCount: 4,
children: List.generate(
(pageCount - 1) != pageIndex
? perPageItem
: lastPageItemLength, (index) {
return GestureDetector(
onTap: () {},
child: Container(
width: 50,
height: 50,
margin: const EdgeInsets.all(5),
color: Colors.amber,
alignment: Alignment.center,
child: Text(
list[index + (pageIndex * perPageItem)],
style: TextStyle(color: Colors.black, fontSize: 20),
),
),
);
}),
);
}),
),
SizedBox(
height: 15,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: pageCount,
itemBuilder: (_, index) {
return GestureDetector(
onTap: () {
pageController.animateToPage(index, duration: Duration(milliseconds: 500), curve: Curves.easeInOut);
},
child: AnimatedContainer(
duration: Duration(milliseconds: 100),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10)),
color: Colors.red
.withOpacity(selectedIndex == index ? 1 : 0.5)),
margin: EdgeInsets.all(5),
width: 10,
height: 10,
),
);
},
),
),
],
),
);
}
}
extension NumExtensions on num {
bool get isInt => (this % 1) == 0;
}
Output :
I am trying to build a GridView list. This all works when I create a simple list of 'players', but now I am trying to persist data using sqflite and I am getting an error:
Error: The argument type 'Future' can't be assigned to the parameter type 'int'
This is my list builder widget:
class PlayerList extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Consumer<PlayerData>(
builder: (context, playerData, child) {
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 20,
crossAxisSpacing: 20,
),
itemCount: playerData.playerCount,
itemBuilder: (BuildContext context, int index) {
final player = playerData.players[index];
return RawMaterialButton(
fillColor: Color(0x991c5597),
elevation: 20,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
CircleAvatar(
backgroundColor: Colors.tealAccent,
radius: 30,
child: Icon(
Icons.star,
color: Color(0xFF16377a),
size: 30,
),
),
Text(player.name, style: smallTitleText),
],
),
),
onPressed: () {
playerData.makeActive(player.name);
playerData.printList();
Navigator.pushNamed(context, PlayScreen.id);
});
});
},
);
}
}
This is how I get the list count:
Future<int> get playerCount async {
final Database db = await getDBConnector();
final List<Map<String, dynamic>> maps = await db.query('players');
if (maps.length != null) {
return maps.length;
} else { return 0;}
}
Wrap your GridView with FutureBuilder
Something like this
return FutureBuilder(
future: playerData.playerCount,
builder : (context,snapshot){
if(!(snapshot.hasData)){
return Container();
}
else{
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 20,
crossAxisSpacing: 20,
),
itemCount: snapshot.data,
itemBuilder: (BuildContext context, int index) {
final player = playerData.players[index];
return RawMaterialButton(
fillColor: Color(0x991c5597),
elevation: 20,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
CircleAvatar(
backgroundColor: Colors.tealAccent,
radius: 30,
child: Icon(
Icons.star,
color: Color(0xFF16377a),
size: 30,
),
),
Text(player.name, style: smallTitleText),
],
),
),
onPressed: () {
playerData.makeActive(player.name);
playerData.printList();
Navigator.pushNamed(context, PlayScreen.id);
});
});
},
);
}
}
);
The error is appearing because playerCount isn't returning int its returning a Future. First, you have to change your class to a stateful widget and load your data as shown below
class PlayerList extends StatefulWidget {
#override
_PlayerListState createState() => _PlayerListState();
}
class _PlayerListState extends State<PlayerList> {
int count;
#override
void initState() {
super.initState();
loadPlayerCount();
}
#override
Widget build(BuildContext context) {
return Consumer<PlayerData>(
builder: (context, playerData, child) {
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 20,
crossAxisSpacing: 20,
),
itemCount: count??0,
itemBuilder: (BuildContext context, int index) {
final player = playerData.players[index];
return RawMaterialButton(
fillColor: Color(0x991c5597),
elevation: 20,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
CircleAvatar(
backgroundColor: Colors.tealAccent,
radius: 30,
child: Icon(
Icons.star,
color: Color(0xFF16377a),
size: 30,
),
),
Text(player.name, style: smallTitleText),
],
),
),
onPressed: () {
playerData.makeActive(player.name);
playerData.printList();
Navigator.pushNamed(context, PlayScreen.id);
});
});
},
);
}
void loadPlayerCount() async{
final Database db = await getDBConnector();
final List<Map<String, dynamic>> maps = await db.query('players');
if (maps.length != null) {
setState(() {
this.count = maps.length;
});
} else {
setState(() {
this.count = 0;
});
}
}
}
import 'package:flutter_event_app/constant/color.dart';
import 'package:flutter_event_app/network/models/categories.dart';
import 'package:flutter_event_app/network/models/event_model.dart';
import 'package:flutter_event_app/network/models/time.dart';
import 'package:flutter_event_app/network/services/event_api.dart';
import 'package:flutter_event_app/pages/event_detail_page.dart';
import 'package:flutter_event_app/pages/search/home_search.dart';
import 'package:flutter_event_app/widgets/event_card.dart';
import 'package:flutter_event_app/widgets/no_events.dart';
import 'package:flutter_event_app/widgets/onload.dart';
class SelectedCategory extends StatefulWidget {
// SelectedCategory(Categories categories);
final Categories categories;
final Time time;
SelectedCategory(this.categories, [this.time]);
#override
_SelectedCategoryState createState() => _SelectedCategoryState();
}
class _SelectedCategoryState extends State<SelectedCategory> {
Categories categories;
Time timing;
String timeselect;
// Event event;
void viewEventDetail(Events event) {
Navigator.of(context).push(
PageRouteBuilder(
opaque: false,
barrierDismissible: true,
transitionDuration: Duration(milliseconds: 300),
pageBuilder: (BuildContext context, animation, __) {
return FadeTransition(
opacity: animation,
child: EventDetailPage(event),
);
},
),
);
}
bool isLoading = false;
List<Events> upcomingEvents;
List categorizedupcomingEvents = [];
List categorizedPaidupcomingEvents = [];
List categorizedFreeupcomingEvents = [];
#override
void initState() {
_fetchData();
categories = widget.categories;
timing = widget.time;
// print(timing.id);
super.initState();
}
Future _fetchData() async {
setState(() => isLoading = true);
upcomingEvents = await getEventss();
categorizedupcomingEvents = upcomingEvents
.where((category) => category.category == categories.id)
.toList();
categorizedPaidupcomingEvents = categorizedupcomingEvents
.where((paid) => paid.is_paid == true)
.toList();
categorizedFreeupcomingEvents = categorizedupcomingEvents
.where((free) => free.is_paid == false)
.toList();
setState(() => isLoading = false);
}
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(
MediaQuery.of(context).size.height / 9.5,
),
child: AppBar(
title: Text(categories.categoryName),
centerTitle: true,
actions: <Widget>[
IconButton(
icon: Icon(
Icons.sort,
),
onPressed: () {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) =>
showFilterByTimeDialog(context);
// )
// );
}),
IconButton(
icon: Icon(
Icons.more_vert,
),
onPressed: () {})
],
bottom: TabBar(
tabs: [
Text('All'),
Text('Paid'),
Text('Free'),
],
),
),
),
body: TabBarView(
children: <Widget>[
// All
isLoading
? OnloadingCards()
: Column(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: categorizedupcomingEvents.isEmpty
? NoItems()
: ListView.builder(
itemCount: categorizedupcomingEvents.length,
shrinkWrap: true,
primary: false,
physics: BouncingScrollPhysics(),
// scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
final event =
categorizedupcomingEvents[index];
return EventCard(event,
onTap: () => viewEventDetail(event));
},
),
),
),
],
),
// Paid
isLoading
? OnloadingCards()
: Column(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: categorizedPaidupcomingEvents.isEmpty
? NoItems()
: ListView.builder(
itemCount:
categorizedPaidupcomingEvents.length,
shrinkWrap: true,
primary: false,
physics: BouncingScrollPhysics(),
// scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
final event =
categorizedPaidupcomingEvents[index];
return EventCard(event,
onTap: () => viewEventDetail(event));
},
),
),
),
],
),
// Free
isLoading
? OnloadingCards()
: Column(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: categorizedFreeupcomingEvents.isEmpty
? NoItems()
: ListView.builder(
itemCount:
categorizedFreeupcomingEvents.length,
shrinkWrap: true,
primary: false,
physics: BouncingScrollPhysics(),
// scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
final event =
categorizedFreeupcomingEvents[index];
return EventCard(event,
onTap: () => viewEventDetail(event));
},
),
),
),
],
),
],
),
));
}
void showFilterByTimeDialog(BuildContext context) {
Dialog fancyDialog = Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
child: SingleChildScrollView(
child: Container(
width: double.infinity,
height: MediaQuery.of(context).size.height * 0.5,
// alignment: Alignment.bottomCenter,
decoration: BoxDecoration(
// color: Colors.greenAccent,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12),
bottomLeft: Radius.circular(12),
bottomRight: Radius.circular(12),
),
),
child: Column(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height * 0.05,
child: Text(
"Time",
style: TextStyle(
color: Colors.deepPurple,
fontSize: 20,
fontWeight: FontWeight.w600),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
// color: Colors.red,
width: double.infinity,
child: ListView.builder(
shrinkWrap: true,
primary: false,
physics: BouncingScrollPhysics(),
itemCount: times.length,
itemBuilder: (context, int index) {
Time time = times[index];
return RaisedButton(
onPressed: () {
debugPrint('I am Awesome');
},
textColor: Colors.red,
// color: Colors.blueAccent,
disabledColor: Colors.grey,
disabledTextColor: Colors.white,
highlightColor: Colors.orangeAccent,
child: Text(time.name),
);
}),
),
),
),
],
),
),
),
);
showDialog(
context: context, builder: (BuildContext context) => fancyDialog);
}
}
Within the same page I have a dialog box as shown below
On the method showFilterByTimeDialog where I select an item and have to go back to the same page below the dialogue .Am still learning flutter and my issue is I need help when I select an item from the dialogue box,i refresh the same page and display a new filtered lst from the current list displayed on that page with a condition of the item selected from the dialogue box.