Related
I want to pass data from alert dialog.Alert dialog contains textfield,so whatever the user type on the textfield that text should pass to the main page (screen).Below is the code of the alert dialog
Padding(
padding: const EdgeInsets.only(left: 42.0),
child: Align(
alignment: Alignment.topCenter,
child: RaisedButton(onPressed: (){
_showDialog();
},
),
),
Padding(
padding: const EdgeInsets.only(top: 50.0),
child: new Text('// Displays text'););
void _showDialog() {
showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return AlertDialog(
title: new Text("Alert Dialog title"),
content: TextField(
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: 'Enter the number'
),
)
,
actions: <Widget>[
// usually buttons at the bottom of the dialog
Row(
children: <Widget>[
new FlatButton(
child: new Text("Cancel"),
onPressed: () {
Navigator.of(context).pop();
},
),
new FlatButton(onPressed: (){
}, child: new Text("OK"))
],
),
],
);
},
);
}
Edit new solution:
// write this in your main page
String onMainPageText;
you can display like this in on your main page! after clicking the okey in your _showdialog method Text(onMainPageText)
change your _showDialog method with the following code.
void _showDialog() {
String dialogText;
showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return AlertDialog(
title: new Text("Alert Dialog title"),
content: TextField(
onChanged: (String textTyped) {
setState(() {
dialogText = textTyped;
});
},
keyboardType: TextInputType.number,
decoration: InputDecoration(hintText: 'Enter the number'),
),
actions: <Widget>[
// usually buttons at the bottom of the dialog
Row(
children: <Widget>[
new FlatButton(
child: new Text("Cancel"),
onPressed: () {
setState(() {
onMainPageText = '';
});
Navigator.of(context).pop();
},
),
new FlatButton(
onPressed: () {
setState(() {
onMainPageText = dialogText;
});
Navigator.of(context).pop();
},
child: new Text("OK"))
],
),
],
);
},
);
}
Old answer:
create a global TextEditingController will handle your problem you can access the text field text with textEditingConroller.text
dont forget to define textEditingController inside your class
class YourMainPageState extends State<YourMainPage>{
TextEditingController textEditingController = new TextEditingController();
}
void _showDialog() {
showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return AlertDialog(
title: new Text("Alert Dialog title"),
content: TextField(
controller: textEditingController,
keyboardType: TextInputType.number,
decoration: InputDecoration(hintText: 'Enter the number'),
),
actions: <Widget>[
// usually buttons at the bottom of the dialog
Row(
children: <Widget>[
new FlatButton(
child: new Text("Cancel"),
onPressed: () {
Navigator.of(context).pop();
},
),
new FlatButton(onPressed: () {print(textEditingController.text);}, child: new Text("OK"))
],
),
],
);
},
);
}
You can display typed text with that code :
Padding(
padding: const EdgeInsets.only(top: 50.0),
child: new Text(texEditingController.text););
The textfield has a parameter called onChanged: you can use that to pass a function
TextField(
keyboardType: TextInputType.number,
onChange: onChange
decoration: InputDecoration(
hintText: 'Enter the number'
),
)
in your main screen use this:
void onChange(String text) {
//do stuff here with text like maybe setState
}
here in below code i have list of widgets and used in listview iam adding widgets with list.add()in setstate also the list not updating i dont know what's happening . why my list is not updating
Here is below code
class EditorPageState extends State<EditorPage> {
List<Widget> obj = List<Widget>();
GlobalKey formkey= GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
obj.add( TextFormField(
textCapitalization: TextCapitalization.sentences,
maxLength: 50,
decoration: InputDecoration(
labelText: "TITLE",
hintText: "UR ARTICLE NAME"
),
));
obj.add(TextFormField(decoration: InputDecoration(
labelText: "Article's Propic",
hintText: "Only image Url is Accepted"
),));
return Scaffold(
appBar: AppBar(title: Text("data"),),
body: Form(
key: formkey,
child:Stack(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 50),
child: ListView(
shrinkWrap: true,
children: obj
),
),
Container(
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
SizedBox(),
Container(
alignment: Alignment.bottomCenter,
height: 50,width: MediaQuery.of(context).size.width,
color: Colors.black38,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(icon: Icon(Icons.format_bold),color: Colors.white,onPressed: (){
setState(() {
obj.add(TextFormField(
style: TextStyle(fontWeight: FontWeight.bold),
decoration: InputDecoration(
labelText: "heading"
),
));
});
},),
IconButton(icon: Icon(Icons.add),
onPressed: (){
setState(() {
obj.add(TextFormField(
style: TextStyle(fontWeight: FontWeight.bold),
decoration: InputDecoration(
labelText: "Start again here"
),
));
});
}
),
IconButton(icon: Icon(Icons.add_a_photo),
onPressed: (){
}
),
IconButton(icon: Icon(Icons.delete),
onPressed: (){
},
)
],
),
),
],
),
),
],
),
),
);
}
}
the above code is of statefulwidget ad it is fullscreen dialog
thats it can i know why my list is not updated
Well you will need implement a ListViewBuilder to do this and please, split your layout creation your build method isn't readable. I make some changes in your layout to be more readable and the source code has some comments to help you get what I changed. I hope it can help and also you can adapt this code to your needs.
class EditorPageState extends State<EditorPage> {
List<Widget> obj = List<Widget>();
GlobalKey formkey= GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
obj.add( TextFormField(
textCapitalization: TextCapitalization.sentences,
maxLength: 50,
decoration: InputDecoration(
labelText: "TITLE",
hintText: "UR ARTICLE NAME"
),
));
obj.add(TextFormField(decoration: InputDecoration(
labelText: "Article's Propic",
hintText: "Only image Url is Accepted"
),));
return Scaffold(
appBar: AppBar(title: Text("data"),),
//you can use this property to easily create a bottom navigation
bottomNavigationBar: _buildBottomNavigator(), // this method return BottomNavigation layout
body: Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Form(
key: formkey,
/// here your question answer... you need implemet a listView builder
/// in every build this will create a new ListView getting itens of a especific list
child : ListView.builder(
itemCount: obj.length, // number of items in your list
//here the implementation of itemBuilder. take a look at flutter docs to see details
itemBuilder: (BuildContext context, int Itemindex){
return obj[Itemindex]; // return your widget
}),
),
),
);
}
//create your bottom navigation layout
Widget _buildBottomNavigator(){
return Container(
color: Colors.black54,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(icon: Icon(Icons.format_bold),color: Colors.white,onPressed: (){
setState(() {
obj.add(TextFormField(
style: TextStyle(fontWeight: FontWeight.bold),
decoration: InputDecoration(
labelText: "heading"
),
));
});
},),
IconButton(icon: Icon(Icons.add),
onPressed: (){
print("on pressed");
setState(() {
obj.add( TextFormField(
style: TextStyle(fontWeight: FontWeight.bold),
decoration: InputDecoration(
labelText: "Start again here"
),
));
});
}
),
IconButton(icon: Icon(Icons.add_a_photo),
onPressed: (){
}
),
IconButton(icon: Icon(Icons.delete),
onPressed: (){
},
)
],
),
);
}
I have a ListView in which I will dynamically add in some children of same type. Inside every children widget has a button. What I want to implement is, that, when user presses the button on a child widget, this child widget will be removed from the ListView. I can do this in C# using events, but I'm a total noob to Dart and Flutter.
Here is my ListView
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('Edit Plan'),
backgroundColor: Colors.green,
actions: <Widget>[
Builder(
builder: (context) => IconButton(
icon: Icon(Icons.add),
onPressed: () {
setState(() {
txts.add('set');
});
},
),
)
],
),
backgroundColor: Colors.white,
body: ListView(
children: txts.map((string) =>
new ListViewItem()).toList(growable: false),
),
);
}
And here is my listViewItem:
class ListViewItem extends StatelessWidget {
final Workout workout;
ListViewItem({Key key, #required this.workout})
: assert(workout != null),
super(key: key);
#override
Widget build(BuildContext context) {
// TODO: implement build
final theme = Theme.of(context);
return Padding(
padding: EdgeInsets.all(12),
child: Card(
elevation: 12,
color: Colors.green,
child: Padding(
padding: EdgeInsets.only(top: 4, bottom: 4, left: 8, right: 8),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const ListTile(
leading: Icon(Icons.album),
title: Text(
'The Enchanted Nightingale',
style: TextStyle(color: Colors.white),
),
subtitle: Text(
'Music by Julie Gable. Lyrics by Sidney Stein.',
style: TextStyle(color: Colors.white),
),
),
TextFormField(
decoration: InputDecoration(
labelText: 'Name your workout',
labelStyle: TextStyle(color: Colors.white)),
),
ButtonTheme.bar(
// make buttons use the appropriate styles for cards
child: ButtonBar(
children: <Widget>[
FlatButton(
child: const Text(
'DELETE',
style: TextStyle(color: Colors.white),
),
onPressed: () {},
),
],
),
),
],
),
)),
);
}
}
I edited your code to use a ListView.builder, you need to remove the item at index from the List (txts) you are using, your code will be as follows:
List<String> txts = List();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Edit Plan'),
backgroundColor: Colors.green,
actions: <Widget>[
Builder(
builder: (context) =>
IconButton(
icon: Icon(Icons.add),
onPressed: () {
setState(() {
txts.add('set');
});
},
),
)
],
),
backgroundColor: Colors.white,
body: new ListView.builder(
itemCount: txts.length,
itemBuilder: (BuildContext context, int index) {
return ListViewItem(
workout: workout,
onDelete: (){
setState(() {
txts.removeAt(index);
});
},
);
},
),
);
}
in addition to that you need to add an ondelete callback in the ListViewItem, the code in the ListViewItem class will be as follows:
class ListViewItem extends StatelessWidget {
final Workout workout;
final VoidCallback onDelete;
ListViewItem({Key key, #required this.workout, this.onDelete})
: assert(workout != null),
super(key: key);
#override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Padding(
padding: EdgeInsets.all(12),
child: Card(
elevation: 12,
color: Colors.green,
child: Padding(
padding: EdgeInsets.only(top: 4, bottom: 4, left: 8, right: 8),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const ListTile(
leading: Icon(Icons.album),
title: Text(
'The Enchanted Nightingale',
style: TextStyle(color: Colors.white),
),
subtitle: Text(
'Music by Julie Gable. Lyrics by Sidney Stein.',
style: TextStyle(color: Colors.white),
),
),
TextFormField(
decoration: InputDecoration(
labelText: 'Name your workout',
labelStyle: TextStyle(color: Colors.white)),
),
ButtonTheme.bar(
// make buttons use the appropriate styles for cards
child: ButtonBar(
children: <Widget>[
FlatButton(
child: const Text(
'DELETE',
style: TextStyle(color: Colors.white),
),
onPressed: () =>onDelete(),
),
],
),
),
],
),
)),
);
}
}
I am trying to create a dropdown / combobox widget and having a hard time to figure. Below is the code that I have tried. Basically creating a list that I gathered from here and there but not able to put it in my own code accordingly.
import 'package:flutter/material.dart';
class Signup extends StatefulWidget{
Signup({Key key}) : super (key:key);
final String title;
#override
SignupPage createState() => new SignupPage();
}
class SignupPage extends State<Signup> {
#override
Widget build(BuildContext context) {
List _countrycodes = ["+65","+91"];
List<DropdownMenuItem<String>> _dropDownMenuItems;
String _selectedCountryCode;
List<String> _colors = <String>['', 'red', 'green', 'blue', 'orange'];
String _color = '';
List<DropdownMenuItem<String>> getDropDownMenuItems() {
List<DropdownMenuItem<String>> items = new List();
for (String code in _countrycodes) {
items.add(new DropdownMenuItem(
value: code,
child: new Text(code)
));
}
return items;
}
/**return new Material(
color: Colors.blueAccent,
child: new Scaffold(
body: new Stack(
children: <Widget>[
new Container(
decoration: new BoxDecoration(
image: new DecorationImage(image: new AssetImage("assets/images/download.jpg"), fit: BoxFit.cover,),
),
),
new Center(
child: new Text("Hello LandingPage"),
)
],
)
));**/
final name = TextFormField(
keyboardType: TextInputType.text,
autofocus: false,
initialValue: 'Techie Quickie',
decoration: InputDecoration(
hintText: 'Name',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0)
),
),
);
final email = TextFormField(
keyboardType: TextInputType.emailAddress,
autofocus: false,
initialValue: 'tq#gmail.com',
decoration: InputDecoration(
hintText: 'Email',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0)
),
),
);
final password = TextFormField(
keyboardType: TextInputType.text,
obscureText: true,
autofocus: false,
initialValue: 'password',
decoration: InputDecoration(
hintText: 'Password',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0)
),
),
);
final passwordConfirmation = TextFormField(
keyboardType: TextInputType.text,
obscureText: true,
autofocus: false,
initialValue: 'password',
decoration: InputDecoration(
hintText: 'Password',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0)
),
),
);
final loginButton = Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: Material(
borderRadius: BorderRadius.circular(30.0),
shadowColor: Colors.lightBlueAccent.shade100,
elevation: 5.0,
child: MaterialButton(
minWidth: 200.0,
height: 42.0,
onPressed: (){
print("Signup button clicked");
},
color: Colors.lightBlueAccent,
child:
Text('Sign Up',
style: TextStyle(color: Colors.white, fontSize: 20.0),
),
),
)
);
final countryCode = DropdownButton(
value: _selectedCountryCode,
items: _dropDownMenuItems,
onChanged: null
);
final inputDecoratoring =InputDecorator(
decoration: const InputDecoration(
icon: const Icon(Icons.color_lens),
labelText: 'Color',
),
isEmpty: _color == '',
child: new DropdownButtonHideUnderline(
child: new DropdownButton<String>(
value: _color,
isDense: true,
onChanged: (String newValue) {
setState(() {
_color = newValue;
});
},
items: _colors.map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
),
),
);
return Scaffold(
backgroundColor: Colors.white,
body: Center (
child: ListView(
padding: EdgeInsets.only(left: 24.0, right: 24.0),
shrinkWrap: true,
children: <Widget>[
name,
SizedBox(height: 18.0),
email,
SizedBox(height: 18.0),
password,
SizedBox(height: 18.0),
passwordConfirmation,
SizedBox(height: 18.0),
// countryCode,
// SizedBox(height: 18.0),
loginButton,
SizedBox(height: 38.0),
],
)
)
);
}
}
This is my main.dart class
import 'package:flutter/material.dart';
import 'package:elegal_dart/screens/landing_page.dart';
import 'package:elegal_dart/screens/home.dart';
import 'package:elegal_dart/screens/devices.dart';
import 'package:elegal_dart/screens/signup.dart';
import 'package:elegal_dart/screens/signin.dart';
/*
void main()
{
Devices( new MaterialApp(
home: new Devices(),
));
}*/
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget
{
#override
Widget build(BuildContext context)
{
return new MaterialApp(
title: 'Navigation',
routes: <String, WidgetBuilder>
{
'/Home' : (BuildContext context) => new Home(),
'/LandingPage' : (BuildContext context) => new LandingPage(),
'/Devices' : (BuildContext context) => new Devices(),
'/Signup' : (BuildContext context) => new Signup(),
'/Signin' : (BuildContext context) => new Signin(),
},
//home: new Signin(onSubmit: null),
home: new Signup(),
);
}
}
UPDATED CODE:
import 'package:flutter/material.dart';
class Signup extends StatefulWidget{
Signup({Key key}) : super (key:key);
final String title;
#override
SignupPage createState() => new SignupPage();
}
class SignupPage extends State<Signup> {
#override
Widget build(BuildContext context) {
List _countrycodes = ["+65","+91"];
List<DropdownMenuItem<String>> _dropDownMenuItems;
String _selectedCountryCode;
List<String> _ccodes = <String>['', '+65', '+91', '+60', 'orange'];
String _ccode = '';
List<DropdownMenuItem<String>> getDropDownMenuItems() {
List<DropdownMenuItem<String>> items = new List();
for (String code in _countrycodes) {
items.add(new DropdownMenuItem(
value: code,
child: new Text(code)
));
}
return items;
}
final name = TextFormField(
keyboardType: TextInputType.text,
autofocus: false,
initialValue: 'Techie Quickie',
decoration: InputDecoration(
hintText: 'Name',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0)
),
),
);
final email = TextFormField(
keyboardType: TextInputType.emailAddress,
autofocus: false,
initialValue: 'tq#gmail.com',
decoration: InputDecoration(
hintText: 'Email',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0)
),
),
);
final password = TextFormField(
keyboardType: TextInputType.text,
obscureText: true,
autofocus: false,
initialValue: 'password',
decoration: InputDecoration(
hintText: 'Password',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0)
),
),
);
final passwordConfirmation = TextFormField(
keyboardType: TextInputType.text,
obscureText: true,
autofocus: false,
initialValue: 'password',
decoration: InputDecoration(
hintText: 'Password',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0)
),
),
);
final loginButton = Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: Material(
borderRadius: BorderRadius.circular(30.0),
shadowColor: Colors.lightBlueAccent.shade100,
elevation: 5.0,
child: MaterialButton(
minWidth: 200.0,
height: 42.0,
onPressed: (){
print("Signup button clicked");
},
color: Colors.lightBlueAccent,
child:
Text('Sign Up',
style: TextStyle(color: Colors.white, fontSize: 20.0),
),
),
)
);
final countryCode = DropdownButtonHideUnderline (
child: DropdownButton<String>(
value: _ccode,
isDense: true,
items: _ccodes.map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
onChanged: (String newValue) {
setState(() {
_ccode = newValue;
});
}
)
);
return Scaffold(
backgroundColor: Colors.white,
body: Center (
child: ListView(
padding: EdgeInsets.only(left: 24.0, right: 24.0),
shrinkWrap: true,
children: <Widget>[
name,
SizedBox(height: 18.0),
email,
SizedBox(height: 18.0),
password,
SizedBox(height: 18.0),
passwordConfirmation,
SizedBox(height: 18.0),
countryCode,
SizedBox(height: 18.0),
loginButton,
SizedBox(height: 38.0),
],
)
)
);
}
}
The error that I am getting in the AVD
The assertion tells you that items must not be null. It's referring to this one: items: _dropDownMenuItems,. You don't ever assign _dropDownMenuItems.
This is a good use for a Dart-y pattern. Replace it with:
final countryCode = DropdownButton(
value: _selectedCountryCode,
items: _countrycodes
.map((code) =>
new DropdownMenuItem(value: code, child: new Text(code)))
.toList(),
onChanged: null,
);
and you no longer need the field or the getDropDownMenuItems function. If you aren't familiar with this syntax, read it as "map each code in countryCodes to a DropdownMenuItem and form them back into a List"
Also, the scope of your variables is wrong. Move them out of the build function and into the State, like this:
class SignupPage extends State<Signup> {
List<String> _countrycodes = ["+65", "+91"];
List<String> _colors = ['', 'red', 'green', 'blue', 'orange'];
String _selectedCountryCode;
String _color = '';
My answer will solve also the problem of using more than one DropdownButton in the same page without the error of more than 1 item in the DropdownMenuItem .
First define the lists you will use this way:
static const List<String> _razas = const
["Schnauzer", "Ovejero Alemán", "Husky", "Brasov",
"Constanta","Mestizo"];
////////barrios
static const List<String> _barrios = const
"Belgrano", "Caballito", "Colegiales", "Lugano", "Palermo","Pilar",
"Montserrat", "Vicente López" ];
static const List<String> _tamanio = const
["Chico", "Mediano", "Grande" ];
String tamanioValue = _tamanio[0];
String barriosValue = _barrios[0];
String razasValue = _razas[0];
Then use this Containers in your Scaffold
Container(
margin: EdgeInsets.only(top:20.0, bottom: 20.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.start,
children:<Widget> [
Text("RAZA "),
new DropdownButton(value:razasValue,
onChanged: (string) => setState(() => razasValue =
string),
items: _razas.map((string) {
return new DropdownMenuItem(
child: new Text(string),
value: string,
);
}).toList(),
),
]
)
),
Container(
margin: EdgeInsets.only(top:20.0, bottom: 20.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.start,
children:<Widget> [
Text("BARRIO "),
new DropdownButton(value:barriosValue,
onChanged: (string) => setState(() =>
barriosValue = string),
items: _barrios.map((string) {
return new DropdownMenuItem(
child: new Text(string),
value: string,
);
}).toList(),
),
]
)
),
Then just replace the values for you database or any file you store the data
raza: razasValue,
barrio: barriosValue,
I am pretty new to Flutter and Dart and I can't seem to find any hints for this particular topic. I am trying to put 3 RadioListTiles in a Row like so:
Row(
children: [
Expanded(
child:RadioListTile<GoalSelection>(
title: Text(
'Net',
style: Theme.of(context).textTheme.body1,
),
value: GoalSelection.net,
groupValue: _goalSelection,
onChanged: (GoalSelection value) {
setState(() {
_goalSelection = value;
});
},
),
),
Expanded(
child: RadioListTile<GoalSelection>(
title: Text(
'Gross',
style: Theme.of(context).textTheme.body1,
),
value: GoalSelection.gross,
groupValue: _goalSelection,
onChanged: (GoalSelection value) {
setState(() {
_goalSelection = value;
});
},
),
),
Expanded(
child: RadioListTile<GoalSelection>(
title: Text(
'Salary',
style: Theme.of(context).textTheme.body1,
),
value: GoalSelection.salary,
groupValue: _goalSelection,
onChanged: (GoalSelection value) {
setState(() {
_goalSelection = value;
});
},
),
),
],
),
The buttons layout fine, but there seems to be a lot of wasted space for the label. I put a screenshot of what it currently looks like below. I have tried wrapping the Expanded, the RadioListTile, and the Text in Padding widgets (all one at a time) to manually set the padding to 0, but it didn't do anything. I have also tried to change Expanded to Flexible even though I didn't think that would change anything. I am at a loss now. Is there any way to get this layout to work? I am kind of assuming it is something really dumb that I am doing.
You can use Radio + text widget instead of RadioListTile. For removing internal padding in Radio widget set:
Radio(
visualDensity: const VisualDensity(
horizontal: VisualDensity.minimumDensity,
vertical: VisualDensity.minimumDensity),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
.....
),
You can use a Radio and Text widget in a row. But the Radio also has the same padding problem. To remove the padding you can put the Radio as a child of a SizedBox.
eg:- SizedBox(height: 20, width: 20, child: Radio(.......))
RadioListTile is used with the purpose of taking the full width in a vertical scroll list.
If you don't want this behavior, don't use it. Use Radio instead.
just set contentPadding: EdgeInsets.zero
RadioListTile(contentPadding: EdgeInsets.zero)
We can control the padding of the RadioListTile using Flexible widget. As you want to arrange 3 RadioListTiles inside a Row Widget. Please try with the below code, it will work.
Row(
children: <Widget>[
Flexible(
fit: FlexFit.loose,
child:
RadioListTile(
title: const Text('hello'),
onChanged: (value) {
setState(() {});
},
),
),
Flexible(
fit: FlexFit.loose,
child:
RadioListTile(
title: const Text('Lafayette'),
onChanged: (value) {
setState(() {});
},
),
)
],
),
Do, let me know. Once you tried with the above code. If it resolved you problem, please accept my answer as useful and provide your valuable comments.
I got the same problem. You could try to customize with Radio, Text, InkWell, Padding.
class LabeledRadio extends StatelessWidget {
const LabeledRadio({
this.label,
this.padding,
this.groupValue,
this.value,
this.onChanged,
});
final String label;
final EdgeInsets padding;
final bool groupValue;
final bool value;
final Function onChanged;
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
if (value != groupValue)
onChanged(value);
},
child: Padding(
padding: padding,
child: Row(
children: <Widget>[
Radio<bool>(
groupValue: groupValue,
value: value,
onChanged: (bool newValue) {
onChanged(newValue);
},
),
Text(label),
],
),
),
);
}
}
// ...
bool _isRadioSelected = false;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <LabeledRadio>[
LabeledRadio(
label: 'This is the first label text',
padding: const EdgeInsets.symmetric(horizontal: 5.0),
value: true,
groupValue: _isRadioSelected,
onChanged: (bool newValue) {
setState(() {
_isRadioSelected = newValue;
});
},
),
LabeledRadio(
label: 'This is the second label text',
padding: const EdgeInsets.symmetric(horizontal: 5.0),
value: false,
groupValue: _isRadioSelected,
onChanged: (bool newValue) {
setState(() {
_isRadioSelected = newValue;
});
},
),
],
),
);
}
The documentation: https://api.flutter.dev/flutter/material/RadioListTile-class.html#material.RadioListTile.3
This is how I fix the padding:
enum ContactSex { nam, nu, khac }
class CreateContactScreen extends StatefulWidget {
static const routeName = './create_contact';
#override
_CreateContactScreenState createState() => _CreateContactScreenState();
}
class _CreateContactScreenState extends State<CreateContactScreen> {
ContactSex _contaxtSex = ContactSex.nu;
final _form = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'TẠO LIÊN HỆ',
style: kHeaderTextStyle,
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('XONG', style: TextStyle(color: Colors.white),),
)
],
),
body: Container(
padding: EdgeInsets.symmetric(horizontal: 15.0, vertical: 20.0),
child: Form(
key: _form,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(
labelText: 'Tên*',
),
textInputAction: TextInputAction.next,
onFieldSubmitted: (_) {
// TODO: when submit this text field
},
validator: (value) {
if (value.isEmpty) {
return 'Hãy nhập tên cho liên hệ.';
}
return null;
},
onSaved: (value) {
// TODO : when save the whole form
},
),
TextFormField(
decoration: InputDecoration(
labelText: 'Họ',
),
textInputAction: TextInputAction.next,
onFieldSubmitted: (_) {
// TODO: when submit this text field
},
// validator: (value) {
// if (value.isEmpty) {
// return null;
// }
// return null;
// },
onSaved: (value) {
// TODO : when save the whole form
},
),
TextFormField(
decoration: InputDecoration(
labelText: 'Số điện thoại*',
),
keyboardType: TextInputType.phone,
textInputAction: TextInputAction.next,
onFieldSubmitted: (_) {
// TODO: when submit this text field
},
validator: (value) {
if (value.isEmpty) {
return 'Hãy nhập số điện thoại cho liên hệ.';
}
return null;
},
onSaved: (value) {
// TODO : when save the whole form
},
),
TextFormField(
decoration: InputDecoration(
labelText: 'Email',
),
textInputAction: TextInputAction.next,
onFieldSubmitted: (_) {
// TODO: when submit this text field
},
// validator: (value) {
// if (value.isEmpty) {
// return null;
// }
// return null;
// },
onSaved: (value) {
// TODO : when save the whole form
},
),
Container(
padding: EdgeInsets.only(top: 15.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Giới tính',
style: TextStyle(fontSize: 14.0),
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
LabeledRadio(
label: 'Nữ',
padding: EdgeInsets.all(0),
groupValue: _contaxtSex,
value: ContactSex.nu,
onChanged: (ContactSex newValue) {
setState(() {
_contaxtSex = newValue;
});
},
),LabeledRadio(
label: 'Nam',
padding: EdgeInsets.all(0),
groupValue: _contaxtSex,
value: ContactSex.nam,
onChanged: (ContactSex newValue) {
setState(() {
_contaxtSex = newValue;
});
},
),LabeledRadio(
label: 'Khác',
padding: EdgeInsets.all(0),
groupValue: _contaxtSex,
value: ContactSex.khac,
onChanged: (ContactSex newValue) {
setState(() {
_contaxtSex = newValue;
});
},
),
],
),
],
),
)
],
)),
),
),
);
}
}
class LabeledRadio extends StatelessWidget {
final String label;
final EdgeInsets padding;
final ContactSex groupValue;
final ContactSex value;
final Function onChanged;
const LabeledRadio(
{this.label, this.padding, this.groupValue, this.value, this.onChanged});
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
if (value != groupValue) {
onChanged(value);
}
},
child: Padding(
padding: padding,
child: Row(
children: <Widget>[
Radio<ContactSex>(
groupValue: groupValue,
value: value,
onChanged: (ContactSex newValue) {
onChanged(newValue);
},
),
Text(label),
],
),
),
);
}
}
You just need to set the "dense" property to true, example:
RadioListTile<String>(
title: "My radio",
dense: true, // <= here it is !
value: '1',
);
you should achieve this manually like
make a group of Radio() and Text() and wrap with InkWell() for state handling. now remove extra space of radio by materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, That's it. Get idea by sample code.
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
InkWell(
onTap: () {
setState(() {
_radioVenue = 0;
});
},
child: Row(
children: [
Radio(
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
activeColor: primaryColor,
groupValue: _radioVenue,
onChanged: (value) {},
value: 0,
),
Text('From our list')
],
),
),
InkWell(
onTap: () {
setState(() {
_radioVenue = 1;
});
},
child: Row(
children: [
Radio(
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
activeColor: primaryColor,
groupValue: _radioVenue,
onChanged: (value) {},
value: 1,
),
Text('From our list')
],
),
),
],
),
We covered both both the issues in this sample.
Removed extra spaces.
whole group is selectable radio + text, Now it behaves like RadioListTile().
Simply use RadioListTile and remove extra padding, by default it's 18
RadioListTile(contentPadding: EdgeInsets.symmetric(horizontal: 0.0)),
OR
RadioListTile(
contentPadding: EdgeInsets.symmetric(horizontal: 0.0),
value: null,
groupValue: null,
onChanged: null,
),
glad to answer
I was looking for same question and ended up on Flutter Documentation
I was working on Column and RadioListTile and I faced same issue, there's a horizontal padding between content inside RadioListTile
So, here it's the answer
Looking for this documentation ! RadioListTile content padding
Just add contentPadding: EdgeInsets.symmetric(horizontal: 0) and here you go, there's no horizontal padding anymore
Just copy paste this code and enjoy
Container(
height:35,
child: Row(
children: [
Radio(
groupValue: data.selected,
value: e,
onChanged: (DataBindModel? value) {
listener.value = MultiChoiceData(selected: value, items: listener.value.items);
onChanged(value);
onSelected(value);
},
),
Text(
e.value,
style: body14,
)
],
),
)
Copy the RadioListTile code and create your on new new file and paste it in there.
Remove the imports causing errors:
import 'package:flutter/widgets.dart'; // leave it
import 'package:flutter/material.dart'; //add
import 'list_tile.dart'; //remove
import 'radio.dart'; //remove
import 'theme.dart'; //remove
import 'theme_data.dart'; //remove
Then add the following padding to it, like this:
//Inside the file locate this widget and Add the padding or remove it. I needed to remove it and add 5.
return MergeSemantics(
child: ListTileTheme.merge(
contentPadding: EdgeInsets.only( // Add this
left: 5,
right: 0,
bottom: 0,
top: 0
),
selectedColor: activeColor ?? Theme.of(context).accentColor,
child: ListTile(
leading: leading,
title: title,
subtitle: subtitle,
trailing: trailing,
isThreeLine: isThreeLine,
dense: dense,
enabled: onChanged != null,
onTap: onChanged != null && !checked ? () { onChanged(value); } : null,
selected: selected,
),
),
);
then Import the file into your project like this:
import 'package:Project_Name/common/customComponets/custom_radio_list_tile.dart' as CustomRadioListTile;
Then use it like this:
CustomRadioListTile.RadioListTile(); // and that's how I managed to do it. Thought I should share.
This is my way of reducing the space. I have three Radio in one row.
Row(
children: [
Expanded(
child: RadioListTile(
contentPadding: EdgeInsets.all(0.0),
value: DayoffType.Range,
groupValue: _dayoffType,
title: Transform.translate(offset: const Offset(-18, 0), child: Text('Range')),
onChanged: (DayoffType? val) {
setState(() {
_dayoffType = val!;
});
},
),
),
Expanded(...Radio2...),
Expanded(...Radio3...)
)