I'd like to fix an Image in the footer of the screen, so in different phones it stays always in the bottom .
What I tried
I tried to use Column, and then in the mainAxisAlignment I would use MainAxisAlignment.end
Additional Question : Is there a way to create a canvas and place it on the image, so I can use relative coordinate on the image if I want to draw something instead of the full screen
You can use the bottomSheet in the scaffold. This automatically allows you to have the widget fixed at the bottom of the display
return Scaffold(
bottomSheet: yourWidget(),
body: Container(color: Colors.red,)
);
Please write a question for each question you have in the future - that makes them more searchable and useful in the future for other people.
However, I think I can answer both pretty simply so I will.
Firstly, if you want an image to always be at the foot of the screen, you can simply use a the bottomNavigationBar property of the Scaffold. It looks like it would have to be a BottomNavigationBar but you can actually pass any widget you'd like.
Here's the code (you can paste it into a file and run that file as it's self-enclosed):
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() => new MyAppState();
}
class MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
bottomNavigationBar: Stack(
children: [
new Container(
height: 100.0,
color: Colors.green,
),
Positioned(
left: 0.0,
right: 0.0,
top: 0.0,
bottom: 0.0,
child: new CustomPaint(
painter: Painter(),
size: Size.infinite,
),
),
],
),
),
);
}
}
class Painter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
canvas.drawLine(Offset.zero, size.bottomRight(Offset.zero), Paint());
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
// bad, but okay for example
return true;
}
}
I've just used a simple painter to illustrate the 'canvas' and how to position it the same as the picture, and a Container with a colour instead of a picture as I don't feel like adding assets to my project. The Positioned widget makes it so that the canvas can be sized to the image and not the other way around, as would happen if you just put them right into the Stack.
Note that if you don't want to use scaffold, you could probably also do this using a Column, with whatever you want for the body wrapped in an Expanded widget (as that will make it expand to fit as much space as possible, which should be everything except the space the image takes up).
you can use persistentFooterButtons widget inside Scaffold
#override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Demo App'),
),
body: _questionIndex < _questions.length
? Quiz(
list: _questions,
selectHandler: _printAns,
questionIndex: _questionIndex)
: Result(_totalScore, _resetQuiz),
persistentFooterButtons: <Widget>[
Row(
children: <Widget>[
RaisedButton(
onPressed: null,
child: Text('Prev'),
),
RaisedButton(
onPressed: null,
child: Text('Next'),
),
],
)
],
),
);
Related
I have an application (simplified) that looks like this:
working dartpad example:
https://dartpad.dev/cc4e524315e104c272cd06aa7037aa10
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: MyWidget(),
),
bottomNavigationBar: BottomWidget(),
),
);
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Text('Hello, World!');
}
}
class BottomWidget extends StatelessWidget {
Widget build(BuildContext context) {
return BottomAppBar(
child: InkWell (
child: Container(
height:100,
color: Colors.pink,
child: Center(
child: Text('this is a bottom navigation bar')
),
),
onTap: () {
showModalBottomSheet(
context: context,
builder: (context) => Container(),
);
}
),
);
}
}
My question is, I want to use showModalBottomSheet to stop user from interacting with the screen, but I need bottomNavigationBar to be shown like this:
Right now it just covers everything including the bottomNavigationBar:
If I change it to showBottomSheet, it works perfectly like the first picture.
Why is their behaviour different?
How can I achieve the result that I want using showModalBottomSheet?
showModalBottomSheet show bottom sheet on top of all widget and layers, if you want to show it under bottomNavigationBar you should use Stack in parent and use a single child into that. its not easy to take a sample and that take a long time to reproduce pseudo code
Hero widget gives animation to different widgets on its own by analyzing. So can I wrap different widgets with Hero so that they get animated and look good? Because am don't know about the outcome or what animation will it show or totally don't show, which widget will and which one not...So can I wrap most of them with her widget? If yes, then which widgets can be wrapped to get animations, and do I have to do any extra work after wrapping with the hero? an example, please.
Or is there any way to apply animations to the whole app in all possible widgets at once, which would be more efficient and tame saving?
Hero widget will automatically create a Hero transition between two navigator routes.
Flutter will figure out where the widget is in both routes and animate the change between locations.
Let's say you want to use a picture as your Hero.
Put it on both the page routes, the one that you'll be transitioning from and the one you'll
be transitioning to.
Then, wrap the image with a Hero widget on both pages. Add a tag. This can be any object. The important thing is to use the same tag on both pages so that Flutter knows which Hero you are animating.
And you're done.
import 'package:flutter/material.dart';
void main() => runApp(HeroApp());
class HeroApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Transition Demo',
home: MainScreen(),
);
}
}
class MainScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Main Screen'),
),
body: GestureDetector(
child: Hero(
tag: 'imageHero',
child: Image.network(
'https://picsum.photos/250?image=9',
),
),
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (_) {
return DetailScreen();
}));
},
),
);
}
}
class DetailScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
child: Center(
child: Hero(
tag: 'imageHero',
child: Image.network(
'https://picsum.photos/250?image=9',
),
),
),
onTap: () {
Navigator.pop(context);
},
),
);
}
}
In flutter, you can for example have two pages with their own sets of widgets that when you navigate from one page to the other, the widgets on the screen will change to the other one.
But is it possible to have a completely seperate layer of widgets, that is drawn on top of all pages and it's widgets would remain when the navigation happens?
Completely possible!
Method 1: Subnavigators
Make the widget you want to stay consistent be at the same level or higher up in the widget tree than the navigator. For example (MaterialApp widget creates navigator automatically at its level)
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(
home: Column(
children: [
Container(
height: 100,
color: Colors.red,
),
Expanded(
child: MaterialApp(
home: PageOne(),
),
),
],
));
}
}
class PageTwo extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(),
appBar: AppBar(
title: Text("Page Two"),
),
);
}
}
class PageOne extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
child: Text("Open Page Two"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => PageTwo()),
);
},
),
),
appBar: AppBar(
title: Text("Page One"),
),
);
}
}
This will keep a red container over any navigation. You could use a Stack instead of a Column if you wanted an overlay. At this point we have two navigators because we have two MaterialApps. Calling navigator.of(context) retrieves the closest one in the widget tree, which will be the subnavigator, allowing our navigation to only affect everything under the second MaterialApp widget
Method 2: Keys
I won't go too in depth on these here. But keys are a way to identify widget across rebuilds. You can give the widget you want to stay consistent a key, and it will be considered the same widget on rebuilds. Check out more information on keys in flutter: https://medium.com/flutter/keys-what-are-they-good-for-13cb51742e7d
I want to place an Iconbutton in the top right corner of my Scaffold that programmatically opens a drawer. It should be the top right corner for every displaytype.
Using an appbar would ruin the look of the page since I just need a small icon that shows that a drawer is available. How do I do this the best way?
My Scaffold is a default one.
How can I achieve this the best way?
You can achieve this using a Stack .
Wrap the body of your Scaffold with a Stack widget and use the Positioned widget as the first child of the stack.
GlobalKey<ScaffoldState> _scafKey = GlobalKey();
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
key: _scafKey,
drawer: YourDrawerWidget(),
body: Stack(
children: <Widget>[
Positioned(
top: 0,
right: 0,
child: IconButton(
icon: Icon(Icons.short_text),
onPressed: (){
_scafKey.currentState.openDrawer();
})),
Container(),
],
),
),
);
}
Replace the container with your widget(the original body of the scaffold).
And also the icon of the IconButton to your Icon.
Here the MyHomePage class is the AppBar you need for your Scaffold. All you need to do is change the icon.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: MyHomePage(),
drawer: Container(
width: 100,
color: Colors.red,
),
),
);
}
}
class MyHomePage extends StatelessWidget implements PreferredSizeWidget {
#override
Widget build(BuildContext context) {
return SafeArea(
child: Container(
color: Colors.transparent,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
AppBarAction(),
],
),
),
);
}
#override
Size get preferredSize => Size.fromHeight(60);
}
class AppBarAction extends StatelessWidget {
#override
Widget build(BuildContext context) {
return IconButton(
icon: Icon(Icons.print),
onPressed: () {
Scaffold.of(context).openDrawer();
},
);
}
}
I have a flutter app in which I have a stack and within a Container with some elements. I want to give some gesture detection and show an overlay layer when the user clicks on it. I have think of creating another container with the color and shape I want and then make it occupy the same space of the other container but above it.
The problem is that I can't figure out how to make the overlay container to have the same size than the main container.
This is what I have basically:
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> {
bool _layerVisible = false;
#override
Widget build(BuildContext context) {
List<Widget> array = List();
array.add(Stack(
children: <Widget>[
GestureDetector(
onTapDown: (TapDownDetails details) {
setState(() {
_layerVisible = true;
});
},
onTapUp: (TapUpDetails details) {
setState(() {
_layerVisible = false;
});
},
child: Container(
padding: EdgeInsets.all(8),
color: Colors.yellow,
child: Column(
children: <Widget>[
Padding(
child: Text("Title text"),
padding: EdgeInsets.only(bottom: 10),
),
Text(
"Veeery long text. This is a dynamic value so we don't really know how long it's going to be...this means that the parent container is going to grow.")
],
)),
),
Visibility(
visible: _layerVisible,
child: Container(
color: Colors.grey,
child: Text(
"This is the container that I want to fit exactly in the yellow container."),
),
)
],
));
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
width: 300,
child: ListView(
children: array,
),
));
}
}
What I want is to make the last container within the stack to occupy the same space of the other container, this way I can create an overlay layer when I click on it.
I try using Expanded, using Positioned.fill, but none of this solution works for me.
Thanks.
Try using an IntrinsicHeight above your Stack. It'll give an explicit size based off the largest widget in the stack to the Stack itself. Then, make sure you add a fit: StackFit.passthrough, on the Stack. That'll pass down the sizing information from IntrinsicHeight to all of it's children.