Making a persistent background image while staying responsive in Flutter - dart

I'm creating a login screen, and i have this background image,
the problem is when the user clicks one of the TextFields and the keyboard pops, the background image changes its size to fit the new screen size (excluding the keyboard).
I want the background to stay persistent and the same size, i would use BoxFit.none, but i'm afraid it will hurt the responsiveness of the app.
Here's the code:
new Container(
decoration: new BoxDecoration(
color: Colors.red,
image: new DecorationImage(
fit: BoxFit.cover,
image: new AssetImage(
'assets/images/splash_screen/background.png'))),
child: new Center(
child: new ListView(
physics: new PageScrollPhysics(),
children: <Widget>[ //Login screen content ],
),
),
);
I also tried to define BoxConstraints with minHeight of the device screen but it doesn't help, and used Stack as well but with not luck.
Here's what i mean by changing dimensions:
No Keyboard / With Keyboard

Put your Scaffold as a child of a Container and make it transparent
final emailField = TextFormField(
decoration: InputDecoration(
hintText: "Email",
),
);
return Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/bg.png'),
fit: BoxFit.cover,
),
),
child: Scaffold(
backgroundColor: Colors.transparent,
body: ListView(
children: <Widget>[
emailField,
],
),
),
);

Try using a Stack, with your image in a Positioned, with a BoxFit of fill. Then, set top: 0.0. This way, its height shouldn't be influenced by the height of the bottom of the screen (i.e. it shouldn't change when the keyboard comes up), and its size should remain the same.
Example:
return Stack(
children: <Widget>[
Positioned(
top: 0.0,
child: Image.asset(
'assets/images/splash_screen/background.png',
fit: BoxFit.fill,
),
),
Center(
child: ListView(
physics: PageScrollPhysics(),
children: <Widget>[
//Login screen content
],
),
),
],
);

Try going to to your Scaffold (or use one) and set
resizeToAvoidBottomPadding = false

You can try this, It works well
import 'package:flutter/material.dart';
class SignUpView extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Stack(children: [
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/background.png"),
fit: BoxFit.cover,
))),
Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Colors.transparent,
appBar: AppBar(
title: Text('NEW USER'),
backgroundColor: Colors.transparent,
elevation: 0,
),
body: Padding(
padding: EdgeInsets.all(10),
child: ListView(children: <Widget>[])))
]);
}
}

Related

Overflow Error in Flutter when keyboard open

I am designing a login page it overflowed when I click on any text form field it open keyboard and through overflow warning like this see attached image.
I also want a Raised button icon should be on the right side of the button.
Widget build(BuildContext context) {
return Container(
child: Scaffold(
body: Stack(
fit: StackFit.expand,
children: <Widget>[
Container(
decoration: BoxDecoration(
image: new DecorationImage(
image: new AssetImage('assets/login_page_bg_1.jpg'),
fit: BoxFit.cover,
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.55), BlendMode.dstATop))),
),
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
flex: 1,
child: Container(
margin: new EdgeInsets.only(top: 42.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset('assets/logo.png',
width: 250.0, height: 200.21),
],
),
),
),
Expanded(
flex: 2,
child: Container(
margin: new EdgeInsets.only(bottom: 40.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
//form filed goes here
Text('Login As User',
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 35.0)),
TextFormField(
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
hintText: 'you#example.com',
labelText: 'Email Address',
),
new Container(
// width: MediaQuery.of(context).size.width,
child: RaisedButton.icon(
color: Color.fromARGB(251, 188, 74, 1),
label: Text('LOGIN'),
icon: Icon(Icons.send,
size: 10.0, color: Colors.black),
onPressed: () {
this.submit();
}, ),)],),),)],)],),),);
Intital state
Error/overflowed State
Set following property to false
Scaffold(
resizeToAvoidBottomInset: false,
...
)
If you're having issues with overflow error, use SingleChildScrollView with it.
Scaffold(
resizeToAvoidBottomInset: false, // set it to false
body: SingleChildScrollView(child: YourBody()),
)
PS: If you like to scroll your widget when the keyboard opens, you can take a look at this answer
This is happening because when the keyboard comes on screen, the height of the canvas to draw decreases. One solution is to wrap your root container inside SingleChildScrollView like this :
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Stack(
fit: StackFit.loose,
children: <Widget>[
Container(
decoration: BoxDecoration(
image: new DecorationImage(
image: new AssetImage('assets/login_page_bg_1.jpg'),
fit: BoxFit.cover,
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.55), BlendMode.dstATop)
)
),
),
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
SizedBox(height: 42,),
Expanded(
flex: 1,
child: Center(
child:
Image.asset('assets/logo.png',
width: 250.0, height: 200.21),
),
),
Expanded(
flex: 2,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
//form filed goes here
Text('Login As User',
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 35.0)),
TextFormField(
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
hintText: 'you#example.com',
labelText: 'Email Address',
)
),
new Container(
// width: MediaQuery.of(context).size.width,
child: RaisedButton.icon(
color: Color.fromARGB(251, 188, 74, 1),
label: Text('LOGIN'),
icon: Icon(Icons.send,
size: 10.0, color: Colors.black),
onPressed: () {
//this.submit();
}, ),)],)),
SizedBox(height: 40,)
],)],),));
It will make your screen scrollable when the height of the content gets more than the available height of the viewport.
A much simpler solution (source) seems to be just setting the Scaffold property resizeToAvoidBottomPadding to false.
This works great with me:
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomPadding: false,
appBar: AppBar(...),
body: ...
Add resizeToAvoidBottomPadding: false, and resizeToAvoidBottomInset: false,
to your Scaffold widget.
Wrap your code with a Container, set the Container's parameters height: MediaQuery.of(context).size.height, and width: MediaQuery.of(context).size.width,. Then wrap your Container with a SingleChildScrollView.
Setting resizeToAvoidBottomInset: true and using body: ListView() works as well. This enables you to scroll the page when you open the keyboard.
An even easier version is to just wrap the offending container with a ListView widget. It makes the screen scrollable and is simple to implement. You can use multiple children with this widget.
Scaffold(
body: ListView(
children: <Widget> [
Container(
),
TextView(
),
Column(
),
],
),
)
you should make the scaffold's floating widgets should size themselves to avoid the onscreen keyboard using :
Scaffold(
resizeToAvoidBottomInset: false,
...
)

Flutter - How to control profile image size in the drawer

I would like to control the profile image size, and get it rounded instead of oval as shown below.
Changing the height and/or the width values doesn't affect neither the size nor the ratio, also the weird thing is when I change the margin parameter it changes the oval shape radius.
new UserAccountsDrawerHeader(
decoration: BoxDecoration(color: Colors.white),
currentAccountPicture: new Container(
margin: const EdgeInsets.only(bottom: 40.0),
width: 10.0,
height: 10.0,
decoration: new BoxDecoration(
shape: BoxShape.circle,
image: new DecorationImage(
fit: BoxFit.fill,
image: new NetworkImage(
"https://example.com/assets/images/john-doe.jpg",
),
),
),
),
accountName: new Container(
...
),
accountEmail: new Container(
...
),
onDetailsPressed: () {
...
},
),
What am I doing wrong ?
Update: The above way of doing is a workaround to the CircleAvatar that didn't give any control on the image size. If you tried CircleAvatar in some different way that gives control on image size, please share it to help.
Use This code for network image:
new CircleAvatar(
radius: 60.0,
backgroundColor: const Color(0xFF778899),
backgroundImage: NetworkImage("Your Photo Url"), // for Network image
),
Use this for asset Image:
new CircleAvatar(
radius: 60.0,
backgroundColor: const Color(0xFF778899),
child: new Image.asset(
'images/profile.png',
), //For Image Asset
),
If you use backgroundImage as the image provider for CircleAvatar then changing the radius property indeed has no effect. From the source circle_avatar.dart it can be observed the image is being rendered as BoxFit.cover DecorationImage(image: backgroundImage, fit: BoxFit.cover) - and in user_accounts_drawer_header.dart the currentAccountPicture is hardcoded to be a 72.0 pixel SizedBox so the image will always be 72.0px in dimensions.
https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/material/user_accounts_drawer_header.dart#L57
https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/material/circle_avatar.dart#L203
Hopefully the Flutter team adds some level of control to this in the future.
Not an answer, just more info that hopefully helps someone.
Try This:
import 'package:flutter/material.dart';
class AppDrawer extends StatefulWidget {
#override
_AppDrawerState createState() => new _AppDrawerState();
}
class _AppDrawerState extends State<AppDrawer> {
#override
Widget build(BuildContext context) {
return new Drawer(
child: Center(
child: Column(
children: <Widget>[
new UserAccountsDrawerHeader(
decoration: BoxDecoration(color: Colors.white),
currentAccountPicture: new CircleAvatar(
radius: 50.0,
backgroundColor: const Color(0xFF778899),
backgroundImage:
NetworkImage("http://tineye.com/images/widgets/mona.jpg"),
),
),
],
),
),
);
}
}
This is the screenshot of output:
Wrap your image in a CircleAvatar widget. It’s made for such purposes.
You put the margin inside the Container of the image while you have to use the margin parameter of the UserAccountDrawerHeader, this is why your image became an oval:
UserAccountsDrawerHeader(
decoration: BoxDecoration(color: Colors.white),
margin: EdgeInsets.only(bottom: 40.0),
currentAccountPicture: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
fit: BoxFit.fill,
image:
NetworkImage("https://via.placeholder.com/150"))),
),
accountName: new Container(
child: Text(
'Name',
style: TextStyle(color: Colors.black),
)),
accountEmail: new Container(
child: Text(
'Email',
style: TextStyle(color: Colors.black),
)),
),
You can create your own header:
DrawerHeader(
decoration: BoxDecoration(
color: Colors.blue
),
child: ListView(
children: [
return ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Image.asset('images/myImage.jpg'),
),
//These can go here or below the header with the same background color
Text("user name"),//customize this text
Text("useremail#example.com"),
//...additional header items here
],
)),
I found a solution!!! at least thats what worked for me
import 'package:flutter/material.dart';
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
// Side menu
drawer: new Drawer(
child: GestureDetector(
onTap: () {},
child: ListView(
children: <Widget>[
new UserAccountsDrawerHeader(
accountName: new Text('Hymn +'),
accountEmail: new Text('johndoe#gmail.com'),
currentAccountPicture: new CircleAvatar(
backgroundImage: new NetworkImage(
'https://miro.medium.com/max/1400/1*uC0kYhn8zRx8Cfd0v0cYQg.jpeg'),
),
),
],
),
),
),
);
}
}
This works for me:
DrawerHeader(
decoration: BoxDecoration(color: Colors.blue),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
/*CircleAvatar(
radius: 50.0,
backgroundColor: const Color(0xFF778899),
child: new Image.asset('assets/images/profile_image.png'), //For Image Asset
),*/
Container(
height: 110,
child: ClipRRect(
borderRadius: BorderRadius.circular(100.0),
child: Image.asset('assets/images/profile_image.png'),
),
),
//These can go here or below the header with the same background color
//Divider(height: 1.0, thickness: 1.0, color: Colors.black),
SizedBox(height: 9.0),
Text("user name"),
//...additional header items here
],
),
),

Using a SVG as a background image for a Container

From this question I am using Flutter's SVG package (flutter_svg) to render a SVG image.
I want to use the SVG as a Container background with Text in the middle.
This is the code I have so far:
Container(
decoration: BoxDecoration(
image: DecorationImage(image: SvgPicture.asset(
'assets/example.svg',
),),
),
children: <Widget>[
Text('Welcome to my Flutter App',
style: Theme.of(context).textTheme.display1.copyWith(
color: Colors.white,
fontWeight: FontWeight.bold
)
),
],
)
The problem I am finding is that SvgPicture is not an ImageProvider so I can't add the BoxDecoration to get a background image.
Is there a way to then use SvgPicture as a Container's box decoration or background?
The exact way to use an SvgPicture is like this:
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
SvgPicture.asset(
'assets/images/splash/background.svg',
alignment: Alignment.center,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
),
Container(
child: Column(
children: <Widget>[Expanded(child: _createLogo())],
),
),
],
),
);
}
how about using a stack() and build everything on top of that. That is how I have done it with just an image as a background for the full viewport.
You can also use flutter_svg_provider
Like this :
import 'package:flutter_svg_provider/flutter_svg_provider.dart';
Container(
decoration: BoxDecoration(
image: DecorationImage(image: Svg(
'assets/example.svg',
),),
),
)

How can I avoid the background image to shrink when my keyboard is active?

I would like to have a background image with text inputs but I don't know which widget I should use to avoid the background image to shrink when my keyboard is active.
Here you can find two screen shots of the problem and my code:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
var backgroundImage = new BoxDecoration(
image: new DecorationImage(
image: new AssetImage('assets/forest.jpg'), fit: BoxFit.cover));
return new MaterialApp(
home: new Scaffold(
body: new Stack(
children: <Widget>[
new Container(
decoration: backgroundImage,
),
new TextField()
],
)));
}
}
closed keyboard
active keyboard
Put Container outside of Scaffold, and make Scaffold as a child of Container with the background image.
return Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/bg.png'),
fit: BoxFit.cover,
),
),
child: Scaffold(
backgroundColor: Colors.transparent,
body: ListView(
children: <Widget>[
TextFormField(
decoration: InputDecoration(
hintText: "Email",
),
),
],
),
),
);
You can use the property resizeToAvoidBottomPadding from Scaffold :
Scaffold(
resizeToAvoidBottomPadding: false,
...
It's the default functionality of the flutter to keep UI above the keyboard so if you set resizeToAvoidBottomInset : false then you will lose the functionality of keeping your UI components above the keyboard
To have a background image in your application, and not to shrink it
better way is to do it like this
Container(
decoration: BoxDecoration(
color: primaryColor, // background color
image: DecorationImage(image: AssetImage(AppImages.appBg)),// background image above color
),
child: SafeArea(
child: Scaffold(
backgroundColor: Colors.transparent, //**IMPORTANT**
body: //All Ui code here//),
),
It is necessary to set Scaffold backgroundColor: Colors.transparent
otherwise, you won't be able to see your background image

Blurred Decoration Image in Flutter

I have the background of my app set like so:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new ExactAssetImage('assets/lol/aatrox.jpg'),
fit: BoxFit.cover,
),
),
child: new BackdropFilter(filter: new ImageFilter.blur(sigmaX: 600.0, sigmaY: 1000.0)),
width: 400.0,
),
);
}
}
I'm wanting to blur the DecorationImage, so I added a BackdropFilter to the Container, but I don't see any change. What am I doing wrong?
You could do something like this, by blurring the container child instead.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new ExactAssetImage('assets/dog.png'),
fit: BoxFit.cover,
),
),
child: new BackdropFilter(
filter: new ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
child: new Container(
decoration: new BoxDecoration(color: Colors.white.withOpacity(0.0)),
),
),
),
);
}
}
Screenshot:
Using Stack:
SizedBox(
height: 200,
child: Stack(
fit: StackFit.expand,
children: [
Image.asset('chocolate_image', fit: BoxFit.cover),
ClipRRect( // Clip it cleanly.
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: Container(
color: Colors.grey.withOpacity(0.1),
alignment: Alignment.center,
child: Text('CHOCOLATE'),
),
),
),
],
),
)
Without using Stack:
Container(
height: 200,
width: double.maxFinite,
decoration: BoxDecoration(
image: DecorationImage(
image: ExactAssetImage("your_chocolage_image"),
fit: BoxFit.cover,
),
),
child: ClipRRect( // make sure we apply clip it properly
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: Container(
alignment: Alignment.center,
color: Colors.grey.withOpacity(0.1),
child: Text(
"CHOCOLATE",
style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
),
),
),
),
)
As I mentioned here, you should wrap your ImageFiltered widget in a ClipRRect to prevent it from flowing out the widget boundaries. Here's the code:
ClipRRect(
child: ImageFiltered(
imageFilter: ImageFilter.blur(sigmaX: 3, sigmaY: 3),
child: Image.asset('assets/flutter_image.png'),
),
),
This is the output:
ImageFiltered is the perfect widget for that . It creates a widget that applies an ImageFilter to its child.
ImageFilter is an easy way to blur or transform pixels in your app . You can import it from dart:ui
Code :
ImageFiltered(
imageFilter: ImageFilter.blur(sigmaY:5,sigmaX:5), //SigmaX and Y are just for X and Y directions
child: Image.asset('assets/image.png') //here you can use any widget you'd like to blur .
)
ImageFilter.blur() make anything blurry and
ImageFilter.matrix() lets you use any matrix for
transformation ,scaling , translating , skewing and rotating
Output :
A similar widget to ImageFiltered is BackdropFilter .
BackdropFilter lets you apply filter to everything that's painted
beneath a widget , instead of applying the filter to the widget
itself.
It's also less performant . If you can do your effect with
ImageFiltered , Use it instead of BackdropFilter.
You can learn more about ImageFiltered by watching this official video or by visiting flutter.dev
It's better if you put in ClipRRect, like this :
Container(
child: ClipRRect(
child: Stack(
children: <Widget>[
FadeInImage.assetNetwork(
placeholder: placeholder,
image: thumbnail,
fit: BoxFit.cover,
),
BackdropFilter(
child: Container(
color: Colors.black12,
),
filter: ImageFilter.blur(sigmaY: 10, sigmaX: 10),
)
],
),
),
width: double.infinity,
),
This case apply for Image (Thumbnail) list items correctly.
All the above answers are correct, I'll reply to #user123456 here since I can't comment yet.
can i make the BoxDecoration image clickeble – user123456
Just wrap the whole Container with a GestureDetector
GestureDetector(
onTap: () {...},
child: Container(
...
decoration: BoxDecoration(...),
),
);
You can use Image widget. It's very simple.
Image(
image: AssetImage("assets/images/news-media.png"),
color: Colors.black,
colorBlendMode: BlendMode.softLight,
fit: BoxFit.fill,
),

Resources