How to pass listview data while using bottom navigation bar in flutter? - flutter

I want to pass data onclick of the listview items from one screen to another. All screen has bottom navigation bar with end drawer. Tried to pass data from second screen to details screen but was unsuccessful as there is no Navigator used. Anyone can help me with this? Following is the implemented code
bottom_nav_bar.dart
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'Utility.dart';
import 'main.dart';
class CustomAnimatedBottomBar extends StatelessWidget {
CustomAnimatedBottomBar({
Key? key,
this.selectedIndex = ScreenType.home,
this.showElevation = true,
this.iconSize = 24,
this.backgroundColor,
this.itemCornerRadius = 40,
this.animationDuration = const Duration(milliseconds: 270),
this.mainAxisAlignment = MainAxisAlignment.spaceBetween,
required this.items,
required this.onItemSelected,
this.curve = Curves.linear,
}) : assert(items.length >= 2 && items.length <= 5),
super(key: key);
final ScreenType selectedIndex;
final double iconSize;
final Color? backgroundColor;
final bool showElevation;
final Duration animationDuration;
final List<BottomNavyBarItem> items;
final ValueChanged<ScreenType> onItemSelected;
final MainAxisAlignment mainAxisAlignment;
final double itemCornerRadius;
final Curve curve;
#override
Widget build(BuildContext context) {
final bgColor = backgroundColor ?? Theme.of(context).bottomAppBarColor;
return Container(
decoration: BoxDecoration(
color: bgColor,
boxShadow: [
if (showElevation)
const BoxShadow(
color: Colors.black12,
blurRadius: 2,
),
],
),
child: SafeArea(
child: Container(
width: double.infinity,
height: kToolbarHeight,
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 8),
child: Row(
mainAxisAlignment: mainAxisAlignment,
children: items.map((item) {
var index = item;
return GestureDetector(
onTap: () => onItemSelected(index.screenType),
child: _ItemWidget(
item: item,
iconSize: iconSize,
isSelected: index.screenType == selectedIndex,
backgroundColor: bgColor,
itemCornerRadius: itemCornerRadius,
animationDuration: animationDuration,
curve: curve,
),
);
}).toList(),
),
),
),
);
}
}
class _ItemWidget extends StatelessWidget {
final double iconSize;
final bool isSelected;
final BottomNavyBarItem item;
final Color backgroundColor;
final double itemCornerRadius;
final Duration animationDuration;
final Curve curve;
const _ItemWidget({
Key? key,
required this.item,
required this.isSelected,
required this.backgroundColor,
required this.animationDuration,
required this.itemCornerRadius,
required this.iconSize,
this.curve = Curves.linear,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Semantics(
container: true,
selected: isSelected,
child: AnimatedContainer(
width: isSelected ? 130 : 50,
height: double.maxFinite,
duration: animationDuration,
curve: curve,
decoration: BoxDecoration(
color:
isSelected ? item.activeColor.withOpacity(0.2) : backgroundColor,
borderRadius: BorderRadius.circular(itemCornerRadius),
),
child: Container(
width: isSelected ? 130 : 50,
padding: EdgeInsets.symmetric(horizontal: 10),
child: Row(
// mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
IconTheme(
data: IconThemeData(
size: iconSize,
color: isSelected
? item.activeColor.withOpacity(1)
: item.inactiveColor == null
? item.activeColor
: item.inactiveColor,
),
child: item.icon,
),
if (isSelected)
Expanded(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 4),
child: DefaultTextStyle.merge(
style: TextStyle(
color: item.activeColor,
fontWeight: FontWeight.bold,
),
maxLines: 1,
textAlign: item.textAlign,
child: item.title,
),
),
),
],
),
),
),
);
}
}
class BottomNavyBarItem {
BottomNavyBarItem({
required this.screenType,
required this.icon,
required this.title,
this.activeColor = Colors.blue,
this.textAlign,
this.inactiveColor,
});
final ScreenType screenType;
final Widget icon;
final Widget title;
final Color activeColor;
final Color? inactiveColor;
final TextAlign? textAlign;
}
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_app/FifthScreen.dart';
import 'package:flutter_app/details_screen.dart';
import 'package:flutter_app/profile_screen.dart';
import 'package:flutter_app/secondPage.dart';
import 'ThirdPage.dart';
import 'Utility.dart';
import 'bottom_nav_bar.dart';
import 'firstpage.dart';
import 'fourthPage.dart';
import 'home_screen.dart';
import 'message_screen.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
enum ScreenType {
firstScreen,
secondScreen,
thirdScreen,
forthScreen,
fifthScreen,
detailsScreen,
home,
messages,
profile
}
class _MyHomePageState extends State<MyHomePage> {
ScreenType _screenType = ScreenType.home;
final _inactiveColor = Colors.grey;
GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: getTitle(_screenType),
),
endDrawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('Drawer Header'),
decoration: BoxDecoration(
color: Colors.blue,
),
),
ListTile(
title: Text('First Screen'),
onTap: (){onTabTapped(ScreenType.firstScreen);
Navigator.of(context).pop();
},
),
ListTile(
title: Text('Second Screen'),
onTap:(){onTabTapped(ScreenType.secondScreen);
Navigator.of(context).pop();
},
),
ListTile(
title: Text('Third Screen'),
onTap: (){onTabTapped(ScreenType.thirdScreen);
Navigator.of(context).pop();
},
),
],
),
),
body: _body(_screenType),
bottomNavigationBar: _buildBottomBar(),
);
}
Widget _body(ScreenType screenType) {
switch (screenType) {
case ScreenType.firstScreen:
return FirstScreen(
navigateScreen: (screenType) => onTabTapped(screenType),
);
case ScreenType.secondScreen:
return SecondScreen(
onClickList: (model){
setState(() {
_screenType = ScreenType.detailsScreen;
});
},
);
case ScreenType.thirdScreen:
return const ThirdScreen();
case ScreenType.forthScreen:
return const ForthScreen();
case ScreenType.home:
return const HomeScreen();
case ScreenType.messages:
return const MessagesScreen();
case ScreenType.profile:
return const ProfileScreen();
case ScreenType.fifthScreen:
return const FifthScreen();
case ScreenType.detailsScreen:
return DetailsScreen();
}
}
Widget _buildBottomBar() {
return CustomAnimatedBottomBar(
backgroundColor: Colors.black,
selectedIndex: _screenType,
showElevation: true,
itemCornerRadius: 24,
curve: Curves.easeIn,
onItemSelected: onTabTapped,
items: <BottomNavyBarItem>[
BottomNavyBarItem(
screenType: ScreenType.home,
icon: Icon(Icons.apps),
title: Text('Home'),
activeColor: Colors.green,
inactiveColor: _inactiveColor,
textAlign: TextAlign.center,
),
BottomNavyBarItem(
screenType: ScreenType.messages,
icon: Icon(Icons.message),
title: Text('Messages'),
activeColor: Colors.purpleAccent,
inactiveColor: _inactiveColor,
textAlign: TextAlign.center,
),
BottomNavyBarItem(
screenType: ScreenType.profile,
icon: Icon(Icons.account_circle_rounded),
title: Text('Profile'),
activeColor: Colors.pink,
inactiveColor: _inactiveColor,
textAlign: TextAlign.center,
),
],
);
}
void onTabTapped(ScreenType screenType) {
if ((_scaffoldKey.currentState ?? ScaffoldState()).isEndDrawerOpen) {
(_scaffoldKey.currentState ?? ScaffoldState()).openEndDrawer();
}
setState(() {
_screenType = screenType;
});
}
Widget getTitle(ScreenType screenType) {
switch (screenType) {
case ScreenType.firstScreen:
return Text("First Screen");
case ScreenType.secondScreen:
return Text("Second Screen");
case ScreenType.thirdScreen:
return Text("Third Screen");
case ScreenType.forthScreen:
return Row(
children: [
IconButton(onPressed: (){
onTabTapped(ScreenType.firstScreen);
}, icon: Icon(Icons.arrow_back_ios)),
Text("Fourth Screen"),
],
);
case ScreenType.detailsScreen:
return Text("Details Screen");
case ScreenType.home:
return Text("Home");
case ScreenType.messages:
return Text("Message");
case ScreenType.profile:
return Text("Profile");
case ScreenType.fifthScreen:
// TODO: Handle this case.
return Text("Fifth Sceen");
break;
}
}
}
second_page.dart
import 'package:flutter/material.dart';
typedef OnClickList(Model);
class SecondScreen extends StatefulWidget {
// final VoidCallback voidCallback;
final OnClickList onClickList;
const SecondScreen({Key? key, required this.onClickList}) : super(key: key);
#override
_SecondScreenState createState() => _SecondScreenState();
}
class _SecondScreenState extends State<SecondScreen> {
#override
Widget build(BuildContext context) {
List<Model> items = [
Model(text: "Text 1 to next screen"),
Model(text: "Text 2 to next screen"),
Model(text: "Text 3 to next screen"),
];
return Container(
child: Center(
child: Column(
children: [
Text("Second Screen"),
ListView.builder(
itemCount: items.length,
shrinkWrap: true,scrollDirection: Axis.vertical,
itemBuilder: (context, index){
Model model = items[index];
return GestureDetector(
onTap: (){
widget.onClickList(model.text);
},
child: Card(
child: Text("${items[index].text}"),
),
);
})
],
),
),
);
}
}
class Model{
String text;
Model({required this.text});
}
details_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_app/secondPage.dart';
class DetailsScreen extends StatefulWidget {
final Model? model;
const DetailsScreen({Key? key, this.model}):super(key:key);
#override
_DetailsScreenState createState() => _DetailsScreenState();
}
class _DetailsScreenState extends State<DetailsScreen> {
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text(widget.model!.text.toString()),
),
);
}
}
first_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_app/main.dart';
typedef NavigateScreen(ScreenType);
class FirstScreen extends StatefulWidget {
const FirstScreen({
Key? key,
required this.navigateScreen,
}) : super(key: key);
final NavigateScreen navigateScreen;
#override
_FirstScreenState createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen> {
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Flex(
direction: Axis.vertical,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("First Screen"),
ElevatedButton(
onPressed: () => widget.navigateScreen(ScreenType.forthScreen),
child: Text("Go To Forth Screen"),
),
ElevatedButton(
onPressed: () => widget.navigateScreen(ScreenType.fifthScreen),
child: Text("Go To Fifth Screen"),
),
],
),
),
);
}
}

To pass data from second screen to details screen:
Add a variable in homepage state which can take content clicked from second screen.
class _MyHomePageState extends State<MyHomePage> {
ScreenType _screenType = ScreenType.home;
final _inactiveColor = Colors.grey;
Model? fromSecond;
…….
}
Change onClickList implementation and switch case.
Widget _body(ScreenType screenType) {
switch (screenType) {
case ScreenType.firstScreen:
return FirstScreen(
navigateScreen: (screenType) => onTabTapped(screenType),
);
case ScreenType.secondScreen:
return SecondScreen(
onClickList: (model) {
fromSecond = model;
setState(() {
_screenType = ScreenType.detailsScreen;
});
},
);
……..
…….
case ScreenType.detailsScreen:
{
if(fromSecond!=null) {
return DetailsScreen(model: fromSecond);
} else {
return DetailsScreen();
}
}
………..
……….
}
On SecondScreen make gesture detector return model to onClickList callback.
…………
…………
return GestureDetector(
onTap: (){
widget.onClickList(model);
},
child: Card(
child: Text("${items[index].text}"),
),
);
…….
…….

Related

All checkboxes in Flutter checkbox Listtile are checked at the same time

I created a checkbox Listtile, where I can click on an Info button to receive further info if neccessary. Therefore I created a main Widget which contains the Listtile widget. When the Info button gets clicked, the detail page opens and reads the specific details from the model class.Up to that point everything works fine.
My leading is a checkbox. If it gets clicked not just one checkbox gets checked, but all of them. how can I write my code, that they arent checked all at the same time automatically?
thank you very much for your help
Kind regards
Here is my code:
//This is my model
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
class Info {
String title;
String description;
//String image;
Info(
{required this.title,
required this.description,
// #required this.image
});
}
List<Info> ModelList = [
Info(
title: 'title1',
description: 'description1'
),
Info(
title: 'title2',
description: 'description2'
),
];
//This is the widget
class MainWidget extends StatefulWidget {
const MainWidget({Key? key}) : super(key: key);
#override
State<MainWidget> createState() => _MainWidgetState();
}
class _MainWidgetState extends State<MainWidget> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder
(itemCount: ModelList.length,
itemBuilder: (context,index)
{Info cardname = ModelList[index];
return Card(
child: CheckboxListTile(
tileColor: const Color(0xFF5D6D7E),
shape: RoundedRectangleBorder(
side: const BorderSide (color:Colors.white,width: 2),
borderRadius: BorderRadius.circular(10),
),
contentPadding: const EdgeInsets.symmetric(vertical: 10.0),
value: timeDilation !=1.0,
onChanged: (bool? value) {
setState (() {
timeDilation = value! ? 5.0 : 1.0;
});
},
title: Text(
cardname.title,
style: const TextStyle(
fontSize: 25.0,
fontWeight: FontWeight.w600,
color: Colors.white),
),
//an welcher Stelle die Checkbox ist (links oder rechts)
controlAffinity:
ListTileControlAffinity.leading,
secondary: IconButton(icon: const Icon(Icons.info_outlined,size: 40,color: Colors.orange,), onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context)=> DetailScreen(cardname)
));
},),
)
);
}
,),
)
;
}
}
//Detail screen
//Detail Screen;
class DetailScreen extends StatelessWidget {
final Info cardname ;
const DetailScreen (this.cardname, {super.key});
//const DetailScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: customAppBar
((cardname.title),),
body: Padding(
padding: const EdgeInsets.all(8.0) ,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Image.network(
// cardname.imageUrl,
//height: 500,
//),
//
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
cardname.description,
textAlign: TextAlign.justify,
style: const TextStyle(fontSize: 22.0),
),
),
],
),
),
) ,
);
}
}
I tried to put the Item builder in an extra widget and return it into the main widget as shown below, but this didn`t work as well
class SubWidget extends StatefulWidget {
const SubWidget({Key? key}) : super(key: key);
#override
State<SubWidget> createState() => _SubWidgetState();
}
class _SubWidgetState extends State<SubWidget> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder
(itemCount: ModelList.length,
itemBuilder: (context,index)
{Info cardname = ModelList[index];
return MainWidget()
Add variable is isSelected bool for Info class
And after onChanged change value: isSelected = !isSelected
Try this:
class Info {
String title;
String description;
bool isSelected;
//String image;
Info({
required this.title,
required this.description,
required this.isSelected,
// #required this.image
});
}
List<Info> ModelList = [
Info(title: 'title1', description: 'description1', isSelected: false),
Info(title: 'title2', description: 'description2', isSelected: false),
];
//This is the widget
class MainWidget extends StatefulWidget {
const MainWidget({Key? key}) : super(key: key);
#override
State<MainWidget> createState() => _MainWidgetState();
}
class _MainWidgetState extends State<MainWidget> {
double timeDilation = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: ModelList.length,
itemBuilder: (context, index) {
Info cardname = ModelList[index];
return Card(
child: CheckboxListTile(
tileColor: const Color(0xFF5D6D7E),
shape: RoundedRectangleBorder(
side: const BorderSide(color: Colors.white, width: 2),
borderRadius: BorderRadius.circular(10),
),
contentPadding: const EdgeInsets.symmetric(vertical: 10.0),
value: cardname.isSelected,
onChanged: (bool? value) {
setState(() {
cardname.isSelected = !cardname.isSelected;
});
},
title: Text(
cardname.title,
style: const TextStyle(
fontSize: 25.0,
fontWeight: FontWeight.w600,
color: Colors.white),
),
//an welcher Stelle die Checkbox ist (links oder rechts)
controlAffinity: ListTileControlAffinity.leading,
secondary: IconButton(
icon: const Icon(
Icons.info_outlined,
size: 40,
color: Colors.orange,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailScreen(cardname),
),
);
},
),
),
);
},
),
);
}
}

Flutter: How to use a button that has the same effect as clicking on a BottomNavigationBar?

I have a Dart file named page0.dart and this only includes a BottomNavigationBar.
BottomNavigationBar has 2 items in it which redirects me to dashboard.dart and target.dart, the navigation via the BottomNavigationBar works as expected.
Now the problem: I need a button on dashboard.dart that should redirect me to target.dart, but keep the ButtomNavigationBar visible.
I am redirecting with Navigator.push, but that opens target.dart directly and skips page0.dart I think.
Screenshots are below. Please watch them for better understanding my problem.
Here are the code samples:
page0.dart:
import 'package:flutter/material.dart';
import 'package:navbartest/dashboard.dart';
import 'package:navbartest/target.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key, required String title}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return const Scaffold(
bottomNavigationBar: BottomNavBar(),
);
}
}
class BottomNavBar extends StatefulWidget {
const BottomNavBar({super.key});
#override
State<BottomNavBar> createState() => _BottomNavBarState();
}
class _BottomNavBarState extends State<BottomNavBar> {
int _pageIndex = 0;
final List<Widget> _tabList = const [
Dashboard(),
Target(),
];
Widget? onItemTap(int index) {
setState(() {
_pageIndex = index;
});
return null;
}
#override
Widget build(BuildContext context) {
return Stack(
children: [
_tabList.elementAt(_pageIndex),
Padding(
padding: EdgeInsets.only(right: 35, bottom: 25, left: 35),
child: Align(
alignment: const Alignment(0.0, 1.0),
child: ClipRRect(
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
child: BottomNavigationBar(
backgroundColor: const Color(0xff565656),
type: BottomNavigationBarType.fixed,
showSelectedLabels: false,
showUnselectedLabels: false,
unselectedItemColor: Colors.white,
selectedItemColor: Colors.white,
onTap: onItemTap,
items: [
BottomNavigationBarItem(
icon: const Icon(Icons.home),
label: "Dashboard",
),
BottomNavigationBarItem(
icon: const Icon(Icons.car_repair),
label: "Target",
),
],
),
),
),
),
],
);
}
}
dashboard.dart
import 'package:navbartest/target.dart';
class Dashboard extends StatelessWidget {
const Dashboard({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Center(
child: Container(
width: 120,
height: 20,
color: Colors.blue,
child: InkResponse(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const Target()),
);
},
child: Text('navigate to target'),
),
),
),
),
);
}
}
target.dart:
class Target extends StatelessWidget {
const Target({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Text('target'),
),
);
}
}
when the app is started, it looks like this
when I click the blue button to navigate, it looks like this (NavBar is gone!)
when I click the symbol in the navbar redirecting me to target.dart, it looks like this (thats how I want it with the blue button too!)
actually you need to use a state management for this type of actions , but I found a work around in your case ,
I will set the classes next Just replace them with your classes and it will work.
1 - page0.dart:
import 'target.dart';
import 'package:flutter/material.dart';
import 'dash.dart';
class BottomNavBar extends StatefulWidget {
const BottomNavBar({super.key});
#override
State<BottomNavBar> createState() => BottomNavBarState();
}
class BottomNavBarState extends State<BottomNavBar> {
late int _pageIndex;
late final List<Widget> _tabList;
Widget? onItemTap(int index) {
setState(() {
_pageIndex = index;
});
return null;
}
#override
void initState(){
super.initState();
_pageIndex = 0;
_tabList = [
Dashboard(ref:(int number){
setState(() {
_pageIndex = number;
});
}),
const Target(),
];
}
#override
Widget build(BuildContext context) {
return Stack(
children: [
_tabList.elementAt(_pageIndex),
Padding(
padding: EdgeInsets.only(right: 35, bottom: 25, left: 35),
child: Align(
alignment: const Alignment(0.0, 1.0),
child: ClipRRect(
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
child: BottomNavigationBar(
backgroundColor: const Color(0xff565656),
type: BottomNavigationBarType.fixed,
showSelectedLabels: false,
showUnselectedLabels: false,
unselectedItemColor: Colors.white,
selectedItemColor: Colors.white,
onTap: onItemTap,
items: [
BottomNavigationBarItem(
icon: const Icon(Icons.home),
label: "Dashboard",
),
BottomNavigationBarItem(
icon: const Icon(Icons.car_repair),
label: "Target",
),
],
),
),
),
),
],
);
}
}
2 - dashboard.dart :
import 'package:flutter/material.dart';
class Dashboard extends StatelessWidget {
const Dashboard({super.key, required this.ref});
final Function(int)? ref ;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Center(
child: Container(
width: 120,
height: 20,
color: Colors.blue,
child: InkResponse(
onTap: ()=>ref!(1),
child: Text('navigate to target'),
),
),
),
),
);
}
}
3 - target.dart:
import 'package:flutter/material.dart';
class Target extends StatelessWidget {
const Target({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Text('target'),
),
);
}
}
remove the import and re import for the right paths in your application file , but this is a work around and you should use the state management .

how to build a IOS style list with listview builder in Flutter?

I was wondering how to build a Cupertino list like that, with a listView.builder
I did it with the CupertinoFormSection, but when i add the listView.builder inside the form, the list does not show. So, right now i put the CupertinoFormSection after the listView, but the result is not what I want.
This is my code:
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
child: ListView.builder(
itemCount: entries.length,
itemBuilder: (context, i) {
return GestureDetector(
onTap: () {
setState(() async {
index = i;
if (i == 0){
await context.setLocale(Locale('en','US'));
}
else if (i == 1){
await context.setLocale(Locale('fr','FR'));
}
else {
await context.setLocale(Locale('it','IT'));
}
});
},
child: CupertinoFormSection(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween,
children:[
Text(entries[i]),
index == i
? Icon(Icons.check_outlined, color: Colors.blue,)
: Icon(null),
],
),
),
],
),
);
},
),
This is the output:
What you're looking for is the standard widgets CupertinoFormSection and the CupertinoFormRow. They are made specific for this kind of UI.
Check it out (also the live demo on DartPad).
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const CupertinoApp(
title: 'Flutter Demo',
home: MyHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class Item {
final String prefix;
final String? helper;
const Item({required this.prefix, this.helper});
}
const items = [
Item(prefix: 'Italiano', helper: 'Italiano'),
Item(prefix: 'English (US)', helper: 'Inglese (USA)'),
Item(prefix: 'Español (EE. UU.)', helper: 'Spagnolo (USA)'),
Item(prefix: 'Italiano (Italia)', helper: 'Italiano (Italia)'),
Item(prefix: 'Italiano (Svizzera)', helper: 'Italiano (Svizzera)'),
Item(prefix: 'English', helper: 'Inglese'),
];
class _MyHomePageState extends State<MyHomePage> {
var _selectedIndex = 0;
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: Container(
color: const Color.fromARGB(255, 242, 242, 247),
child: Center(
child: Container(
width: 250,
padding: const EdgeInsets.symmetric(vertical: 16),
child: SingleChildScrollView(
child: CupertinoFormSection.insetGrouped(
children: [
...List.generate(
items.length,
(index) => GestureDetector(
onTap: () => setState(() => _selectedIndex = index),
child: buildCupertinoFormRow(
items[index].prefix,
items[index].helper,
selected: _selectedIndex == index,
),
),
),
],
),
),
),
),
),
);
}
Widget buildCupertinoFormRow(
String prefix,
String? helper, {
bool selected = false,
}) {
return CupertinoFormRow(
prefix: Text(prefix),
helper: helper != null
? Text(
helper,
style: Theme.of(context).textTheme.bodySmall,
)
: null,
child: selected
? const Icon(
CupertinoIcons.check_mark,
color: Color.fromARGB(255, 45, 118, 234),
size: 20,
)
: Container(),
);
}
}

How can I scroll down and focus to a specific widget in flutter?

I am implementing a tutorial of app using https://pub.dev/packages/tutorial_coach_mark . This marked button of beyond the view. So when I need to target this button, I need to scroll/focus this specific part. But I can not find any solution. Can anyone help me with that please?
One Idea is to , Make one Listview with all your widgets . then
Use this :
scroll_to_index: ^2.1.1
Example:
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:scroll_to_index/scroll_to_index.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Scroll To Index Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Scroll To Index Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
static const maxCount = 100;
static const double maxHeight = 1000;
final random = math.Random();
final scrollDirection = Axis.vertical;
late AutoScrollController controller;
late List<List<int>> randomList;
#override
void initState() {
super.initState();
controller = AutoScrollController(
viewportBoundaryGetter: () =>
Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom),
axis: scrollDirection);
randomList = List.generate(maxCount,
(index) => <int>[index, (maxHeight * random.nextDouble()).toInt()]);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: [
IconButton(
onPressed: () {
setState(() => counter = 0);
_scrollToCounter();
},
icon: Text('First'),
),
IconButton(
onPressed: () {
setState(() => counter = maxCount - 1);
_scrollToCounter();
},
icon: Text('Last'),
)
],
),
body: ListView(
scrollDirection: scrollDirection,
controller: controller,
children: randomList.map<Widget>((data) {
return Padding(
padding: EdgeInsets.all(8),
child: _getRow(data[0], math.max(data[1].toDouble(), 50.0)),
);
}).toList(),
),
floatingActionButton: FloatingActionButton(
onPressed: _nextCounter,
tooltip: 'Increment',
child: Text(counter.toString()),
),
);
}
int counter = -1;
Future _nextCounter() {
setState(() => counter = (counter + 1) % maxCount);
return _scrollToCounter();
}
Future _scrollToCounter() async {
await controller.scrollToIndex(counter,
preferPosition: AutoScrollPosition.begin);
controller.highlight(counter);
}
Widget _getRow(int index, double height) {
return _wrapScrollTag(
index: index,
child: Container(
padding: EdgeInsets.all(8),
alignment: Alignment.topCenter,
height: height,
decoration: BoxDecoration(
border: Border.all(color: Colors.lightBlue, width: 4),
borderRadius: BorderRadius.circular(12)),
child: Text('index: $index, height: $height'),
));
}
Widget _wrapScrollTag({required int index, required Widget child}) =>
AutoScrollTag(
key: ValueKey(index),
controller: controller,
index: index,
child: child,
highlightColor: Colors.black.withOpacity(0.1),
);
}
This will work Perfectly
final dataKey = new GlobalKey();
SingleChildScrollView(
child: Column(
children: [
otherwidgets(),
otherwidgets(),
Container(
key: controller.dataKey,
child: helpPart(context),
),
otherwidgets(),
otherwidgets(),
],
),
on action: Scrollable.ensureVisible(dataKey.currentContext!);
This worked for me!

How change the Icon of an IconButton when it is pressed

I want to know how I can change the Icon of an IconButton when it is pressed. (Favorite_border to Favorite). I tried somethings but it doesn't works.
Maybe it is easy but I am a beginner and I don't understand very well how it is works.
Update
import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
import '../recyclerview/data.dart';
import 'package:watch/constants.dart';
int itemCount = item.length;
List<bool> selected = new List<bool>();
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
initState() {
for (var i = 0; i < itemCount; i++) {
selected.add(false);
}
super.initState();
}
Icon notFavorite = Icon(Icons.favorite_border, size: 25,);
Icon inFavorite = Icon(Icons.favorite, size: 25,);
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Accueil', style: kAppBarStyle,),
//backgroundColor: Colors.white,
elevation: 0,
),
body: ListView.builder(
itemCount: itemCount,
itemBuilder: (BuildContext context, int index) {
return Container(
child: new Row(
children: <Widget>[
//Image
new Container(
margin: new EdgeInsets.all(5.0),
child: new CachedNetworkImage(
imageUrl: item[index].imageURL,
height: MediaQuery.of(context).size.width / 4,
width: MediaQuery.of(context).size.width / 2,
fit: BoxFit.cover,
),
),
//Text
Expanded(
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Spacer(),
//Titre
Container(
padding: const EdgeInsets.only(bottom: 75.0, top: 10.0 ),
child: Text(
item[index].title,
style: kItemTitle,
),
),
//Decription
Container(
padding: const EdgeInsets.only(left: 10.0, top: 10.0),
child:Text(
item[index].description,
style: kItemDescription,
),
),
//Favoris
Spacer(),
GestureDetector(
child: Container(
padding: const EdgeInsets.only(right: 10.0, top: 3.0),
child: selected.elementAt(index) ? inFavorite : notFavorite,
),
onTap: () {
setState(() {
selected[index] = !selected.elementAt(index);
});
},
),
],
),
),
],
),
);
}
)
);
}
}
It is a ListView with Images, Texts and the Favorite Button and it works fine.
First you need a boolean variable.
bool toggle = false;
After that you can use IconButton like this:
IconButton(
icon: toggle
? Icon(Icons.favorite_border)
: Icon(
Icons.favorite,
),
onPressed: () {
setState(() {
// Here we changing the icon.
toggle = !toggle;
});
}),
custom radio button (some IconButton in ListView that change their icons):
main.dart file :
import 'package:flutter/material.dart';
import 'my_home_page.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
my_home_page.dart file:
import 'package:flutter/material.dart';
int itemCount = 5;
List<bool> selected = new List<bool>();
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
initState() {
for (var i = 0; i < itemCount; i++) {
selected.add(false);
}
super.initState();
}
Icon firstIcon = Icon(
Icons.radio_button_on, // Icons.favorite
color: Colors.blueAccent, // Colors.red
size: 35,
);
Icon secondIcon = Icon(
Icons.radio_button_unchecked, // Icons.favorite_border
color: Colors.grey,
size: 35,
);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: ListView.builder(
itemCount: itemCount,
itemBuilder: (BuildContext context, int index) {
return IconButton(
icon: selected.elementAt(index) ? firstIcon : secondIcon,
onPressed: () {
try {
// your code that you want this IconButton do
setState(() {
selected[index] = !selected.elementAt(index);
});
print('tap on ${index + 1}th IconButton ( change to : ');
print(selected[index] ? 'active' : 'deactive' + ' )');
} catch (e) {
print(e);
}
},
);
}),
),
);
}
}
Copy paste the code and it will work :)
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark(),
home: HomeApp(),
);
}
}
class HomeApp extends StatefulWidget {
#override
_HomeAppState createState() => _HomeAppState();
}
class _HomeAppState extends State<HomeApp> {
// Using a Bool
bool addFavorite = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Flutter App :)"),
),
body: Center(
child: IconButton(
icon: Icon(addFavorite ? Icons.favorite : Icons.favorite_border),
onPressed: () {
// Setting the state
setState(() {
addFavorite = !addFavorite;
});
}),
),
);
}
}
Updating the Code for ListView
class _HomeAppState extends State<HomeApp> {
// Using a Bool List for list view builder
List<bool> addFavorite = List<bool>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Flutter App :)"),
),
body: ListView.builder(
itemCount: 10,
itemBuilder: (context, index) {
// Setting a bool initially
addFavorite.add(false);
return IconButton(
icon: Icon(addFavorite.elementAt(index)
? Icons.favorite
: Icons.favorite_border),
onPressed: () {
// Setting the state
setState(() {
// Changing icon of specific index
addFavorite[index] =
addFavorite[index] == false ? true : false;
});
});
}),
);
}
}
the IconButton must be in StatefulWidget and use a flag for unselected icon and selected icon:
.
.
.
bool selected = false;
Icon first_icon = Icon(...);
Icon second_icon = Icon(...);
.
.
.
IconButton(
icon: selected
? first_icon
: second_icon,
onPressed: () {
try {
// your code that you want this IconButton do
setState(() {
selected = !selected;
});
} catch(e) {
print(e);
}
}),
for use in ListView:
.
.
.
List<bool> selected = new List<bool>();
Icon first_icon = Icon(...);
Icon second_icon = Icon(...);
.
.
.
ListView.builder(
controller: scrollController,
primary: true,
...
itemCount: _yourListViewLength,
itemBuilder: (BuildContext context, int i) {
selected.add(false);
IconButton(
icon: selected.elementAt(i)
? first_icon
: second_icon,
onPressed: () {
try {
// your code that you want this IconButton do
setState(() {
selected.elementAt(i) = !selected.elementAt(i);
});
} catch(e) {
print(e);
}
}),
},
)
i hope this help you
My code if you want : home_screen.dart
import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
import '../recyclerview/data.dart';
import 'package:watch/constants.dart';
class ListViewExample extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new ListViewExampleState();
}
}
class ListViewExampleState extends State<ListViewExample>{
bool addFavorite = false;
Icon notFavorite = Icon(Icons.favorite_border, size: 25,);
Icon inFavorite = Icon(Icons.favorite, size: 25,);
List<Container> _buildListItemsFromItems(){
return item.map((item){
var container = Container(
child: new Row(
children: <Widget>[
//Image
new Container(
margin: new EdgeInsets.all(5.0),
child: new CachedNetworkImage(
imageUrl: item.imageURL,
height: MediaQuery.of(context).size.width / 4,
width: MediaQuery.of(context).size.width / 2,
fit: BoxFit.cover,
),
),
//Text
Expanded(
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Spacer(),
//Titre
Container(
padding: const EdgeInsets.only(bottom: 75.0, top: 5.0 ),
child: Text(
item.title,
style: kItemTitle,
),
),
//Decription
Container(
padding: const EdgeInsets.only(left: 10.0, top: 5.0),
child:Text(
item.description,
style: kItemDescription,
),
),
//Favoris
Spacer(),
GestureDetector(
child: Container(
padding: const EdgeInsets.only(right: 10.0, top: 1.0),
child: addFavorite ? inFavorite : notFavorite,
),
onTap: () {
setState(() {
addFavorite = !addFavorite;
});
},
),
],
),
),
],
),
);
return container;
}).toList();
}
//Scaffold Global
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Accueil', style: kAppBarStyle,),
//backgroundColor: Colors.white,
elevation: 0,
),
body: ListView(
children: _buildListItemsFromItems(),
),
);
}
}
It is not an IconButton but just an Icon but it is working.