Flutter: change theme brightess on part of screen? - dart

How can I make a theme get a Dark brightess on only a part of the screen? The brightness doest not work on the text.
#override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Theme(
data: ThemeData(brightness: Brightness.light),
child: Container(
child: Text("Bright Text"),
),
),
Theme(
data: ThemeData(brightness: Brightness.dark),
child: Container(
child: Text("Dark Text"),
),
),
],
),
);
}

It seems that this solution actually works, the reason you can't observe it in your original example is because the default text color in both color modes is the same — black (at least that's what I've got experimenting with it).
If you change your example to use a widget that uses a color that actually changes, you can clearly see it's working:
#override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Theme(
data: ThemeData(brightness: Brightness.light),
child: Container(
child: Icon(Icons.audiotrack), // always renders a black icon
),
Theme(
data: ThemeData(brightness: Brightness.dark),
child: Container(
child: Icon(Icons.audiotrack), // always renders a white icon
),
),
],
),
);
}
Sometimes you need to get the brightness of the current context to do some intricate configuration; the common way to do this: MediaQuery.of(context).platformBrightness will always give you the current color mode of the device/platform.
If you want to get the brightness that was "overridden" by the method above, you need to use Theme.of(context).brightness instead.

Related

Flutter - restrict widget to match others widget height

I would like to create list item widget with photo, and some information on the right side of this photo. Since web Image may be way to large, I also want my photo widget to match the height (while maintaining aspect ration) with "content" widgets height, possibly without giving an explicit height.
For now my widget looks like this:
In Android I would restrict image size with:
constraintTop_toTopOf(contentId)
constraintBottom_toBottomOf(contentId)
Is it possible to do similar thing in Flutter ?
For now my code looks like this (I would like to avoid giving explicit height in 'maxHeight' parameter of ConstrainedBox):
class SpeakerItemWidget extends StatelessWidget{
final Speaker _speaker;
SpeakerItemWidget(this._speaker);
Widget _speakerItemContent() =>
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'${_speaker.name} ${_speaker.surname}',
style: TitleTextStyle(),
),
SizedBox(height: Margin.small),
Text(
_speaker.title,
style: DescriptionTextStyle(),
),
Text(
_speaker.company,
style: DescriptionTextStyle(),
)
],
);
#override
Widget build(BuildContext context) =>
InkWell(
splashColor: Theme.of(context).accentColor,
onTap: () => debugPrint('open event details'),
child: Padding(
padding: EdgeInsets.all(Margin.small),
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: 60,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
FittedBox(
fit: BoxFit.contain,
child: SpeakerPhotoWidget(_speaker),
),
_speakerItemContent(),
],
),
),
),
);
}
class SpeakerPhotoWidget extends StatelessWidget{
final Speaker _speaker;
SpeakerPhotoWidget(this._speaker);
#override
Widget build(BuildContext context) {
return ConstrainedBox(
constraints: BoxConstraints(
//initial size of widget is 0,0 - causes crash when inside FittedBox
minHeight: 1,
minWidth: 1,
),
child: Padding(
padding: EdgeInsets.only(right: Margin.small),
child: FadeInImage.assetNetwork(
placeholder: 'assets/images/speaker_placeholder.png',
image: 'some uri',
fit: BoxFit.contain,
),
)
);
}
}

Expanded widget inside Column not expanded, instead it's got invisible

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),
],
)
);
}
}

Unwanted space appearing between RaisedButton widgets in a column

tl;dr Why is space appearing between my two buttons when I have not explicitly set any?
I am trying to make a layout like the one below:
However, what appears to be about 16px of space appears between the two buttons and I cannot figure out where it is coming from.
I at first thought maybe the Column was adding space but I am using MainAxisAlignment.center which shouldn't add any. I now think that there is perhaps some Material theming going on that automatically applies padding to the RaisedButton, however I have looked through both button_theme.dart and raised_button.dart and it seemed like only the inner padding (between text and button edges) was being set. I'm sure I overlooked something and would appreciate any help in finding out why this space exists.
auth.dart (screen shown in the image)
...
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(flex: 2, child: Container()),
Expanded(
flex: 8,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 32),
child: Image(
fit: BoxFit.contain,
image: AssetImage('lib/res/drawable/logo.webp'))),
PrimaryButton(
onPressed: //...,
child: Text('Log In')),
PrimaryButton(
onPressed: //...,
child: Text('Sign Up')),
])),
Expanded(flex: 2, child: Container()),
]));
}
primary_button.dart (custom rounded button widget that extends RaisedButton):
...
Widget build(BuildContext context) {
return Theme(
data: Theme.of(context).copyWith(
textTheme: Theme.of(context).textTheme,
buttonTheme: Theme.of(context).buttonTheme.copyWith(
padding: EdgeInsets.all(0),
minWidth: double.infinity,
buttonColor: Theme.of(context).accentColor,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24))),
),
child: Builder(builder: super.build));
}
add the property materialTapTargetSize and set it to MaterialTapTargetSize.shrinkWrap.
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
if you check the source code of RawMaterialButton it adds a padding based on that value:
Size minSize;
switch (widget.materialTapTargetSize) {
case MaterialTapTargetSize.padded:
minSize = const Size(48.0, 48.0);
break;
case MaterialTapTargetSize.shrinkWrap:
minSize = Size.zero;
break;
}
return Semantics(
container: true,
button: true,
enabled: widget.enabled,
child: _InputPadding(
minSize: minSize,
child: result,
),
);

how can I make BottomNavigationBar stick on top of keyboard flutter

I am trying to make a simple chat app, so I created a scaffold and my body, will be the messages and my bottomNavigationBar would be my typing field and sending icon.
I added a text field but when typing the navigation bar is hidden by the keyboard.
this is the code of my BottomNavigationBar :
bottomNavigationBar: new Container(
height: ScreenSize.height/12,
/*color: Colors.red,*/
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
new Container(
child: new Icon(Icons.send),
width:ScreenSize.width/6,
),
],
),
new Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Material(
child: new Container(
child: new TextField(
autofocus: false,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(9.0),
border: InputBorder.none,
hintText: 'Please enter a search term',
),
),
width:ScreenSize.width*4/6,
),
elevation: 4.0,
/*borderRadius: new BorderRadius.all(new Radius.circular(45.0)),*/
clipBehavior: Clip.antiAlias,
type: MaterialType.card,
)
],
),
new Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
new Container(
child: Text('HELLO C1'),
color: Colors.green,
width:ScreenSize.width/6,
),
],
)
],
),
),
here is how it looks when focused :
if you use a Stack on your Scaffold's body, instead of bottomNavigationBar, your nav will push up above the keyboard. even if you fix to the bottom with a Positioned:
Positioned(
bottom: 0.0,
left: 0.0,
right: 0.0,
child: MyNav(),
),
simply wrap your bottom navigation bar with Padding and set it to MediaQuery.of(context).viewInsets,
bottomNavigationBar: Padding(
padding: MediaQuery.of(context).viewInsets,
child: ChatInputField(),
),
Literally just worked through the same issue. Given the code i was refactoring, this worked like a charm. Peep the github link, review his change and apply. Couldn't be much more straight forward: https://github.com/GitJournal/GitJournal/commit/f946fe487a18b2cb8cb1d488026af5c64a8f2f78..
Content of the link above in case the link goes down:
(-)BottomAppBar buildEditorBottonBar(
(+)Widget buildEditorBottonBar(
BuildContext context,
Editor editor,
EditorState editorState,
BottomAppBar buildEditorBottonBar(
folderName = "Root Folder";
}
*REPLACE* return BottomAppBar(
elevation: 0.0,
color: Theme.of(context).scaffoldBackgroundColor,
child: Row(
children: <Widget>[
FlatButton.icon(
icon: Icon(Icons.folder),
label: Text(folderName),
onPressed: () {
var note = editorState.getNote();
editor.moveNoteToFolderSelected(note);
},
)
],
mainAxisAlignment: MainAxisAlignment.center,
*WITH THE WRAPPER* return StickyBottomAppBar(
child: BottomAppBar(
elevation: 0.0,
color: Theme.of(context).scaffoldBackgroundColor,
child: Row(
children: <Widget>[
FlatButton.icon(
icon: Icon(Icons.folder),
label: Text(folderName),
onPressed: () {
var note = editorState.getNote();
editor.moveNoteToFolderSelected(note);
},
)
],
mainAxisAlignment: MainAxisAlignment.center,
),
),
);
}
class StickyBottomAppBar extends StatelessWidget {
final BottomAppBar child;
StickyBottomAppBar({#required this.child});
#override
Widget build(BuildContext context) {
return Transform.translate(
offset: Offset(0.0, -1 * MediaQuery.of(context).viewInsets.bottom),
child: child,
);
}
}
I achieved this by a mix of two things I found separated in the web:
1 - Inside the Scaffold, I put other with only a bottomNavigationBar with a empty Container. For some reason, this trick push all my real bottomNavigationBar up to the top of the keyboard.
Scaffold(
bottomNavigationBar: Container(
height: 0,
),
body: Scaffold(
body: MyWidget(
But, I did not want all the content up, so I got that Package:
2 - I added flutter_keyboard_visibility: ^5.1.0 from
https://pub.dev/packages/flutter_keyboard_visibility
With this Package, you can do anything you want in response to keyboard visibility - is up to you. In my case, I made all content of my real bottomNavigationBar disappear except the textfield, which stay on the top of the keyboard:
[TextFormField] // dont go away,
//The others:
KeyboardVisibilityBuilder(builder: (context, visible) {
return Column(
children: [
visible
? SizedBox(
height: 0,
)
: OtherWidgets(
If you need some kind of button; you can do:
Scaffold(
bottomNavigationBar: bottomNavigationBar,
floatingActionButton: ExampleButton(
text: 'Hello',
),
body: body,
),
You can apply further customizations on the Floating Action Button using parameters in the Scaffold.
There is a simple way to do this if you want to really need to use the bottom navigation bar of the scaffold to put your widgets in rather than put it on a stack. Just wrap your scaffold with another scaffold and it should solve the problem.
return Scaffold(
body: Scaffold(
bottomNavigationBar: yourBottomNavigationBarWidget(),
body: yourBody(),
This works best especially when the height of your widget changes dynamically (because the text user types may introduce multiple lines) and you want the body to resize accordingly. A body in the stack, as suggested by many, will require a bottom padding to be visible over the text field and need to change dynamically as user types which is difficult to handle when you have multiple widgets sitting in and around the text field.

Pin a view to bottom of device

I have a view in a stack and I would like it to stay pinned to the bottom of the phone when it is turned to landscape. Currently i have the following:
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: detectOrientationForAppBar(),
backgroundColor: Colors.black,
key: _scaffoldKey,
body: new Column(
children: <Widget>[
new Expanded(
child: new Stack(
children: <Widget>[
new Container(
height: double.infinity,
width: double.infinity,
child: new Padding(
padding: const EdgeInsets.all(1.0),
child: new Center(
child: _cameraPreviewWidget(),
),
),
),
_captureControlRowWidget()
],
),
),
],
),
);
}
within this i would like the _captureControlRowWidget to stay fixed to the bottom of the device even when it is rotated. Here is my _captureControlRowWidget:
Widget _captureControlRowWidget() {
return new Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
new Container(
color: Colors.black,
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
new IconButton(
icon: const Icon(
Icons.camera_alt,
color: Colors.white,
),
color: Colors.white,
onPressed: controller != null &&
controller.value.isInitialized &&
!controller.value.isRecordingVideo
? onTakePictureButtonPressed
: null,
),
//showSwapCameraButton(),
new IconButton(
icon: new Icon(
Icons.videocam,
color: isRecording ? Colors.red : Colors.white,
),
color: isRecording ? Colors.red : Colors.white,
onPressed: controller != null &&
controller.value.isInitialized &&
!controller.value.isRecordingVideo
? onVideoRecordButtonPressed
: onStopButtonPressed,
)
],
),
),
],
);
}
Ive tried a few things like using the CrossAxis and MainAxis Alignments but it always sticks to the edge of the phone that is lowest. e.g if im holding the phone in porttrait the widget is at the bottom, if i rotate the phone 90 degrees in either direction the widget should be on the right side of the phone.
At the moment, your main body is a Column, so, as expected your control widget is below your camera preview. In landscape mode you want your control widget to be to the right of the camera preview, which means you want your main body to be a Row.
You can achieve this by changing the top Column to a Flex (which is a switch-selectable Row/Column).
#override
Widget build(BuildContext context) {
bool landscape = MediaQuery.of(context).orientation == Orientation.landscape;
return new Scaffold(
appBar: detectOrientationForAppBar(),
backgroundColor: Colors.black,
key: _scaffoldKey,
body: new Flex(
direction: landscape ? Axis.horizontal : Axis.vertical,
You will have to make the same change in your _captureControlRowWidget, making its Columns and Rows into orientation sensitive Flexes.

Resources