Flutter landscape orientation layout - layout

How to set AppBar height in landscape mode so that it is not taking up for screen padding?
Is there a usual Flutter landscape layout Widget? Aforementioned problematic layout is as follow:
new Padding(
padding: media.padding,
child: new Scaffold(
key: _scaffoldKey,
body: new Row(
children: <Widget>[
new LimitedBox(
maxWidth: 320.0,
child: new Column(children: [
_buildAppBar(),
new Expanded(
child: new ModuleDrawer(
widget.module.sugar,
topPadding: 0.0,
)),
]),
),
new Expanded(
child: new RecordList(
widget.model,
),
),
],
)));

You could probably use the primary property of a Scaffold, in combination of detecting the orientation through a simple MediaQuery. So on landscape mode, set the primary flag to false to tell the Scaffold to not take status bar height into account when determining the AppBar height.
See the documentation:
Whether this scaffold is being displayed at the top of the screen.
If true then the height of the appBar will be extended by the height of the screen's status bar, i.e. the top padding for MediaQuery.
The default value of this property, like the default value of AppBar.primary, is true.
So in your case, something like this should do:
#override
Widget build(BuildContext context) {
final Orientation orientation = MediaQuery.of(context).orientation;
final bool isLandscape = orientation == Orientation.landscape;
return new Scaffold(
primary: !isLandscape,
appBar: new AppBar(
title: new Text('AppBar title'),
),
body: new Center(
child: new Text('Look at the appbar on landscape!'),
),
);
}

Related

Flutter textformfield cursor moving to front of the text

I am using a textformfield in my application. The cursor keeps moving to the left most side of the text. To solve this issue I added a listener:
final TextEditingController _controller = TextEditingController();
#override
Widget build(BuildContext context) {
_controller.text = widget.localLayoutItem.cx.toInt().toString();
_controller.addListener(() {
_controller.value = _controller.value.copyWith(
text: _controller.text,
selection: TextSelection.fromPosition(TextPosition(
offset: _controller.text.length,
)),
composing: TextRange.empty,
);
});
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
controller: _controller,
decoration: const InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.only(left: 10),
iconColor: Colors.grey,
),
onChanged: (value) {
FocusedItemModel.of(context).redraw();
widget.localLayoutItem.cx = double.parse(value);
},
),
],
);
}
The textfield value is directly connected to the widgets x-axis value so if the widget moves I need to update the textfield value as well and vice-versa.
Problem:
After adding the listener the cursor is staying on the right most but I lost functionality like using the arrow key to a desired character or deleting all characters.
how to solve this issue?
update the text editing controller like this
TextEditingController questionController = TextEditingController.fromValue(TextEditingValue(
text: somevalue,
selection: TextSelection( baseOffset: somevalue.length,
extentOffset: somevalue.length),
)

Flutter error: Column's children must not contain any null values, but a null value was found at index 0

I created an application in android studio to navigate from one screen to another.Here two stateless widgets are created as two screens and both contain a button to navigate pages each other.
However when i run the application a red screen is generated on my android phone I get an error saying
exception 'Column's children must not contain any null values, but a null value was found at index 0'.
I have provided my code below:
FIRST SCREEN
class FirstScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("First Screen"),
),
body: Container(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
center(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage('assets/new 7wonders.jpg'),
fit: BoxFit.cover,
),
),
),
Text('New 7 Wonders',
style: TextStyle(fontSize: 40, fontStyle: FontStyle.italic),
),
RaisedButton(
child: Text("Bang Here"),
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) => SecondScreen()));
},
color: Colors.red,
textColor: Colors.yellow,
padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
splashColor: Colors.grey,
)
],
),
),
),
);
}
center({BoxDecoration decoration}) {}
}
SECOND SCREEN
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Screen"),
),
body: RaisedButton(
child: Text("Go to First page"),
onPressed:() {
Navigator.pop(context);
},
),
);
}
}
Your center method should return a Widget, it is currently providing null to the Column.
Do this instead:
Widget center() {
// return a decorated box widget which gives you the decoration property
return Image(
image: AssetImage(
'assets/new 7wonders.jpg',),
fit: BoxFit.cover,
);
}
}
Then use in your Column like :
Container(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// call the center method which returns a Widget
center(),
Text(
'New 7 Wonders',
style: TextStyle(fontSize: 40, fontStyle: FontStyle.italic),
),
RaisedButton(
child: Text("Bang Here"),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => SecondScreen()));
},
color: Colors.red,
textColor: Colors.yellow,
padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
splashColor: Colors.grey,
)
],
),
),
),
you have to return any widget in center
center({BoxDecoration decoration}) {
return Container();
}
You tryed write Center instead center in line 24?
And in Center must be will return for example Containter()
In 24th line, you returned null value. You can implement the center method like this;
return Container();
Remove center use this
Container(
height: 100, // height and width according to your ui
width:100,
child:Image.asset(('assets/new7wonders.jpg',fit: BoxFit.cover,), // use for local image from asset and please change image name in code as well as in asset folder.there should not be space between image name .
),

More space between LabelText and HintText in TextFormField (Flutter)

I want to increase the distance between labelText and hintText in a TextFormField, and contentPadding: EdgeInsets.fromLTRB(x, x, x, x), doesn't help me at all, it does apply a padding but those elements remain together.
My preview:
You can do this with hintStyle and LabelStyle, set height attribute to what you want
You can see my test result in picture
code snippet
TextFormField(
decoration: const InputDecoration(
icon: Icon(Icons.person),
hintText: 'What do people call you?',
hintStyle: TextStyle(height:7, fontWeight: FontWeight.bold),
labelText: 'Name *',
labelStyle: TextStyle(height:5, fontWeight: FontWeight.bold),
),
full code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextFormField(
decoration: const InputDecoration(
icon: Icon(Icons.person),
hintText: 'What do people call you?',
hintStyle: TextStyle(height:7, fontWeight: FontWeight.bold),
labelText: 'Name *',
labelStyle: TextStyle(height:5, fontWeight: FontWeight.bold),
),
onSaved: (String value) {
// This optional block of code can be used to run
// code when the user saves the form.
},
validator: (String value) {
return value.contains('#') ? 'Do not use the # char.' : null;
},
),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Provided you are using a OutlineInputBorder, you can use textAlignVertical: TextAlignVertical.bottom, together with
decoration: InputDecoration(
contentPadding: EdgeInsets.only(top: 28),
border: OutlineInputBorder(
)
)
Adjust the contentPadding to your desired height.
I needed a TextField just with a label and no hint. My workaround to create space between was to provide the hint as an empty string. Hope this helps took me like 20 minutes to figure out 🙄
TextField(
decoration: InputDecoration(
hintStyle: TextStyle(
height: 3.0, // sets the distance between label and input
),
hintText: '', // needed to create space between label and input
labelStyle: TextStyle(
color: kWhiteTextColor,
fontSize: 20.0,
),
labelText: 'My first name is',
),
),
TextFormField(
controller: controller.fullNameController,
focusNode: controller.fullNameFocusNode,
enabled: false,
decoration: InputDecoration(
alignLabelWithHint: true,
labelText: fullNameLabel,
hintText: fullNameLabel,
labelStyle: TextStyle(
fontSize: 18,
height: 0.5, // Tweak this 1,2 moves label bottom-> -1,-2 moves label upwards
fontWeight: FontWeight.w500,
),
floatingLabelBehavior: FloatingLabelBehavior.always),
),
Figured it out!
Don't use labelText Parameter, instead, use the label parameter, wrap your text widget with padding widget then specify the amount of padding you want between label and text form field.
Like so
label: Padding( padding: Const EdgeInsets.all(10), child:Text('your label text')

How to create a scroll view with fixed footer with Flutter?

I would like to create a view that has to have a Column with a scroll view (e.g. something like SingleChildScrollView) and a footer regardless of the screen size. If the screen is big enough, it will use the empty space between the scroll and the footer, if not, it will expand and only make the widget above the footer scrollable.
It's more or less like Listview with scrolling Footer at the bottom but with a diference that I want the keyboard to overflow the footer and it also should stay in place.
Something like
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(left: 30.0, right: 30.0, top: 80.0),
child: Form(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
// Multiple widgets and form fields
],
),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 50.0),
child: SafeArea(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
// Footer widgets
],
),
),
)
],
),
);
For those who were looking to implement just footer with scrollview in a simple way, below code might help :
Scaffold(
appBar: buildAppBar('Some cool appbar'),
body: Column(
children: [
Expanded(
child: SingleChildScrollView(
child: Column(
children: [
PackageCard(),
PackageCard(),
PackageCard(),
],
),
),
),
Container(
child: Text('Your super cool Footer'),
color: Colors.amber,
)
],
),
);
Visual representation:-
---Column
|
|---Expanded--
|-SingleChildScrollView (column /YOUR SCROLLABLE VIEW)
|
|-Container(YOUR FOOTER)
I used expanded with SinglechildScrollView over here
Even though the Rémi answer being right, I've actually found an easier way to achieve what I was looking for by just combining the LayoutBuilder with the IntrinsicHeight.
class ScrollableFooter extends StatelessWidget {
#override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: constraints.copyWith(
minHeight: constraints.maxHeight,
maxHeight: double.infinity,
),
child: IntrinsicHeight(
child: Column(
children: <Widget>[
// Your body widgets here
Expanded(
child: Align(
alignment: Alignment.bottomCenter,
child: // Your footer widget
),
),
],
),
),
),
);
});
}
}
How I solved this was to wrap the fixed Footer and The SingleChildScrollView in a Stack widget then align the Footer accordingly.
class ScrollableFooter extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
SingleChildScrollView(
child: Container(
padding: EdgeInsets.all(5),
child: Column(
children: <Widget>[
// Your body widgets here
],
),
),
),
Align(
alignment: Alignment.bottomCenter,
child: // Your fixed Footer here,
),
],
);
}
}
The accepted solution works in many cases, but it becomes tricky when you want to use something like a ListView because it can't provide an intrinsic height. I tried to find some different solution, and turns out I could, and it seems more flexible. I managed to solve this situation using slivers. Where the content is inside a sliver, and the footer is also inside a sliver.
Tip: Watch "The Boring Flutter Development Show, Ep. 12", which is all about slivers.
return Scaffold(
body: CustomScrollView(
shrinkWrap: true,
slivers: [
SliverToBoxAdapter(
child: Column(
children: [
//content widgets
],
),
),
SliverFillRemaining(
hasScrollBody: false,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
//footer widgets,
],
),
),
],
),
);
The difficulty is that Column and SingleChildScrollView have a hard time working together because one needs constraints and the other removes them.
The trick is to use a CustomMultiChildLayout and do the calculations yourself. Helped by MediaQuery to obtain the size of the keyboard, so that the footer can disappear to leave more room for the content.
Here's a reusable widget that does it for you:
class FooterLayout extends StatelessWidget {
const FooterLayout({
Key key,
#required this.body,
#required this.footer,
}) : super(key: key);
final Container body;
final Container footer;
#override
Widget build(BuildContext context) {
return CustomMultiChildLayout(
delegate: _FooterLayoutDelegate(MediaQuery.of(context).viewInsets),
children: <Widget>[
LayoutId(
id: _FooterLayout.body,
child: body,
),
LayoutId(
id: _FooterLayout.footer,
child: footer,
),
],
);
}
}
enum _FooterLayout {
footer,
body,
}
class _FooterLayoutDelegate extends MultiChildLayoutDelegate {
final EdgeInsets viewInsets;
_FooterLayoutDelegate(this.viewInsets);
#override
void performLayout(Size size) {
size = Size(size.width, size.height + viewInsets.bottom);
final footer =
layoutChild(_FooterLayout.footer, BoxConstraints.loose(size));
final bodyConstraints = BoxConstraints.tightFor(
height: size.height - max(footer.height, viewInsets.bottom),
width: size.width,
);
final body = layoutChild(_FooterLayout.body, bodyConstraints);
positionChild(_FooterLayout.body, Offset.zero);
positionChild(_FooterLayout.footer, Offset(0, body.height));
}
#override
bool shouldRelayout(MultiChildLayoutDelegate oldDelegate) {
return true;
}
}
Used as such:
FooterLayout(
body: body,
footer: footer,
),
Although the accepted answer seems to work on mobile devices, problems occur when the width is (much) bigger than the height. When that happens, the IntrinsicHeight acts like an AspectRatio, and the height increases so the footer is pushed off the screen.
I think the problem is with the definition used by the IntrinsicHeight of its internal workings:
... instead size itself to a more reasonable height.
I can confirm that #Rémi's solutions works also in those cases.
It deserves to be a standard widget provided by the Flutter framework.

OnPressed Set activeColor to a button of a list, and set inactiveColor to others btns - Flutter

I have a list of Chips, and I want them to change color when user click on them.
For instance if I click on the first Chip its color become black, and every other chips are grey. Then if I click on the second Chip its color become black and first Chip color become grey and so on.
I can't find a beautiful/simple way to do this, have you any ideas ?
Thanks a lot
Here is how you can do it:
Widget _myChip(int number, String name) {
return new Padding(
padding: const EdgeInsets.all(8.0),
child: new InkWell(
child: new Chip(
label: new Text(name,
style: new TextStyle(
color: selectedChip == number ? Colors.white : Colors.black
),),
backgroundColor:
selectedChip == number ? Colors.black : Colors.grey),
onTap: () {
setState(() {
selectedChip = number;
});
},
),
);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Stackoverflow'),
),
body: new Column(
children: <Widget>[
_myChip(1, 'Arnold'),
_myChip(2, 'Sylvester'),
_myChip(3, 'Priscilla'),
_myChip(4, 'Parge'),
_myChip(5, 'Something'),
],
),
);
}
You need to give chips a unique number to identify and use inline if to change the color of the chips.

Resources