Can we have a selectable ListTile() just like ChoiceChip() ?
I want my Card() which contains ListTile to be selectable.
Here is the Image of the Cards:
Here is the code of a Card:
Container(
width: 98.0,
child: Card(
child: ListTile(
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Flat No',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
],
),
subtitle: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'102',
style: TextStyle(
color: Colors.black,
fontSize: 15.0,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
),
Just use ChoiceChip with Column.
Demo here: DartPad
Try this,
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final flatRoomList = List.generate(50, (i) => i + 1);
final selectedFlatRooms = <int>{};
final alreadyReservedRooms = <int>{2, 4, 23, 7, 13, 39};
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(8.0),
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 10.0,
mainAxisSpacing: 10.0,
),
itemCount: flatRoomList.length,
itemBuilder: (context, index) {
final roomNo = flatRoomList[index];
return MyChoiceChip(
flatNo: roomNo.toString(),
selected: selectedFlatRooms.contains(roomNo),
onSelected: alreadyReservedRooms.contains(roomNo)
? null
: (isSelected) {
setState(() {
if (isSelected)
selectedFlatRooms.add(roomNo);
else
selectedFlatRooms.remove(roomNo);
});
},
);
},
),
),
);
}
}
class MyChoiceChip extends StatelessWidget {
final String flatNo;
final bool selected;
final ValueChanged<bool> onSelected;
const MyChoiceChip({
Key key,
#required this.flatNo,
#required this.selected,
this.onSelected,
}) : assert(flatNo != null),
assert(selected != null),
super(key: key);
#override
Widget build(BuildContext context) {
return ChoiceChip(
elevation: 5.0,
backgroundColor: Colors.green[50],
disabledColor: Colors.red[300],
padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0),
label: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
"Flat No",
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
),
),
Text(
flatNo,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 24.0,
),
),
],
),
),
selected: selected,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0),
),
onSelected: onSelected,
);
}
}
If you want to make your Card clickable, you just need to wrap your Card Widget with GestureDetector, InkWell, or ... .
child: GestureDetector(
oneTap: (){...}
child: Card(..),
);
Related
I am learning Flutter now and i have a screen that loading many series characters, and i have an icon in the AppBar showing
ModalBottomSheet and it have many choices to filter to update data with the new chosen ones.
I got the choices and stored the in a List of Strings but i dont know how to pass it to a function in my cubit file and i don't know how to update data using cubit , i tried many ways but didn't work with me.
Here's my code
import 'package:breakingbad/data/models/breaking_bad_characters.dart';
import 'package:breakingbad/domain/cubit/rick_and_morty_cubit.dart';
import 'package:breakingbad/presentation/character-detail.dart';
import 'package:conditional_builder_null_safety/conditional_builder_null_safety.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../widgets/character_item.dart';
import '../widgets/chip_choice.dart';
class MyHomePage extends StatefulWidget {
static String id ='home';
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return BlocConsumer<RickAndMortyCubit,RickAndMortyState>(
listener: (context, state){},
builder: (context, state) {
var cubit = RickAndMortyCubit.get(context);
return Scaffold(
appBar: AppBar(
title: const Center(child: Text('Rick And Morty')),
actions: [
IconButton(
padding: const EdgeInsets.only(right: 25),
onPressed: (){
showModalBottomSheet(
context: context,
builder: (context) =>
Column(
children: [
Container(
alignment: Alignment.center,
color: Colors.black,
width: double.infinity,
height: 50,
child: const Text('Filter Characters',style: TextStyle(color:
Colors.white,fontSize: 22),),
),
const ChoiceChipWidget(),
],
)
);
},
icon: const Icon(Icons.filter_list_sharp,size: 40,)),
],
),
body: ConditionalBuilder(
condition: state is RickAndMortyCharsLoaded,
fallback: (context)=> const Center(child: CircularProgressIndicator()),
builder: (context) => GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 2 / 3,
crossAxisSpacing: 1,
mainAxisSpacing: 1,
),
itemCount: cubit.allHuman.length,
itemBuilder: (context,index) =>
CharacterItem(
rickAndMortyCharacters: cubit.allHuman[index],
widget:CharacterDetail(rickAndMortyCharacters: cubit.allHuman[index]),
)
),
)
);
}
);
}
}
import 'package:breakingbad/domain/cubit/rick_and_morty_cubit.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class ChoiceChipWidget extends StatefulWidget {
const ChoiceChipWidget( {super.key, });
#override
State<ChoiceChipWidget> createState() => _ChoiceChipWidgetState();
}
class _ChoiceChipWidgetState extends State<ChoiceChipWidget> {
String selectedChoice1 = "";
String selectedChoice2 = "";
String selectedChoice3 = "";
List<String> filter=[];
#override
Widget build(BuildContext context) {
return BlocBuilder<RickAndMortyCubit, RickAndMortyState>(
builder: (context, state) {
var cubit = RickAndMortyCubit.get(context);
return Column(
children: [
Chip(
elevation: 20,
padding: const EdgeInsets.all(8),
backgroundColor: Colors.greenAccent[100],
shadowColor: Colors.black,
label: const Text(
'Gender',
style: TextStyle(fontSize: 20),
), //Text
),
Row(
children: cubit.gender.map((item){
return Container(
padding: const EdgeInsets.all(2.0),
child: ChoiceChip(
label: Text(item),
labelStyle: const TextStyle(
color: Colors.black, fontWeight: FontWeight.bold),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(22.0),
),
backgroundColor: Colors.grey[300],
selectedColor: Colors.blue,
selected: selectedChoice1 == item,
onSelected: (selected) {
setState(() {
selectedChoice1 = item;
filter.add(selectedChoice1);
});
},
),
);
}).toList()
),
Chip(
elevation: 20,
padding: const EdgeInsets.all(8),
backgroundColor: Colors.greenAccent[100],
shadowColor: Colors.black,
label: const Text(
'Species',
style: TextStyle(fontSize: 20),
), //Text
),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children:cubit.species.map((item){
return Container(
padding: const EdgeInsets.all(2.0),
child: ChoiceChip(
label: Text(item),
labelStyle: const TextStyle(
fontSize: 18,
color: Colors.black, fontWeight: FontWeight.bold),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(22.0),
),
backgroundColor: Colors.grey[300],
selectedColor: Colors.blue,
selected: selectedChoice2 == item,
onSelected: (selected) {
setState(() {
selectedChoice2 = item;
filter.add(selectedChoice2);
});
},
),
);
}).toList()
),
),
Chip(
elevation: 20,
padding: const EdgeInsets.all(8),
backgroundColor: Colors.greenAccent[100],
shadowColor: Colors.black,
label: const Text(
'Statue',
style: TextStyle(fontSize: 20),
), //Text
),
Row(
children:cubit.statue.map((item){
return Container(
padding: const EdgeInsets.all(2.0),
child: ChoiceChip(
label: Text(item),
labelStyle: const TextStyle(
color: Colors.black, fontWeight: FontWeight.bold),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(22.0),
),
backgroundColor: Colors.grey[300],
selectedColor: Colors.blue,
selected: selectedChoice3 == item,
onSelected: (selected) {
setState(() {
selectedChoice3 = item;
filter.add(selectedChoice3);
});
},
),
);
}).toList()
),
SizedBox(height: 4,),
InkWell(
onTap: (){
// here i want to apply changes
Navigator.pop(context);
},
child: Chip(
elevation: 20,
padding: const EdgeInsets.all(8),
backgroundColor: Colors.greenAccent[100],
shadowColor: Colors.black,
label: const Text(
'apply',
style: TextStyle(fontSize: 20),
), //Text
),
),
],
);
},
);
}
}
I have two main functions, the first one get all characters to the home screen:
List<Characters>?
getAllCharacters(){
myRepository.
getAllCharacters().then(
(allCharacters)=>
this.allCharacters =
allCharacters;
);
return allCharacters;
}
and the second function that takes a parameter of List of Strings which i suppose to get them from the filtering in bottomSheet;
List<Characters>?
getFilteredCharacters
(List<String> list){
myRepository
.getFilteredCharacters(list)
.then((filteredCharacters)=>
this.filteredCharacters =
filteredCharacters;
);
return filteredCharacters;
}
Anyone could help me in this issue?
I pull some variables in Firebase and I create a widget list with these variables. I want to control widget visibility when I click a widget. When I use the Visibility widget and set "visible: widgetVisibility" value, all widgets are changed at the same time. I only want the widget I clicked to change. How can I do that?
body: StreamBuilder<QuerySnapshot>(
stream: _keyService.getKeys(),
builder: (context, snapshot) {
return !snapshot.hasData
? const Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot mypost = snapshot.data!.docs[index];
return Padding(
padding: EdgeInsets.all(size * 0.3),
child: InkWell(
onTap: () {
valueVisible = !valueVisible;
},
child: Container(
decoration: BoxDecoration(
color: ColorItems.mainColor,
border: Border.all(width: 5, color: Colors.grey),
borderRadius: BorderRadius.all(Radius.circular(20))),
child: Padding(
padding: EdgeInsets.all(size),
child: Container(
child: Row(
children: [
Expanded(
child: Text(
"${mypost['key']}",
style: const TextStyle(
color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold),
),
),
const Text(
": ",
style:
TextStyle(color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(
width: 20,
),
Expanded(
child: Visibility(
visible: valueVisible,
child: Text(
"${mypost['value']}",
style: const TextStyle(
color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold),
),
))
],
),
),
),
),
),
);
},
);
})
Additionally, screenshots is here..
This might not be the optimal solution, but I always create a List for that purpose:
instead of one valueVisible bool I create a List and add a bool for each item in the list.
...itemBuilder: (context, index) { valueVisibleList.add(true)...
and in the button I then use the current item index to change only the corresponding bool
onTap: () { setState(({
valueVisibleList[index] = !valueVisibleList[index];
})
},
Just use a Map<String, bool> where the keys are the post's key and the value its visibility. The visibility should default to true if the key is not present. And the state should only change inside a setState function.
It would be something like the following (Check out the live demo on DartPad):
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 MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
final posts = [
for (var i = 0; i < 100; i++) {'key': 'key$i', 'value': '$i'}
];
class _MyHomePageState extends State<MyHomePage> {
final valueVisible = <String, bool>{};
#override
Widget build(BuildContext context) {
const size = 16.0;
return Scaffold(
body: ListView.builder(
itemCount: posts.length,
itemBuilder: (context, index) {
final mypost = posts[index];
return Padding(
padding: const EdgeInsets.all(size * 0.3),
child: InkWell(
onTap: () {
setState(() {
valueVisible[mypost['key']!] =
!(valueVisible[mypost['key']!] ?? true);
});
},
child: Container(
decoration: BoxDecoration(
color: const Color(0xffff9400),
border: Border.all(width: 5, color: Colors.grey),
borderRadius: const BorderRadius.all(Radius.circular(20))),
child: Padding(
padding: const EdgeInsets.all(size),
child: Row(
children: [
Expanded(
child: Text(
"${mypost['key']}",
style: const TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.bold),
),
),
const Text(
": ",
style: TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.bold),
),
const SizedBox(
width: 20,
),
Expanded(
child: Visibility(
visible: valueVisible[mypost['key']!] ?? true,
child: Text(
"${mypost['value']}",
style: const TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.bold),
),
),
)
],
),
),
),
),
);
},
),
);
}
}
I am trying to get data from my api and display it using Card widget .I want to align everything in an even manner without using a table. I have a written a code for it. But still there are a few rows which are not aligned properly.
Please write a detailed answer
Here is my table:
Here is my code:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:http/http.dart';
import 'Posts.dart';
late List<Post> drivers;
class MyApp extends StatefulWidget {
// to set the root of app.
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.green,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
late final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Center(
child: const Text("Driver Table",
style: TextStyle(
fontWeight: FontWeight.w900,
),
),
),
),
body: Container(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children:[
Expanded(
child: Container(
height: 70,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey,
),
borderRadius: const BorderRadius.all(Radius.circular(20))
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: const [
Text('Did',
style: TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.w900
),
),
Text('Dname',style: TextStyle(
fontSize: 24,
color: Colors.white,
fontWeight: FontWeight.w900
),),
Text('Age',style: TextStyle(
fontSize: 24,
color: Colors.white,
fontWeight: FontWeight.w900
),),
],
),
),
),
]
),
Expanded(
child: Container(
child:_buildBody(context),
),
)
],
),
color:const Color(0xFF303030),
),
//
);
}
// build list view & manage states
FutureBuilder<List<Post>> _buildBody(BuildContext context) {
final HttpService httpService = HttpService();
return FutureBuilder<List<Post>>(
future: httpService.getPosts(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
final List<Post>? posts = snapshot.data; //marked
return _buildPosts(context, posts!);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
);
}
// build list view & its tile
ListView _buildPosts(BuildContext context, List<Post> posts) {
Row(
children: [
Container(
child: const Text('Did',
style: TextStyle(
color: Colors.white,
),
),
),
Container(
child: const Text('Dname',style: TextStyle(
color: Colors.white,
),),
),
Container(
child: const Text('Age',style: TextStyle(
color: Colors.white,
),),
),
],
);
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: posts.length,
padding: const EdgeInsets.all(20),
itemBuilder: (context, index) {
return Container(
height:70,
child: Card(
shadowColor: Colors.white,
color:const Color(0xFF303030),
elevation: 1,
child: IntrinsicHeight(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(posts[index].Did,style: const TextStyle(fontWeight: FontWeight.bold,
color:Colors.white,),),
Text(posts[index].Dname,style: const TextStyle(fontWeight: FontWeight.bold,
color:Colors.white,),),
Text(posts[index].Age,style: const TextStyle(fontWeight: FontWeight.bold,color:Colors.white,),
),
],
),
),
),
);
},
);
}
}
class HttpService {
Future<List<Post>> getPosts() async {
Response res = await get(
Uri.parse('http://localhost/localconnect/driver_change.php'));
print(res.body);
if (res.statusCode == 200) {
List<dynamic> body = jsonDecode(res.body);
List<Post> posts = body.map(
(dynamic item) => Post.fromJson(item),
).toList();
return posts;
} else {
throw "Unable to retrieve posts.";
}
}
}
Posts.dart
import 'dart:convert';
List<Post> userFromJson(String str) => List<Post>.from(json.decode(str).map((x) => Post.fromJson(x)));
String userToJson(List<Post> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Post{
Post({
required this.Did,
required this.Dname,
required this.Age,
});
String Did;
String Dname;
String Age;
factory Post.fromJson(Map<String, dynamic> json) => Post(
Did: json["Did"],
Dname: json["Dname"],
Age: json["Age"],
);
Map<String, dynamic> toJson() => {
"Did": Did,
"Dname": Dname,
"Age": Age,
};
}
For every Text widget use
textAlign: TextAlign.center,
and on every Row Row
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
Main issue is coming from ListView.builder's
padding: const EdgeInsets.all(20), //remove this padding
Remove the padding here and no need to use IntrinsicHeight widget.
I am developing an app with a dropdown. Below is my code. I have removed the UI design code to isolate the dropdown section itself.
class ShoppingCartUIState extends State<ShoppingCartUI> {
final _formKey = GlobalKey<FormState>();
String _checkoutDropdownValue=null;
//**UI design Code Removed**//
_showCheckoutPopup() {
String date=DateTime.now().toString();
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0)), //this right here
child: Container(
height: MediaQuery.of(context).size.height/3,
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Container(
margin: EdgeInsets.all(10),
child: Text(
"What is Your Required Delivery Date?",
style: Theme.of(context).textTheme.subtitle,
),)
],
),
Row(
children: <Widget>[
IconButton(
icon: Icon(Icons.calendar_today),
color: Colors.green,
onPressed: () {
date = "111";
},
),
Text(date)
],
),
Row(
children: <Widget>[
Container(
margin: EdgeInsets.only(top:20, left:10),
child: Text(
"What is your Airport of delivery?",
style: Theme.of(context).textTheme.subtitle,
),)
],
),
Row(
children: <Widget>[
Container(
margin: EdgeInsets.only(top:5, left:10),
child: DropdownButton(
hint: Text(
"Please Select ",
style: TextStyle(
fontSize: 14,
),
),
items: <String>[
'Skinless Boneless, Full Loins',
'brown',
'silver'
].map((data) {
return DropdownMenuItem(
child: new Text(data,
style: Theme.of(context).textTheme.body1),
value: data,
);
}).toList(),
onChanged: (String newValue) {
setState(() {
_checkoutDropdownValue = newValue;
print(newValue);
});
},
value: _checkoutDropdownValue),
)
],
),
],
),
));
}
#override
void initState() {
// TODO: implement initState
super.initState();
}
}
The issue is when I change the dropdown item, the new value never get selected. The previously selected value is always displayed. However since i am using a print when dropdown is done, I can see the item has changed.
How can I solved this issue?
Wrap your Dialog widget with StatefulBuilder to rebuild the dialog.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyPage(), //TODO: Add Scaffold
);
}
}
class MyPage extends StatefulWidget {
#override
_MyPageState createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> {
String date = "";
String _checkoutDropdownValue;
_showCheckoutPopup() {
return StatefulBuilder(
builder: (context, setState){
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
), //this r// ight here
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
margin: EdgeInsets.all(10),
alignment: Alignment.centerLeft,
child: Text(
"What is Your Required Delivery Date?",
style: Theme.of(context).textTheme.subtitle,
),
),
Row(
children: <Widget>[
IconButton(
icon: Icon(Icons.calendar_today),
color: Colors.green,
onPressed: () {
setState(() {
date = "111";
});
},
),
Text(date)
],
),
Container(
margin: EdgeInsets.only(top: 20, left: 10),
alignment: Alignment.centerLeft,
child: Text(
"What is your Airport of delivery?",
style: Theme.of(context).textTheme.subtitle,
),
),
Row(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 5, left: 10),
child: DropdownButton<String>(
hint: Text(
"Please Select ",
style: TextStyle(
fontSize: 14,
),
),
items: <String>[
'Skinless Boneless, Full Loins',
'brown',
'silver'
].map((data) {
return DropdownMenuItem(
child: new Text(data,
style: Theme.of(context).textTheme.body1),
value: data,
);
}).toList(),
onChanged: (String newValue) {
setState(() {
_checkoutDropdownValue = newValue;
});
},
value: _checkoutDropdownValue,
),
)
],
),
],
),
),
);
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton(
child: Text("Click Here"),
onPressed: () {
showDialog(
context: context,
builder: (context) => _showCheckoutPopup(),
);
},
),
),
);
}
}
can you change your onPressed to print(_checkoutDropdownValue); instead of print(newValue); that way we can see if there is a problem with the assignment
how to animate the added containers as soon as they appear ? ( animation of height going from 0 to containerHeight)
here is a code to illustrate my question:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Home(),
));
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
List<Widget> widgetList = [Container()];
class _HomeState extends State<Home> {
TextEditingController controller = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Animated container'),
backgroundColor: Colors.blue,
),
body: Container(
alignment: Alignment.topCenter,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Center(
child: Padding(
//shift to left
padding: const EdgeInsets.only(left: 55.0),
child: Row(
children: widgetList.toList(),
),
),
),
],
),
),
FlatButton(
child: Text(
'Add',
style: TextStyle(color: Colors.white),
),
onPressed: () {
setState(() {
add(controller.text);
});
},
color: Colors.blue,
),
FlatButton(
child: Text(
'Clear',
style: TextStyle(color: Colors.white),
),
onPressed: () {
setState(() {
widgetList.clear();
});
},
color: Colors.blue,
),
TextField(
onChanged: (text) {},
textAlign: TextAlign.center,
controller: controller,
keyboardType: TextInputType.number,
style: TextStyle(
color: Colors.white,
fontSize: 25.0,
fontWeight: FontWeight.w300),
decoration: InputDecoration(
hintStyle: TextStyle(
color: Colors.white, fontWeight: FontWeight.w300),
fillColor: Colors.blue,
filled: true,
),
),
]),
),
);
}
}
void add(String containerHeight) {
widgetList.add(Padding(
padding: const EdgeInsets.all(3.0),
child: AnimatedContainer(
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(2.0),
),
duration: Duration(milliseconds: 165),
alignment: Alignment.center,
//color: Colors.red,
height: double.parse(containerHeight),
width: 29.0,
child: Text(
containerHeight,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: containerHeight.length == 1
? 19.0
: containerHeight.length == 2
? 19.0
: containerHeight.length == 3
? 16.0
: containerHeight.length == 4 ? 14.0 : 10.0),
),
)));
}
Screenshot of the ui
You just have to put the height of the container in the text field and press 'add', then the containers will appear directly without animation,
so my question is how to animate so that the height goes from 0 to containerHeight ?
i know it works when the widget is already there and we modify it's height, but i couldn't figure out how to do in that scenario ( adding to a list and displaying it directly ).
thank you.
Try the following code. It is working.
import 'package:flutter/material.dart';
import 'dart:async';
void main() {
runApp(MaterialApp(
home: Home(),
));
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
List<Widget> widgetList = [Container()];
StreamController<String> animationStream = StreamController();
class _HomeState extends State<Home> {
TextEditingController controller = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Animated container'),
backgroundColor: Colors.blue,
),
body: Container(
alignment: Alignment.topCenter,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Center(
child: Padding(
//shift to left
padding: const EdgeInsets.only(left: 55.0),
child: Row(
children: widgetList.toList(),
),
),
),
],
),
),
FlatButton(
child: Text(
'Add',
style: TextStyle(color: Colors.white),
),
onPressed: () {
animationStream = StreamController();
setState(() {
add("0");
animationStream.sink.add(controller.text);
});
},
color: Colors.blue,
),
FlatButton(
child: Text(
'Clear',
style: TextStyle(color: Colors.white),
),
onPressed: () {
setState(() {
widgetList.clear();
});
},
color: Colors.blue,
),
TextField(
onChanged: (text) {},
textAlign: TextAlign.center,
controller: controller,
keyboardType: TextInputType.number,
style: TextStyle(
color: Colors.white,
fontSize: 25.0,
fontWeight: FontWeight.w300),
decoration: InputDecoration(
hintStyle: TextStyle(
color: Colors.white, fontWeight: FontWeight.w300),
fillColor: Colors.blue,
filled: true,
),
),
]),
),
);
}
}
void add(String containerHeight) {
widgetList.add(new MyWidget());
}
class MyWidget extends StatelessWidget {
const MyWidget({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: animationStream.stream,
builder: (context, snapshot) {
String _hight = "0";
if (snapshot.hasData ) {
_hight = snapshot.data;
try { double.parse(_hight);} catch (e) { print('please enter a valid hight');_hight="0"; }
}
return Padding(
padding: const EdgeInsets.all(3.0),
child: AnimatedContainer(
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(2.0),
),
duration: Duration(milliseconds: 2165),
alignment: Alignment.center,
//color: Colors.red,
height: double.parse(_hight),
width: 29.0,
child: Text(
_hight,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: _hight.length == 1
? 19.0
: _hight.length == 2
? 19.0
: _hight.length == 3
? 16.0
: _hight.length == 4 ? 14.0 : 10.0),
),
));
},
);
}
}