Related
I am trying to expand widget inside of Column widget but not able to make it expended.
When giving constant height to parent widget, the layout will be rendered as expected. But as I remove the constant height layout is not as expected as I want to make Listview with it and I should not give a constant height to the widget which will be used as listview item.
Below is my layout code.
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
title: 'layout test',
home: Layout_test_class(),
));
}
class Layout_test_class extends StatelessWidget {
Widget cell() {
return Container(
color: Colors.yellow,
// height: 200, after un commenting this will work. but i want to make it without this
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Container(
color: Colors.green,
child: Text('apple z'),
),
),
Container(
color: Colors.red,
child:Text('apple 2'),
)
],
),
),
Column(
children: <Widget>[
Container(
color: Colors.black,
width: 200,
height: 200,
),
],
),
],
),
);
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('title'),
),
body: Center(
child: ListView(
children: <Widget>[
cell(),
],
)
),
);
}
}
Below is my expected output screenshot.
Try to wrap your Container with IntrinsicHeight
return IntrinsicHeight(
Container(
color: Colors.yellow
child: ...
)
)
Your ListView needs to be inside Flexible. Flexible inside Column will set maximum height available to ListView. ListView needs a finite height from parent, Flexible will provide that based on max. space available.
Column(
children: <Widget>[
Flexible(
child: ListView.builder(...)
),
Container(
color: Colors.red,
child:Text('apple 2'),
),
],
)
A nice way of doing this, it's to play with the MediaQuery, heigth and width.
Let me explain, if you want the widget to have the maximum heigth of a decide screen, you can set it like this:
Container(
height: MediaQuery.of(context).size.height // Full screen size
)
You can manipulate it by dividing by 2, 3, 400, the value you want.
The same things works for the width
Container(
width: MediaQuery.of(context).size.width // Can divide by any value you want here
)
Actually quite the opposite, if you're planning to use this as an item in a listViewyou can't let infinite size on the same axis your listView is scrolling.
Let me explain:
Currently you're not defining any height on your cell() widget, which is fine if you're using it alone. like this :
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
title: 'layout test',
home: Layout_test_class(),
));
}
class Layout_test_class extends StatelessWidget {
Widget cell() {
return Container(
color: Colors.yellow,
//height: 250, after un commenting this will work. but i want to make it without this
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Container(
color: Colors.green,
child: Text('apple z'),
),
),
Container(
color: Colors.red,
child: Text('apple 2'),
)
],
),
),
Column(
children: <Widget>[
Container(
color: Colors.black,
width: 200,
height: 200,
),
],
),
],
),
);
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('title'),
),
body: cell(),
);
}
}
But using it with a listView you have to define a height. A listView scrolls as long as it have some content to scroll. Right now it just like you're giving it infinite content so it would scroll indefinitely. Instead Flutter is not constructing it.
It's actually quite ok to define a global size for your container (as an item). You can even define a specific size for each using a parameter like this :
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
title: 'layout test',
home: Layout_test_class(),
));
}
class Layout_test_class extends StatelessWidget {
Widget cell(double height) {
return Container(
color: Colors.yellow,
height: height, //after un commenting this will work. but i want to make it without this
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Container(
color: Colors.green,
child: Text('apple z'),
),
),
Container(
color: Colors.red,
child: Text('apple 2'),
)
],
),
),
Column(
children: <Widget>[
Container(
color: Colors.black,
width: 200,
height: 200,
),
],
),
],
),
);
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('title'),
),
body: ListView(
children: <Widget>[
cell(250.0),
cell(230.0),
cell(300.0),
],
)
);
}
}
I'm trying to create a card with a text within a container but I would like to show only a part of the text and when the user click on "show more", show the rest. I saw a Widget to construct text like this here, but I need expand the card container either and I don't know how to do that because I need to know how many lines the text have to expand with the correctly size. Exists a way to calculate the size according the number of lines or characters?
I tried to create the card as follows, where the DescriptionText is the Widget on the link and specify a minHeight in the Container in the hope of expanding the container along with the text but did not work.
Widget _showAnswerCard(Answer answer, User user) {
return Card(
elevation: 3.0,
color: Theme.of(context).backgroundColor,
child: Container(
constraints: BoxConstraints(minHeight: 90),
padding: EdgeInsets.all(10.0),
child: Flex(
direction: Axis.horizontal,
children: <Widget>[
Expanded(flex: 1, child: _showUserAvatar(answer)),
Expanded(flex: 3, child: _showAnswerDetails(answer, user)),
],
),
));
}
Widget _showAnswerDetails(Answer answer, User user) {
return Flex(
direction: Axis.vertical,
children: <Widget>[
Expanded(
flex: 3,
child: DescriptionTextWidget(text: answer.content),
),
Expanded(
flex: 1,
child: _showAnswerOptions(),
)
],
);
}
I'll really appreciate if someone could help me with that.
Just use Wrap widget to wrap your Card widget.
Based on your link for suggested answer. I did change to use Wrap widget.
Jus do copy/paste below code and check.
import 'package:flutter/material.dart';
class ProductDetailPage extends StatelessWidget {
final String description =
"Flutter is Google’s mobile UI framework for crafting high-quality native interfaces on iOS and Android in record time. Flutter works with existing code, is used by developers and organizations around the world, and is free and open source.";
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: const Text("Demo App"),
),
body: new Container(
child: new DescriptionTextWidget(text: description),
),
);
}
}
class DescriptionTextWidget extends StatefulWidget {
final String text;
DescriptionTextWidget({#required this.text});
#override
_DescriptionTextWidgetState createState() =>
new _DescriptionTextWidgetState();
}
class _DescriptionTextWidgetState extends State<DescriptionTextWidget> {
bool flag = true;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Wrap(
children: <Widget>[
Card(
margin: EdgeInsets.all(8),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
child: Column(
children: <Widget>[
Container(
child: Text(
widget.text,
overflow: flag ? TextOverflow.ellipsis : null,
style: TextStyle(
fontSize: 15,
),
),
),
InkWell(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text(
flag ? "show more" : "show less",
style: new TextStyle(color: Colors.blue),
),
],
),
onTap: () {
setState(() {
flag = !flag;
});
},
),
],
)),
),
],
);
}
}
Result:
The solution I can think of is to use two labels, one for displaying only one line of text and one for displaying all the text. When the button is clicked, the two labels are alternately displayed in an animated manner. There is no computer at the moment, it is not convenient to verify, I hope to give you some help in the implementation of the program.
I am trying to set an image in the center of Column, and the Text at the bottom of the image, by wrapping Image and Text in the Column widget and placing it in the Center widget.
Unfortunately, it centers the Column and makes Image to be above the center of the screen.
How can I solve it?
My current code:
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: Theme.of(context).primaryColor),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset(ImagePaths.newLogoLogin),
Text(Strings.beALocal)
],
),
),
);
}
This can be achieved using the Expanded widget:
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: Theme.of(context).primaryColor),
child: Column(
children: [
Spacer(),
Image.asset(ImagePaths.newLogoLogin),
Expanded(
Column(
children: [ Text(Strings.beALocal) ],
mainAxisAlignment: MainAxisAlignment.start
)
)
],
),
);
}
You could use a Stack with a Positioned Text widget inside it.
Full example:
void main() => runApp(App());
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("Test")),
body: Stack(children: [Placeholder(), Test()]),
),
);
}
}
class Test extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: Stack(
alignment: AlignmentDirectional.bottomCenter,
overflow: Overflow.visible,
children: <Widget>[
Container(
width: 150,
height: 150,
color: Colors.blue,
),
Positioned(child: Text("Some text"), bottom: -25),
],
),
);
}
}
you can use widget SafaArea or calc size of the appbar and the navigation bar, when you have this result use this for remove in height size of screen after this you can add column MainAxisAlignment.center, CrossAxisAlignment.center and add other widget in Column
I'm struggling with the ListView.
My problem is that I've a Listview inside another Listview and the second Listview items height are not always the same. I want to get rid of the itemExtent and create an automatically height for the first Listview.
What I really want to acomplish is something like this:
#override
Widget build(BuildContext context) {
return
Column(
children: <Widget>[
TextField(),
Expanded(
child: ListView.builder(
key: new Key("ditisdekeyvoordelistview"),
itemBuilder: _makeMovieList,
padding: EdgeInsets.all(0.0),
itemCount: _movies.length,
itemExtent: 300.0,
),
),
],
);
}
//FIRST LIST
Widget _makeMovieList(BuildContext context, int index) {
return Container(
child: ListTile(
contentPadding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0),
leading: Container(
child: Column(mainAxisSize: MainAxisSize.max, children: <Widget>[
Image.network(
_movies[index].movieImage,
fit: BoxFit.cover,
width: 100.0,
)
])),
title: Text(
_movies[index].movieTitle,
),
subtitle: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_makeStarRating(_movies[index].movieRating),
Text(_movies[index].movieDescription),
_makeCardDates(index)
],
),
),
);
}
//SECOND LIST
Widget _makeCardDates(int index) {
return Expanded(
child: ListView.builder(
physics: const NeverScrollableScrollPhysics(),
padding: EdgeInsets.all(0.0),
itemCount: _movies[index].dateTimeList.length,
itemBuilder: (context, indexx) {
return GestureDetector(
onTap: () {
print(_movies[index].dateTimeList[indexx].toString());
},
child: Card(
elevation: 8.0,
color: Color.fromRGBO(64, 75, 96, .9),
child: Column(
children: <Widget>[
Text(_movies[index].cinema),
Text(((dateFormatMovieHours
.format(_movies[index].dateTimeList[indexx]))
.toString())),
],
)));
},
itemExtent: 40.0,
),
);
}
Using itemExtent on a ListView isn't required, though ListView needs to have a finite height set for vertical scroll (default) and finite width is needed for horizontal scroll. Otherwise, the ListView will throw a "constraints are unbounded" error.
For your use case, you can either set height on the list items in the first ListView, or set height on the second ListView. However, if you'd like the second ListView to be non-scrollable and the list items in the first ListView will adapt dynamically, you can use a Column of Widgets similar to this sample.
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: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final items = [
'Apple',
'Banana',
'Carrot',
'Dog',
'Egg',
'Flower',
'Goat',
'Honey'
];
final subItems = ['1.00', '2.00', '3.00', '4.00'];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: firstList(),
),
);
}
firstList() {
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.all(8.0),
child: Card(
child: Container(
color: Colors.lightBlue[50],
padding: EdgeInsets.all(16.0),
child: Row(
children: [
Expanded(
flex: 2,
child: Text('${items[index]}'),
),
Expanded(
flex: 1,
child: secondList(subItems),
),
],
),
),
),
);
},
);
}
secondList(List item) {
// Create List<Widget> for the second "List"
var subList = List<Widget>();
item.forEach((data) {
subList.add(
Card(
child: Container(
padding: EdgeInsets.all(16.0),
color: Colors.lightBlueAccent,
child: Text('$data'),
),
),
);
});
// Populate Column instead of ListView
return Column(
children: subList,
);
}
}
Is it possible to make the FloatingActionButton in the centre instead of the right side?
import 'package:flutter/material.dart';
import 'number.dart';
import 'keyboard.dart';
class ContaPage extends StatelessWidget {
#override
Widget build(BuildContext context) => new Scaffold(
body: new Column(
children: <Widget>[
new Number(),
new Keyboard(),
],
),
floatingActionButton: new FloatingActionButton(
elevation: 0.0,
child: new Icon(Icons.check),
backgroundColor: new Color(0xFFE57373),
onPressed: (){}
)
);
}
I don't know if this was added since this question was first answered, but there's now floatingActionButtonLocation property on the Scaffold class.
It would work like this in your original question:
class ContaPage extends StatelessWidget {
#override
Widget build(BuildContext context) => new Scaffold(
// ...
floatingActionButton: new FloatingActionButton(
// ...FloatingActionButton properties...
),
// Here's the new attribute:
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
Also see the documentation:
Scaffold class (search floatingActionButtonLocation): https://docs.flutter.dev/flutter/material/Scaffold-class.html
...and the FloatingActionButtonLocation class: https://docs.flutter.dev/flutter/material/FloatingActionButtonLocation-class.html
With the new flutter API you do that very easily just change the floatingActionButtonLocation property in the Scaffold to
FloatingActionButtonLocation.centerFloat
Example :
return new Scaffold(
floatingActionButton: new FloatingActionButton(
child: const Icon(Icons.add),
),
floatingActionButtonLocation:
FloatingActionButtonLocation.centerFloat,
bottomNavigationBar: new BottomAppBar(
color: Colors.white,
child: new Row(...),
),
);
Use the Property floatingActionButtonLocation of scaffold class.
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
Full Example:
import 'package:flutter/material.dart';
final 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: HomePage()
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(child: Center(child: Text('Hello World')),),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.camera, color: Colors.white, size: 29,),
backgroundColor: Colors.black,
tooltip: 'Capture Picture',
elevation: 5,
splashColor: Colors.grey,
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
}
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
Use this property with floatingActionButtonLocation property in Scaffold.
FloatingActionButton Flutter - More Details
Try wrapping it in a Center widget or use a crossAxisAlignment of CrossAxisAlignment.center on your Column.
You should pick one part of your Column to be wrapped in a Flexible that will collapse to avoid overflow, or replace some or all of it with a ListView so users can scroll to see the parts that are hidden.
You can use Container and Align widgets as below:
#override
Widget build(BuildContext context) {
return new Scaffold(
body: Center(
),
floatingActionButton: Container(
padding: EdgeInsets.only(bottom: 100.0),
child: Align(
alignment: Alignment.bottomCenter,
child: FloatingActionButton.extended(
onPressed: _getPhoneAuthResult,
icon: Icon(Icons.phone_android),
label: Text("Authenticate using Phone"),
),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
Align(
alignment: Alignment.center,
child: Container(
child: FloatingActionButton(
hoverColor: Colors.black,
elevation: 10,
onPressed: () {},
backgroundColor: Colors.pink,
child: Icon(Icons.add,),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0))),
),
),
),
Here I used "Align" widget to make the FloatingActionButton center. You can see it here.
after end of the floating action button widget, you can Use floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
For Example
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
File _image;
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark(),
title: "Camera App",
home: Scaffold(
appBar: AppBar(
title: Text("Camera App"),
),
body: Center(
child: Center(
child: _image == null
? Text('No image selected.')
: Image.file(_image,
alignment: Alignment.topLeft,
),
),
),
floatingActionButton: FloatingActionButton(
elevation: 50,
hoverColor: Colors.red,
autofocus: true,
onPressed: () {
imagepicker();
},
child: Icon(Icons.camera_alt),
tooltip: 'Pick Image',
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
),
);
}
Future imagepicker() async {
var image = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
_image = image;
});
}
}
The above examples are great, but if you want to have full control over the exact location of the floating action button, you should wrap your FloatingActionButton widget with Align widget and use Alignment(x axis, y axis) to set the exact location.
Align(
alignment: Alignment(0.0, 0.8),
//control the location by changing the numbers here to anything between 1 and -1
child: FloatingActionButton()
)
By changing the logic to use crossAxisAlignment, the mainAxisAlignment and the Flexible the FloatingActionButton were centered at the bottom of the screen
import 'package:flutter/material.dart';
import 'number.dart';
import 'keyboard.dart';
class ContaPage extends StatelessWidget {
#override
Widget build(BuildContext context) => new Scaffold(
body: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Number(),
new Keyboard(),
new Flexible(
child: new Container(
padding: new EdgeInsets.only(bottom: 16.0),
child: new FloatingActionButton(
elevation: 0.0,
child: new Icon(Icons.check),
backgroundColor: new Color(0xFFE57373),
onPressed: (){}
)
)
)
],
),
);
}
For more freedom of alignment and more than 2 FAB use Stack
Stack(
children: <Widget>[
Center(
child: Center(
child: _image == null
? Text('No image selected.')
: Image.file(_image,
alignment: Alignment.topLeft,
),
),
),
Align(
alignment: Alignment.centerLeft,
child: new FloatingActionButton(
child: const Icon(Icons.skip_previous),
onPressed: () {
}),
),
Align(
alignment: Alignment.centerRight,
child: new FloatingActionButton(
child: const Icon(Icons.skip_next),
onPressed: () {
}),
),
],
)
I modified the code, now the button is in the bottom center but I do not know if it will always stay in the bottom, regardless of the size of the screen.
import 'package:flutter/material.dart';
import 'number.dart';
import 'keyboard.dart';
class ContaPage extends StatelessWidget {
#override
Widget build(BuildContext context) => new Scaffold(
body: new Column(
children: <Widget>[
new Number(),
new Keyboard(),
new Stack(
alignment: new FractionalOffset(0.5, 1.0),
children: <Widget>[
new FloatingActionButton(
elevation: 0.0,
child: new Icon(Icons.check),
backgroundColor: new Color(0xFFE57373),
onPressed: (){}
)
],
)
],
),
);
}
Since Scaffold.floatingActionButton just asks for a Widget, you can wrap your FloatingActionButton with the standard classes for more control if the Scaffold.floatingActionButtonLocation property isn't enough (which already gives you many standard placements, that can also play nicely with your appBar or bottomNavigationBar).
Container is a classic component, but a little overkill given that it combines a variety of widgets.
As others mentioned, Align is handy when you want to position relative to the Align widget itself (which if unconstrained fills to its parent). It can take a variety of preset Alignment constants, or use the Alignment constructor to specify your own relative position, e.g. Alignment(0.0, 0.0) represents the center of the rectangle, (1,1) the bottom right corner, and (-1,-1) the upper left. However, the parent of your FAB is influenced by the Scaffold's floatingActionButtonLocation:, so one way to help take it into account is by setting it to FloatingActionButtonLocation.centerDocked, which when used with Align lets you think about positioning relative to the screen's center.
But maybe you like the basic positioning provided by floatingActionButtonLocation, but just want to shift the FAB by a known number of logical pixels, e.g. to compensate for other widgets on the screen. In that case wrapping in a Padding with the appropriate EdgeInsets should work fine.
Depending on your design simply you can use persistentFooterButtons which accepts a list of widgets as children.
just like here for an example:
persistentFooterButtons: [
new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
child: Align(
alignment: Alignment.center,
child: FloatingActionButton(
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) => InstallationPage()),);
},
child: new Icon(Icons.add, color: SysColors.ICON_COLOR, size: 34.w,),
),
),
],
)
],