I am a newbie in a flutter. I have a simple app I need to show the JSON value in my container and on tap, the second value will show.
class _MyHomePageState extends State<MyHomePage> {
final List _questions = [
{'would': 'Coffe', 'rather': 'Tea'},
{'would': 'Coffe', 'rather': 'Tea'},
{'would': 'Coffe', 'rather': 'Tea'},
];
#override
Widget build(BuildContext context) {
final PrimaryColor = const Color(0xff404040);
final PreferredSizeWidget appBar = AppBar(
centerTitle: true,
title: Text(
'Would you Rather',
style: TextStyle(fontFamily: 'FredokaOne'),
),
backgroundColor: PrimaryColor,
);
return Scaffold(
backgroundColor: Color(0xff404040),
appBar: appBar,
body: Column(
children: <Widget>[
InkWell(
onTap: () => print("And after click here it will change both question"),
child: Container(
child: Text(_questions[0].would,),
),
),
InkWell(
onTap: () => print("And after click here it will change both question"),
child: Container(
child: Text(_questions[0].rather,),
),
),
],
));
}
}
Here I have a list of questions. In 1 array there are 2 values. I need to show these 2 values in each container and when I tap on the container the next array will appear.
Create a variable index that will increment in nextQuestion function is triggered when one of the containers is tapped. The increment will stop once it reaches the last element of _questions List. Finally, use the index when assigning the values of the Text inside the Containers to change when changing the index.
class _MyHomePageState extends State<MyHomePage> {
final List _questions = [
{'would': 'Coffe', 'rather': 'Tea'},
{'would': 'Blue', 'rather': 'Red'},
{'would': 'Green', 'rather': 'Yellow'},
];
int index = 0;
#override
Widget build(BuildContext context) {
final PrimaryColor = const Color(0xff404040);
int size = _questions.length;
void nextQuestion(){
if(index < size - 1)
setState(() {
index++;
});
print(index);
}
final PreferredSizeWidget appBar = AppBar(
centerTitle: true,
title: Text(
'Would you Rather',
style: TextStyle(fontFamily: 'FredokaOne'),
),
backgroundColor: PrimaryColor,
);
return Scaffold(
backgroundColor: Color(0xff404040),
appBar: appBar,
body: Column(
children: <Widget>[
InkWell(
onTap: nextQuestion,
child: Container(
height: 100,
child: Text(_questions[index]['would']),
),
),
InkWell(
onTap: nextQuestion,
child: Container(
height: 100,
child: Text(_questions[index]['rather']),
),
),
],
));
}
}
Related
How do I make it so that the icon will only update for the tile that was clicked? Right now, the behavior is that all icons update when clicking on one tile.
Here is the code (trimmed to only include relevant parts):
Column(children: List.generate(
filteredFAQ.length,
(index) => Column(
children: [
if(index > 0) {
Container(
child: Column(
children: <Widget>[
ExpansionTile(
trailing: SvgPicture.string(
isQuestionClicked
? addPayeeArrowUp
: rightArrow,
color: primary,
),
onExpansionChanged:
(bool expanded) {
setState(() {
isQuestionClicked = expanded;
});
},
),
],
)
)
}
]
)
),);
here are screenshots of the behavior:
[2
I used the in built onExpansionChange of the ExpansionTile.
To only change the icon of the expanded tile, you can use this approach:
create a Map:
Map<int, bool> state = {};
and use it accordingly in your ExpansionTile to check whether it's selected, if the value is true or false:
List.generate(6, (index) {
return ExpansionTile(
title: Text('Item $index'),
trailing: state[index] ?? false
? Icon(Icons.arrow_drop_up)
: Icon(Icons.arrow_drop_down),
onExpansionChanged: (value) {
setState(() {
state[index] = value;
});
},
children: [
Container(
height: 100,
color: Colors.red,
),
],
);
}),
Complete runnable example:
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatefulWidget {
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
Map<int, bool> state = {};
bool isExpanded = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Demo Home Page'),
),
body: Column(
children:
// generate 6 ExpansionTiles
List.generate(6, (index) {
return ExpansionTile(
title: Text('Item $index'),
trailing: state[index] ?? false
? Icon(Icons.arrow_drop_up)
: Icon(Icons.arrow_drop_down),
onExpansionChanged: (value) {
setState(() {
state[index] = value;
});
},
children: [
Container(
height: 100,
color: Colors.red,
),
],
);
}),
),
);
}
}
You have to manage each childrens state separatory.
I think it's best to manage them in filteredFAQ by adding
bool isExpanded
property there. but you can achive by manage them as separated property like
final items = List<bool>.generate(filteredFAQ.length, (index) => false);
and change their state when they're expanded
items[index] = !items[index]
here's a sample complete code
Column(children: List.generate(
filteredFAQ.length,
(index) => Column(
children: [
if(index > 0) {
Container(
child: Column(
children: <Widget>[
ExpansionTile(
trailing: SvgPicture.string(
items[index]
? addPayeeArrowUp
: rightArrow,
color: primary,
),
onExpansionChanged:
(bool expanded) {
setState(() {
items[index] = !items[index];
});
},
),
],
)
)
}
]
)
),);
And don't forget to initalize items at where you initialize filteredFAQ
If you provide a whole code in the widget I can complete it if you need more information
I created a list of widgets. What I would like to do is to get the index of the widget that is being tapped. I wrapped the widget in gesture detection, and I would like to print the index of the widget which is being tapped
This is a widget I created:
class Tile extends StatelessWidget {
final Color color;
const Tile({Key? key,required this.color}) : super(key: key);
sayhello(int idd){
print("Hello from the tile file$idd");
}
#override
Widget build(BuildContext context) {
return GestureDetector(
child: Container(
width: 30,
height: 31,
color: color,
),
);
}
}
This is the file where it is being used:
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
List<Widget> list = [
Tile(color: Colors.black26),
Tile(color: Colors.cyanAccent),
Tile(color: Colors.deepOrange),
Tile(color: Colors.tealAccent),
Tile(color: Colors.purpleAccent),
Tile(color: Colors.yellowAccent),
Tile(color: Colors.black),
];
Color color=Colors.amber;
void _incrementCounter() {
setState(() {
if(true)
{
list[0]=Container(
child: Text('HN'),
color: Colors.deepOrange,
);
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children:[
Row(
children: [
list[0],
list[1],
list[2],
],
),
Row(
children: [
list[3],
list[4],
list[5],
],
),
]
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
I created a list of my widget and added the gestureDetector. I want to get the index of the widget which is being tapped.
I recommend you to use widget key.
Then you can print it on widget tap.
Code:
Tile widget
.
GestureDetector(
onTap: () {
print(
key.toString(),
);
},
child: Container(
width: 30,
height: 31,
color: color,
),
),
Calling Tile widget
List<Widget> list = [
Tile(
color: Colors.black26,
key: Key('tile_black'),
),
Tile(
color: Colors.cyanAccent,
key: Key('cyan_accent'),
),
];
I want to create a generic Layout which accepts a child Widget as a parameter, that lays out the content as follows:
I have an AppBar at the Top, a Title (headline), and below that the Content (could be anything). At the bottom, I have a Column with a few buttons. If the content is too big for the screen, all those widgets, except the AppBar, are scrollable. If the content fits the screen, the title and content should be aligned at the top, and the buttons at the bottom.
To showcase what I mean, I created a drawing:
It is easy to create to scrollable content functionality. But I struggle with laying out the content so that the buttons are aligned at the bottom, if the content does NOT need to be scrollable.
It is important to say that I don't know the height of the content widget or the buttons. They are dynamic and can change their height. Also, the title is optional and can have two different sizes.
What I tried is the following:
import 'package:flutter/material.dart';
class BaseScreen extends StatelessWidget {
final String? title;
final bool bigHeader;
final Widget child;
final Widget bottomButtons;
const BaseScreen({
Key? key,
required this.child,
required this.bottomButtons,
this.bigHeader = true,
this.title,
}) : super(key: key);
#override
Widget build(BuildContext context) {
final AppBar appBar = AppBar(
title: Text("AppBar"),
);
double minChildHeight = MediaQuery.of(context).size.height -
MediaQuery.of(context).viewInsets.bottom -
MediaQuery.of(context).viewInsets.top -
MediaQuery.of(context).viewPadding.bottom -
MediaQuery.of(context).viewPadding.top -
appBar.preferredSize.height;
if (title != null) {
minChildHeight -= 20;
if (bigHeader) {
minChildHeight -= bigHeaderStyle.fontSize!;
} else {
minChildHeight -= smallHeaderStyle.fontSize!;
}
}
final Widget content = Column(
mainAxisSize: MainAxisSize.min,
children: [
if (title != null)
Text(
title!,
style: bigHeader ? bigHeaderStyle : smallHeaderStyle,
textAlign: TextAlign.center,
),
if (title != null)
const SizedBox(
height: 20,
),
ConstrainedBox(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
child,
bottomButtons,
],
),
constraints: BoxConstraints(
minHeight: minChildHeight,
),
),
],
);
return Scaffold(
appBar: appBar,
body: SingleChildScrollView(
child: content,
),
);
}
TextStyle get bigHeaderStyle {
return TextStyle(fontSize: 20);
}
TextStyle get smallHeaderStyle {
return TextStyle(fontSize: 16);
}
}
The scrolling effects work perfectly, but the Buttons are not aligned at the bottom. Instead, they are aligned directly below the content. Does anyone know how I can fix this?
DartPad you can check here
customscrollview tutorial
Scaffold(
// bottomNavigationBar: ,
appBar: AppBar(
title: Text(" App Bar title ${widgets.length}"),
),
//============
body: CustomScrollView(
slivers: [
SliverFillRemaining(
hasScrollBody: false,
child: Column(
// controller: _mycontroller,
children: [
title,
...contents,
// ---------------------This give Expansion and button get down --------
Expanded(
child: Container(),
),
// ---------------------This give Expansion and button get down --------
Buttons
],
),
)
],
))
We can Achieve with the help of CustomScrollView widget and Expanded widget.here Expanded widget just expand between the widget
Sample Code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(debugShowCheckedModeBanner: false, home: MyApp()),
);
}
class MyApp extends StatefulWidget {
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
var widgets = [];
var _mycontroller = ScrollController();
#override
Widget build(BuildContext context) {
var title = Center(
child: Text(
"Scrollable title ${widgets.length}",
style: TextStyle(fontSize: 30),
));
var contents = [
...widgets,
];
var Buttons = Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 100,
child: ElevatedButton(
onPressed: () {
setState(() {
widgets.add(Container(
height: 100,
child: ListTile(
title: Text(widgets.length.toString()),
subtitle: Text("Contents BTN1"),
),
));
});
// _mycontroller.jumpTo(widgets.length * 100);
},
child: Text("BTN1"),
),
),
)),
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 100,
child: ElevatedButton(
onPressed: () {
setState(() {
if (widgets.length > 0) {
widgets.removeLast();
}
});
// _mycontroller.jumpTo(widgets.length * 100);
},
child: Text("BTN2"),
),
),
))
],
);
return MaterialApp(
debugShowCheckedModeBanner: false,
home: SafeArea(
child: Scaffold(
// bottomNavigationBar: ,
appBar: AppBar(
title: Text(" App Bar title ${widgets.length}"),
),
body: CustomScrollView(
slivers: [
SliverFillRemaining(
hasScrollBody: false,
child: Column(
// controller: _mycontroller,
children: [
title,
...contents,
Expanded(
child: Container(),
),
Buttons
],
),
)
],
)),
),
);
}
}
Try this:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp();
#override
Widget build(BuildContext context) {
return MaterialApp(
home: BaseScreen(
bottomButtons: [
ElevatedButton(onPressed: () {}, child: const Text('Button 1')),
ElevatedButton(onPressed: () {}, child: const Text('Button 2')),
],
content: Container(
color: Colors.lightGreen,
height: 200,
),
title: 'Title',
),
);
}
}
class BaseScreen extends StatelessWidget {
final bool bigHeader;
final List<Widget> bottomButtons;
final String? title;
final Widget content;
const BaseScreen({
this.bigHeader = true,
required this.bottomButtons,
required this.content,
this.title,
});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('AppBar'),
),
body: CustomScrollView(
slivers: [
SliverFillRemaining(
hasScrollBody: false,
child: Column(
children: [
if (title != null)
Padding(
padding: const EdgeInsets.symmetric(vertical: 12),
child: Text(
title!,
style: bigHeader ? _bigHeaderStyle : _smallHeaderStyle,
textAlign: TextAlign.center,
),
),
content,
const Spacer(),
...bottomButtons,
],
),
),
],
),
);
}
TextStyle get _bigHeaderStyle => const TextStyle(fontSize: 20);
TextStyle get _smallHeaderStyle => const TextStyle(fontSize: 16);
}
Screenshots:
without_scrolling
scrolled_up
scrolled_down
I used a bottom navigation bar in flutter using this widget,
how can I make that bottom navigation bar show on all the pages?
and can I make it appear when I choose a page from drawer??
please help me,
You can actually achieve this with the pageview widget
https://api.flutter.dev/flutter/widgets/PageView-class.html
With this, you can have all the pages inside one class and build the bottom navigation bar underneath the pageview widget. By default the pages are swipeable but you can disable it doing
Scaffold(
body:
Container(
child:
Column(
children: <Widget> [
PageView(
physics:new NeverScrollableScrollPhysics())
controller: _controller,
children: [
MyPage1(),
MyPage2(),
MyPage3(),
],
),
googleNavBar()
]
)
);
May I suggest you to use flutter builtin BottomNavigationBar widget instead of third party widget.
Here is my code you can modify as per you requirement. Hope this will help.
class DashboardScreen extends StatefulWidget {
#override
_DashboardScreenState createState() => _DashboardScreenState();
}
class _DashboardScreenState extends State<DashboardScreen> with SingleTickerProviderStateMixin {
final _selectedItemColor = Colors.white;
final _unselectedItemColor = Color(0xFF828282);
final _selectedBgColor = Color(0xFF00cde7);
final _unselectedBgColor = Colors.transparent;
int _currentIndex = 0;
GlobalKey<ScaffoldState> _key = GlobalKey();
// List of body of current screen you import/create from other dart file.
final List<Widget> _children = [
HomeScreen(),
AppointmentScreen(id: 1),
PaymentScreen(id: 1),
ProfileScreen(id: 1)
];
// List of dynamic app bar for different page. You can also import/create app bar easily
final List<Widget> _childAppBar = [
HomeAppBar(),
AppointmentAppBar(),
PaymentAppBar(),
ProfileAppBar()
];
void _onItemTapped(int index) {
setState(() {
_currentIndex = index;
});
debugPrint("Tapped item : $index");
}
Color _getBgColor(int index) =>
_currentIndex == index ? _selectedBgColor : _unselectedBgColor;
Color _getItemColor(int index) =>
_currentIndex == index ? _selectedItemColor : _unselectedItemColor;
Widget _buildIcon(IconData iconData, String text, int index) => Container(
width: MediaQuery.of(context).size.width,
height: kBottomNavigationBarHeight,
child: Material(
color: _getBgColor(index),
child: InkWell(
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
child: Column(
children: [
Icon(iconData, color: _getItemColor(index)),
Text(text,
style: TextStyle(fontSize: 12, fontWeight: FontWeight.w500, fontFamily: 'Poppins', color: _getItemColor(index))),
],
),
),
],
),
onTap: () => _onItemTapped(index), // function responsible for navigation on tap
),
),
);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
key: _key,
appBar: _childAppBar.elementAt(_currentIndex), // this is dynamic app bar
body: _children.elementAt(_currentIndex), // this is dynamic body of the current screen
bottomNavigationBar:
BottomNavigationBar(
currentIndex: 0,
type: BottomNavigationBarType.fixed,
iconSize: 30.0,
items: [
BottomNavigationBarItem(
icon: _buildIcon(Icons.home, "Home", 0), // Check this _buildIcon function above
title: SizedBox.shrink(),
),
BottomNavigationBarItem(
icon: _buildIcon(Icons.group, "Appointment", 1),
title: SizedBox.shrink(),
),
BottomNavigationBarItem(
icon: _buildIcon(Icons.add_circle_outline, "Make Payment", 2),
title: SizedBox.shrink(),
),
BottomNavigationBarItem(
icon: _buildIcon( Icons.person_outline, "My Account", 3),
title: SizedBox.shrink(),
),
]
),
drawer: _currentIndex == 0 || _currentIndex == 3 ? Drawer( // check to show drawer on particular screen
child: ListView(
padding: const EdgeInsets.all(0.0),
children: <Widget>[
UserAccountsDrawerHeader(
accountName: Text("Mohammad Gayasuddin"),
accountEmail: Text("ladla8602#gmail.com"),
currentAccountPicture: CircleAvatar(
backgroundColor: Colors.white70,
)),
ListTile(
title: Text('Login'),
trailing: Icon(Icons.lock),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LoginScreen(),
),
);
}),
ListTile(
title: Text('Sign Up'),
trailing: Icon(Icons.add_circle_outline),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RegisterScreen(),
),
);
})
],
),
) : PreferredSize(
child: Container(),
preferredSize: Size(0.0, 0.0),
),
),
);
}
}
Unable to create dynamic list view with text and radio button in flutter
when i am creating dynamically(Fetching the data from service and binding the data with text ) list view with text and radio button when i am selecting radio button it is not showing selected (indicator );
import 'package:flutter/material.dart';
class DemoTest extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new DemoTestStatesFull(),
);}}
class DemoTestStatesFull extends StatefulWidget {
DemoTestState createState() => DemoTestState();
}
class DemoTestState extends State {
final List<String> floor_list = [
"floor1",
"floor2",
"floor3",
"floor4",
"floor5",
"floor6",
];
int _selectedIndex =0;
int _value2=0;
Container datacontainer=new Container();
_onSelected(int index) {
setState(() => _selectedIndex = index);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Dynamic View Example'),
),
body: Stack(
children: <Widget>[
new RaisedButton(
child: Text("Fetch Data"),
onPressed:() {setState(() {
datacontainer= DisplayData(floor_list);// Let Suppose Here getting data from web service after json parsing string list is
print("Button is clicked");
});}),
datacontainer,
],));}
Widget DisplayData(List<String>floorlist)
{
datacontainer =new Container(
height: 300.00,
width: 400.00,
child: ListView.builder(
itemCount: (floorlist.length),
itemBuilder: (context, i) {
return new InkResponse(
enableFeedback: true,
onTap: ()
{
print(" Card index is $i");
},
child:new Card(
color: _selectedIndex != null && _selectedIndex == i ? Colors.greenAccent : Colors.white,
elevation: 3.0,
margin: EdgeInsets.fromLTRB(5.00, 0.00, 5.00,5.00),
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(padding: const EdgeInsets.fromLTRB(20.00,0.0, 0.0,0.0)),
Padding(
padding: const EdgeInsets.all(10.0),
child: Text(floorlist[i], style: new
TextStyle(fontSize: 20.0,
fontWeight: FontWeight.bold)),
),
Padding(padding: const EdgeInsets.fromLTRB(70.00,
0.0, 0.0,0.0)),
Padding(
padding: const EdgeInsets.all(10.0),
child: Text(floorlist[i], style: new
TextStyle(fontSize: 20.0,
fontWeight: FontWeight.bold)),
),
new Radio(
value: i,
groupValue: _value2,
onChanged:(int value)
{
setState(() {
_value2=value;
print("Radio index is $value");
});}),])));}
),);return datacontainer;}}
just i want to create dynamic list view with text and select able radio button
first you can easily use gestureDetector for the row without the radio button and
put radio button at trailing , listTile is like a row for the list and have title and trailing under it as a relative position inside the tile (listTile is the list row you want that contains text and a radio button) .
ps : GestureDetector is a widget so you can return it instead of the left side of the row.
return ListTile(
leading:GestureDetector(
child: //add the text here,
onTap: () {
//here handle the onclick for text
} ,
) ,
trailing://here add the radio button with onchanged normally,
);
hope that answers your question.