How to manage a custom widget state in SingleChildScrollView Widget - flutter

I'm trying to design this view.
I already have the basic design of the cards, but i would like to know how to change the card's background color, the card's border color and add the little green square according to the width size of the current card when the user click one of them. It's important to know that only one card can be painted in green when the user clicked it.
Here is my code:
CategoryCardModel
class CategoryCardModel {
final String? categoryCardModelName;
CategoryCardModel(this.categoryCardModelName);
}
CategoryCard
import 'dart:ffi';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
class CategoryCard extends StatelessWidget {
final String? categoryCardName;
final Function()? wasPressed;
const CategoryCard({
super.key,
required this.categoryCardName,
this.wasPressed,
});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: wasPressed,
child: Card(
shape: RoundedRectangleBorder(
side: const BorderSide(
color: Color.fromRGBO(212, 213, 215, 100),
width: 3,
),
borderRadius: BorderRadius.circular(20.0),
),
child: Container(
decoration: BoxDecoration(
color: const Color.fromRGBO(242, 243, 243, 100),
borderRadius: BorderRadius.circular(20.0)),
padding: const EdgeInsets.all(10),
child: Text(
categoryCardName ?? 'Todas',
style: const TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: Color.fromRGBO(91, 94, 99, 100)),
),
),
),
);
}
}
MyHomePage
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'category_card.dart';
import 'category_card_model.dart';
class MyHomePage extends StatefulWidget {
MyHomePage({super.key, required this.title});
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// List of models
final categoryCardModelList = <CategoryCardModel>[
CategoryCardModel("Todas"),
CategoryCardModel("Smartphones"),
CategoryCardModel("Accesorios para celular"),
CategoryCardModel("TV")
];
List<CategoryCardModel>? _categoryCardModelListOf;
#override
void initState() {
super.initState();
setState(() {
_categoryCardModelListOf = List.of(categoryCardModelList);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: SingleChildScrollView(
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: _categoryCardModelListOf!
.map<Widget>((categoryCardModel) => CategoryCard(
wasPressed: () {
print("Hello World");
setState(() {});
},
categoryCardName:
categoryCardModel.categoryCardModelName))
.toList())));
}
}
main
import 'package:flutter/material.dart';
import 'my_home_page.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: "Caregory Cards"),
);
}
}

Selected is needed for Card
class CategoryCard extends StatelessWidget {
final String? categoryCardName;
final Function()? wasPressed;
final bool isActive;
const CategoryCard(
{super.key,
required this.categoryCardName,
this.wasPressed,
this.isActive = false});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: wasPressed,
child: Card(
shape: const StadiumBorder(),
child: Container(
decoration: BoxDecoration(
color: (isActive ? Colors.green : Colors.grey).withOpacity(.1),
borderRadius: BorderRadius.circular(24.0),
border: Border.all(
width: 2, color: isActive ? Colors.green : Colors.grey)),
padding: const EdgeInsets.all(10),
child: Text(
categoryCardName ?? 'Todas',
style: const TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: Color.fromRGBO(91, 94, 99, 100)),
),
),
),
);
}
}
Create a state variable for selected model
CategoryCardModel? activeTab;
And use
children: _categoryCardModelListOf!
.map<Widget>((categoryCardModel) => CategoryCard(
isActive: activeTab == categoryCardModel,
wasPressed: () {
activeTab = categoryCardModel;
setState(() {});
},
categoryCardName: categoryCardModel.categoryCardModelName))
.toList(),
),

Update your CategoryCard class like this, you may need to change the color according to your desire :
class CategoryCard extends StatelessWidget {
final String? categoryCardName;
final Function()? wasPressed;
final bool isSelected;
const CategoryCard({
super.key,
required this.categoryCardName,
this.wasPressed,
this.isSelected = false,
});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: wasPressed,
child: Card(
shape: RoundedRectangleBorder(
side: BorderSide(
color: isSelected ? Colors.green : Color.fromRGBO(212, 213, 215, 100),
width: 3,
),
borderRadius: BorderRadius.circular(20.0),
),
child: Container(
decoration: BoxDecoration(
color: isSelected ? Colors.greenAccent : const Color.fromRGBO(242, 243, 243, 100),
borderRadius: BorderRadius.circular(20.0),
),
padding: const EdgeInsets.all(10),
child: Text(
categoryCardName ?? 'Todas',
style: const TextStyle(fontSize: 25, fontWeight: FontWeight.bold, color: Color.fromRGBO(91, 94, 99, 100)),
),
),
),
);
}
}
And then change your _MyHomePageState class to this :
class _MyHomePageState extends State<MyHomePage> {
// List of models
final categoryCardModelList = <CategoryCardModel>[
CategoryCardModel("Todas"),
CategoryCardModel("Smartphones"),
CategoryCardModel("Accesorios para celular"),
CategoryCardModel("TV")
];
List<CategoryCardModel>? _categoryCardModelListOf;
CategoryCardModel? _selectedCardModel;
#override
void initState() {
super.initState();
setState(() {
_categoryCardModelListOf = List.of(categoryCardModelList);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: _categoryCardModelListOf!
.map<Widget>((categoryCardModel) => CategoryCard(
wasPressed: () {
print("Hello World");
setState(() {
_selectedCardModel = categoryCardModel;
});
},
categoryCardName: categoryCardModel.categoryCardModelName,
isSelected: _selectedCardModel == categoryCardModel,
))
.toList(),
),
),
);
}
}

Use above two answers for highlighting selected option...and here is what missing...
The underline below selected tab...
for that update your category card as below,
as u have mentioned underline width must be in size of tab width,
I have used ** IntrinsicWidth**
class CategoryCard extends StatelessWidget {
final String? categoryCardName;
final Function()? wasPressed;
final bool? isselected;
const CategoryCard({
super.key,
required this.categoryCardName,
this.wasPressed,
this.isselected=false
});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: wasPressed,
child: IntrinsicWidth(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Column(children: [
Card(
shape: RoundedRectangleBorder(
side: BorderSide(
color:isselected==true?Colors.red: Color.fromRGBO(212, 213, 215, 100),
width: 3,
),
borderRadius: BorderRadius.circular(20.0),
),
child: Container(
decoration: BoxDecoration(
color: const Color.fromRGBO(242, 243, 243, 100),
borderRadius: BorderRadius.circular(20.0)),
padding: const EdgeInsets.all(10),
child: Text(
categoryCardName ?? 'Todas',
style: const TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: Color.fromRGBO(91, 94, 99, 100)),
),
),
),
if(isselected==true)
Padding(
padding: EdgeInsets.symmetric(horizontal: 20),
child: Container(
color: Colors.red[200],
height: 5,
),
),
],),
),
),
);
}
}

Related

How to achieve animated search app bar in flutter?

I want to achieve the animated search app bar: https://drive.google.com/file/d/1BnykuOZExHusxIRgareKmdaPM6RlswYe/view?usp=sharing
I tried to use a stack and an animated container, to achieve it. however, it was giving renderflex error.
I would like to know if anyone has other suggestions to achieve it.
Following is the code for the custom appbar and search widget:
AppBar:
class CustomHomeAppBar extends ConsumerStatefulWidget with PreferredSizeWidget {
#override
final Size preferredSize;
CustomHomeAppBar({Key? key, required this.title})
: preferredSize = const Size.fromHeight(60.0),
super(key: key);
final String title;
#override
ConsumerState<ConsumerStatefulWidget> createState() =>
_CustomHomeAppBarState();
}
class _CustomHomeAppBarState extends ConsumerState<CustomHomeAppBar> {
#override
Widget build(BuildContext context) {
return AppBar(
backgroundColor: Colors.white,
foregroundColor: Colors.black,
elevation: 0,
title: Stack(children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
InkWell(
onTap: () {},
child: const CircleAvatar(
radius: 18,
backgroundColor: Colors.teal,
child: CircleAvatar(
backgroundImage: NetworkImage(
"https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80"),
radius: 28,
),
),
),
const SizedBox(
width: 10,
),
Text(
widget.title,
style:
const TextStyle(fontWeight: FontWeight.w400, fontSize: 22),
),
],
),
Positioned(right: 0, child: AnimatedSearchBar())
]));
}
}
search widget:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/foundation/key.dart';
import 'package:flutter/src/widgets/framework.dart';
class AnimatedSearchBar extends StatefulWidget {
const AnimatedSearchBar({Key? key}) : super(key: key);
#override
State<AnimatedSearchBar> createState() => _AnimatedSearchBarState();
}
class _AnimatedSearchBarState extends State<AnimatedSearchBar> {
bool _folded = true;
#override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: const Duration(milliseconds: 400),
width: _folded ? 24 : MediaQuery.of(context).size.width - 16,
// height: 56,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(32),
color: Colors.white,
),
child: Row(children: [
Expanded(
child: Container(
// padding: const EdgeInsets.only(left: 16),
decoration:
BoxDecoration(color: Color.fromARGB(255, 212, 207, 207)),
child: !_folded
? const TextField(
decoration: InputDecoration(
hintText: 'Search',
hintStyle: TextStyle(color: Colors.blue),
border: InputBorder.none))
: null,
),
),
AnimatedContainer(
duration: const Duration(milliseconds: 400),
child: InkWell(
onTap: () {
print("clicks");
setState(() {
_folded = !_folded;
});
},
// child: Padding(
// padding: const EdgeInsets.all(16.0),
child: Icon(
_folded ? Icons.search : Icons.close,
color: Colors.blue[900],
),
),
),
// )
]),
);
}
}
It results in the following appbar:
search with stack

How should I manage multiple Provider and Consumer

I'm coding textfield with river_pod library as follows.
When I tapped each suffixIcon, it works both password and password-confirmation field and finally it figured out that each state is only managed by single provider.
And wonder how should I manage this provider and consumer separately, and effectively.
//main.dart
import 'package:cards/view/textfield.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
runApp(
ProviderScope(
child: MaterialApp(
title: 'Cards Demo',
home: RegisterWidget(),
),
),
);
}
class RegisterWidget extends ConsumerWidget {
#override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
body: Padding(
padding: const EdgeInsetsDirectional.fromSTEB(20, 50, 20, 0),
child: Column(
children: [
Container(
width: double.infinity,
height: 50,
// color: Colors.grey,
alignment: Alignment.topLeft,
child: Image.asset('images/logo.png'),
),
Container(
padding: const EdgeInsetsDirectional.fromSTEB(10, 0, 10, 0),
margin: const EdgeInsets.only(top: 30),
width: double.infinity,
// color: Colors.blue,
child: Column(
children: [
const Align(
alignment: AlignmentDirectional(0, 0),
child: TextFieldCustom(
labelText: "email",
hintText: "type your email-adress",
suffixIcon: null,
),
),
Align(
alignment: const AlignmentDirectional(0, 0),
child: TextFieldCustom(
labelText: "password",
hintText: "set password",
suffixIcon: SuffixIconWidget()),
),
Align(
alignment: const AlignmentDirectional(0, 0),
child: TextFieldCustom(
labelText: "password-confirm",
hintText: "password for confirmation",
suffixIcon: SuffixIconWidget()),
),
],
),
),
],
),
));
}
}
//textfield.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
final mask = StateProvider<bool>((ref) => true);
class TextFieldCustom extends ConsumerWidget {
const TextFieldCustom({required this.labelText, required this.hintText, this.suffixIcon, Key? key}): super(key: key);
final String labelText;
final String hintText;
final Widget? suffixIcon;
#override
Widget build(BuildContext context, WidgetRef ref) {
return Container(
margin: const EdgeInsets.only(bottom: 10),
child: TextFormField(
style: const TextStyle(
fontSize: 13,
),
obscureText: ObscureTextFunction(suffixIcon, ref),
decoration: InputDecoration(
labelText: labelText, //**
hintText: hintText, //**
suffixIcon: suffixIcon, //**
labelStyle: const TextStyle(
fontSize: 15,
color: Color.fromARGB(255, 219, 219, 219),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(2),
borderSide: const BorderSide(
color: Color.fromARGB(255, 219, 219, 219),
width: 1.0,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(2),
borderSide: const BorderSide(
color: Color.fromARGB(255, 219, 219, 219),
width: 1.0, //outlineの太さ
)),
),
));
}
}
bool ObscureTextFunction(suffixIcon, ref) {
if (suffixIcon == null) {
return false;
} else {
final bool isVisible = ref.watch(mask);
return isVisible ? false : true;
}
}
class SuffixIconWidget extends ConsumerWidget {
#override
Widget build(BuildContext context, WidgetRef ref) {
final bool isVisible = ref.read(mask);
return IconButton(
icon: Icon(ref.watch(mask) // false
? FontAwesomeIcons.solidEye
: FontAwesomeIcons.solidEyeSlash),
onPressed: () {
ref.read(mask.notifier).update((state) => !isVisible);
},
);
}
}
Additional Code
final mask = StateProvider<bool>((ref) => true);
final maskConfirm = StateProvider<bool>((ref) => true);
class SuffixIconWidget extends ConsumerWidget {
#override
Widget build(BuildContext context, WidgetRef ref) {
final bool isVisible = ref.read(mask);
return IconButton(
icon: Icon(ref.watch(mask) // false
? FontAwesomeIcons.solidEye
: FontAwesomeIcons.solidEyeSlash),
onPressed: () {
ref.read(mask.notifier).update((state) => !isVisible);
},
);
}
}
class SuffixIconWidgetConfirm extends ConsumerWidget {
#override
Widget build(BuildContext context, WidgetRef ref) {
final bool isVisible = ref.read(maskConfirm);
return IconButton(
icon: Icon(ref.watch(maskConfirm) // false
? FontAwesomeIcons.solidEye
: FontAwesomeIcons.solidEyeSlash),
onPressed: () {
ref.read(maskConfirm.notifier).update((state) => !isVisible);
},
);
}
}
For local states that are only important for the widget, I would just recommend you have a simple boolean in TextFieldCustom and change it with setState.
Generally speaking though, for this widget to be correctly reusable with Riverpod, you should create a callback function onIconPressed(). Just like you are passing labelText, suffixIcon etc., in Flutter you can also pass functions like you do for buttons. Then for one provider to work on both widgets, it shouldn't be a provider of boolean, but instead of an object that holds two booleans.

When I press the button, I cannot change my Text values ​with setState()

When I press the button, I want the value of my _sicaklikSeviyesi variable to change and update it to the screen with setState(), but I can't. I've been dealing with this problem for the last 2 days, I couldn't find a solution for a song. Can you help me pls?
Main Screen Codes :
import 'package:akilli_okul_sistemleri/alert_dialog.dart';
import 'package:akilli_okul_sistemleri/bottom_info_bar.dart';
import 'package:akilli_okul_sistemleri/drawer_panel.dart';
import 'package:flutter/material.dart';
class AnaMenu extends StatefulWidget {
const AnaMenu({Key? key}) : super(key: key);
#override
State<AnaMenu> createState() => _AnaMenuState();
}
class _AnaMenuState extends State<AnaMenu> {
BottomInfoBarState altPanel = BottomInfoBarState();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Akıllı Ev Sistemleri'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
altPanel.degisenDegerler();
AlertBoxDialog.alertBoxCreator(
context: context,
title: "Başlık",
desc: 'Açıklama',
imageLocation: AlertBoxDialog.yuksekSicaklikLogo);
},
child: Text("ISI UYARISI"),
),
),
drawer: DrawerPanel(),
bottomNavigationBar: BottomInfoBar(),
);
}
}
Bottom Info Bar Codes :
import 'package:flutter/material.dart';
import 'package:akilli_okul_sistemleri/ana_menu.dart';
class BottomInfoBar extends StatefulWidget {
BottomInfoBar({Key? key}) : super(key: key);
#override
BottomInfoBarState createState() => BottomInfoBarState();
}
class BottomInfoBarState extends State<BottomInfoBar> {
Color _logoRengi = Colors.white;
int _sicaklikSeviyesi = 15,
_sesSeviyesi = 15,
_hareketSeviyesi = 45,
_isikSeviyesi = 75,
_dumanSeviyesi = 20;
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(color: Colors.black38, spreadRadius: 0, blurRadius: 10),
],
),
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(15), topRight: Radius.circular(15)),
child: BottomAppBar(
color: Colors.orange[300],
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_bottomContainerCreator(
Icons.local_fire_department, _sicaklikSeviyesi.toString()),
_bottomContainerCreator(
Icons.record_voice_over, "%$_sesSeviyesi"),
_bottomContainerCreator(
Icons.directions_walk, '%$_hareketSeviyesi'),
_bottomContainerCreator(Icons.light, "%$_isikSeviyesi"),
_bottomContainerCreator(Icons.cloud, "%$_dumanSeviyesi"),
],
),
),
),
);
}
_bottomContainerCreator(IconData icon, String text) {
return Container(
decoration: BoxDecoration(
color: Colors.grey[700], borderRadius: BorderRadius.circular(15.0)),
margin: EdgeInsets.all(3),
padding: EdgeInsets.all(3),
height: 60,
child: Column(
children: [
Container(
padding: EdgeInsets.all(5),
child: Icon(
icon,
size: 27,
color: _logoRengi,
),
),
Padding(
padding: const EdgeInsets.only(top: 1),
child: Text(
text,
style:
TextStyle(fontWeight: FontWeight.bold, color: Colors.white),
),
),
],
),
);
}
void degisenDegerler() {
setState(() {
_sicaklikSeviyesi = 100;
if (_sicaklikSeviyesi < 20) {
_logoRengi = Colors.blue;
} else if (_sicaklikSeviyesi > 50) {
_logoRengi = Colors.red;
} else {
_logoRengi = Colors.yellow;
}
});
}
}
You can move the setState up the widget tree (in the AnaMenu widget). All widgets that depend on the value (in your case the color) will rebuild and update.
Try this code below for a simple function. If your bottombar doesn't require other logic. You might want to convert it to a Stateless widget
class AnaMenu extends StatefulWidget {
const AnaMenu({Key? key}) : super(key: key);
#override
State<AnaMenu> createState() => _AnaMenuState();
}
class _AnaMenuState extends State<AnaMenu> {
late Color color;
#override
void initState() {
color = Colors.blue;
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Akıllı Ev Sistemleri'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
setState(() {
color = Colors.green;
});
// AlertBoxDialog.alertBoxCreator(
// context: context,
// title: "Başlık",
// desc: 'Açıklama',
// imageLocation: AlertBoxDialog.yuksekSicaklikLogo);
},
child: Text("ISI UYARISI"),
),
),
// drawer: DrawerPanel(),
bottomNavigationBar: BottomInfoBar(color: color),
);
}
}
class BottomInfoBar extends StatefulWidget {
final Color color;
BottomInfoBar({required this.color, Key? key}) : super(key: key);
#override
BottomInfoBarState createState() => BottomInfoBarState();
}
class BottomInfoBarState extends State<BottomInfoBar> {
// Color _logoRengi = Colors.white;
late int _sicaklikSeviyesi;
late int _sesSeviyesi;
late int _hareketSeviyesi;
late int _isikSeviyesi;
late int _dumanSeviyesi;
#override
void initState() {
_sicaklikSeviyesi = 15;
_sesSeviyesi = 15;
_hareketSeviyesi = 45;
_isikSeviyesi = 75;
_dumanSeviyesi = 20;
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(color: Colors.black38, spreadRadius: 0, blurRadius: 10),
],
),
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(15), topRight: Radius.circular(15)),
child: BottomAppBar(
color: Colors.orange[300],
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_bottomContainerCreator(
Icons.local_fire_department, _sicaklikSeviyesi.toString()),
_bottomContainerCreator(
Icons.record_voice_over, "%$_sesSeviyesi"),
_bottomContainerCreator(
Icons.directions_walk, '%$_hareketSeviyesi'),
_bottomContainerCreator(Icons.light, "%$_isikSeviyesi"),
_bottomContainerCreator(Icons.cloud, "%$_dumanSeviyesi"),
],
),
),
),
);
}
_bottomContainerCreator(IconData icon, String text) {
return Container(
decoration: BoxDecoration(
color: Colors.grey[700], borderRadius: BorderRadius.circular(15.0)),
margin: EdgeInsets.all(3),
padding: EdgeInsets.all(3),
height: 60,
child: Column(
children: [
Container(
padding: EdgeInsets.all(5),
child: Icon(
icon,
size: 27,
color: widget.color,
),
),
Padding(
padding: const EdgeInsets.only(top: 1),
child: Text(
text,
style:
TextStyle(fontWeight: FontWeight.bold, color: Colors.white),
),
),
],
),
);
}
}

Making reusable flutter widget

I've been trying to make my custom widget reusable but kept on hitting dead ends... I want to be able to use change the colors of the icons, text within the card, the first card, and the enclosed card... Also, I should be able to change the icons, text that is within the icon and also the on tap function for each of the buttons should be able to do something different whenever it's tapped
class _CustomCardState extends State<CustomCard> {
#override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.fromLTRB(20, 10, 20, 1),
color: Colors.red,
child: InkWell(
onTap: (){},
child: ListTile(
leading: Card(
color: Colors.white,
margin: EdgeInsets.all(5),
child: Padding(
padding: EdgeInsets.all(8.0),
child: Icon(
KycIcons.add_a_photo,
size: 20,
color: Colors.red,
),
),
),
title: Text('Uplaod your selfie',
style: TextStyle(color: Colors.white, fontSize: 16)),
),
),
);
}
}`
Here is a very simple example of how you can build reusable widgets:
import 'package:flutter/material.dart';
class ContainerMain extends StatelessWidget {
String text;
Color color;
ContainerMain(this.text, {this.color = Colors.white});
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Container(
alignment: Alignment.center,
height: size.height / 10,
width: size.width,
child: Text(
text,
style: TextStyle(fontSize: 20, color: color),
),
);
}
}
Here is my contribution to your class. BTW, it should be a StatelessWidget instead of a StatefulWidget since there are no state variables involved.
import 'package:flutter/material.dart';
class CustomCard extends StatefulWidget {
final Color iconColor;
final double iconSize;
final Color cardColor;
final Color innerCardColor;
final String title;
final TextStyle style;
final void Function()? onTap;
const CustomCard({
Key? key,
this.iconColor = Colors.red,
this.iconSize = 20.0,
this.cardColor = Colors.red,
this.innerCardColor = Colors.white,
this.title = 'Upload your selfie',
this.style = const TextStyle(color: Colors.white, fontSize: 16),
this.onTap,
}) : super(key: key);
#override
_CustomCardState createState() => _CustomCardState();
}
class _CustomCardState extends State<CustomCard> {
#override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.fromLTRB(20, 10, 20, 1),
color: widget.cardColor,
child: InkWell(
child: ListTile(
leading: Card(
color: widget.innerCardColor,
margin: const EdgeInsets.all(5),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
KycIcons.add_a_photo,
size: iconSize,
color: widget.iconColor,
),
),
),
title: Text(widget.title, style: widget.style),
onTap: widget.onTap,
),
),
);
}
}

Navigate to another page from ListTile

My app got a expandable List with multiple entries. I want to navigate to different pages by clicking on the ListTiles on the lowest level. I know that there's the 'onTap' method but it requires a buildContext which I dont have the way I programmed it.
I got the code from the web and modified it just a little. Heres the Code:
import 'package:flutter/material.dart';
import '../screens/model_view_screen.dart';
import '../models/entry.dart';
class EntryItem extends StatelessWidget {
const EntryItem(this.entry);
final Entry entry;
Widget _buildTiles(Entry root) {
if (root.children.isEmpty) {
return Padding(
padding: const EdgeInsets.all(10.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(
width: 2,
color: Color.fromRGBO(3, 120, 163, 1),
),
),
child: ListTile(
leading: Image.asset(root.imageUrl),
title: Text(root.title),
onTap: () {},
),
),
);
}
return Padding(
padding: const EdgeInsets.all(10.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(
width: 3,
color: Color.fromRGBO(3, 120, 163, 1),
),
),
child: ExpansionTile(
key: PageStorageKey<Entry>(root),
leading: Image.asset(root.imageUrl),
title: Text(root.title, style: TextStyle(color: Colors.black)),
children: root.children.map<Widget>(_buildTiles).toList(),
),
),
);
}
#override
Widget build(BuildContext context) {
return _buildTiles(entry);
}
}
The routeName of the destination is given in a List:
class Entry{
final String title;
final String imageUrl;
final String routeName;
final List<Entry> children;
Entry(this.title, this.imageUrl, this.routeName, [this.children = const <Entry>[]]);
}
Thank you in advance.
You want to pass BuildContext to _buildTiles:
Widget _buildTiles(BuildContext context, Entry root) {
....
child: ListTile(
leading: Image.asset(root.imageUrl),
title: Text(root.title),
onTap: () => Navigator.of(context).pushNamed(root.routeName),
),
....
children: root.children.map((e) => _buildTiles(context, e)).toList(),
....
#override
Widget build(BuildContext context) {
return _buildTiles(context, entry);
}