I am currently working on having a gradient background animation in my app... I am doing so with the help of a lottie animation! I have tried to enclose it in a container and have succeeded in doing so. However there is one issue, I am not able to make the container bigger than a certain amount despite me changing the height to something even bigger than 2000... I really dont know what to do to make sure that there are no whitespaces in the screen and that this gradient fills the screen in all devices. Here is the code. I have also added in a screenshot of how it looks so that you get an idea of whats happening.
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
class WelcomeScreen extends StatefulWidget {
#override
_WelcomeScreenState createState() => _WelcomeScreenState();
}
class _WelcomeScreenState extends State<WelcomeScreen> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Padding(
padding: const EdgeInsets.all(0),
child: Container(
height: 1000,
width: 1000,
child: Lottie.asset('assets/gradient-background.json'),
),
),
));
}
}
I am new to flutter development so please forgive me if this is a very silly mistake! Thanks a lot and i really appreciate your help!
First of all, i would like to thank you all for your help. Special thanks to Nehal because he made me aware about the fit property which turns out to be a feature of a lottie asset animation! Thanks so much and this is the correct code:
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
class WelcomeScreen extends StatefulWidget {
#override
_WelcomeScreenState createState() => _WelcomeScreenState();
}
class _WelcomeScreenState extends State<WelcomeScreen> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
height: double.infinity,
width: double.infinity,
child:
Lottie.asset('assets/gradient-background.json', fit: BoxFit.cover),
),
));
}
}
I was able to fix this by using OverflowBox.
SizedBox(
height: 120,
child: OverflowBox(
minHeight: 170,
maxHeight: 170,
child: Lottie.asset(
'assets/file.json',
repeat: false,
),
),
)
Use an expanded widget and dont use any padding. You dont need to mention the height or width of the container and use the background property in decoration of container
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
class WelcomeScreen extends StatefulWidget {
#override
_WelcomeScreenState createState() => _WelcomeScreenState();
}
class _WelcomeScreenState extends State<WelcomeScreen> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Expanded(
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/gradient-background.json'),
fit: BoxFit.cover,
),
),
),
),
),
);
}
}
Also you can make a custom gradient in flutter rather than using a background photo.
Related
I am trying to use an AnimatedSwitcher within Stack. This leads to very strange behaviour of the animation. It animates the respective child widget (a red box in my case) in the center of my Stack and upon completion it snaps to the top left corner of my screen(which is where I would also like the animation to to take place). When I switch back, the same odd behaviour occurs.
My code looks as follows:
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: Home()));
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
bool _showMenu = false;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack(
children: [
GestureDetector(
onTap: () => setState(() => _showMenu = !_showMenu),
child: SizedBox.expand(
child: Container(
color: Colors.yellow,
),
),
),
AnimatedSwitcher(
duration: Duration(milliseconds: 500),
child: _showMenu
? Container(
key: UniqueKey(),
height: 200,
width: 200,
color: Colors.red,
)
: Container())
],
),
),
);
}
}
Which produces the following behaviour on the tap-event somewhere on the screen:
Any ideas why the red box is not animated in the top left corner but only goes there once the animation has finished?
The problem lies, as #Marino Zorilla pointed out, in the unique key I specified for my animating widget. Once I removed this key and also changed the "empty" Container (for the false-condition of my ternary operation) to a SizedBox it works as desired.
Apparently, this has to do with how flutter works internally (when the element tree and the widget tree are compared to determine which widgets need to be rebuild). If the widget changes to a different type (like in my case from Container to SizedBox) no key is needed for flutter to know that this widget needs to be rebuild.
The correct code looks as follows:
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: Home()));
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
bool _showBox = false;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack(
children: [
GestureDetector(
onTap: () => setState(() => _showBox = !_showBox),
child: SizedBox.expand(
child: Container(
color: Colors.yellow,
),
),
),
AnimatedSwitcher(
duration: Duration(milliseconds: 500),
child: _showBox
? Container(
height: 200.0,
width: 200.0,
color: Colors.red,
)
: SizedBox(),
)
],
)),
);
}
}
I have a following container which is actually bigger than the screen. But it seems like flutter doesn't allow the container width to be bigger than the screen.
import 'package:flutter/material.dart';
import 'dart:math' as math;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Test(),
);
}
}
class Test extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onTap: () {
print("Tapped");
},
child: Transform.rotate(
angle: math.pi / 4,
child: Container(
height: 200,
width: 700,
color: Colors.blue,
),
),
),
);
}
}
I tried to use Transform.scale instead but the GestureDetector doesn't work on the parts of container that is bigger than the screen.
import 'package:flutter/material.dart';
import 'dart:math' as math;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Test(),
);
}
}
class Test extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onTap: () {
print("Tapped");
},
child: Transform.rotate(
angle: math.pi / 4,
child: Transform(
transform: Matrix4.diagonal3Values(4, 1, 1),
child: Container(
height: 200,
width: 300,
color: Colors.blue,
),
),
),
),
);
}
}
The container will be resized using a resize handle. I'm okay with container not having width greater than screen whilst it's not rotated but when it's rotated I want the container to have width based on resize handle which can be greater than screen. Is there any workaround for this? Any help would be greatly appreciated.
I found a way and that is to use Stack & Positioned:
Stack(
children: [
Positioned(top: 0,
left: 0,
height: 200,
width: 1000,
child: Container(height: 200, width: 1000, color: Colors.blue),
),
],
),
Adjust the height and width of Positioned to limit how much width and height container can have.
From what I know it's not possible to have a container bigger than the screen. You have to take into account that the idea is for the app to run on different sized screens, so I personally don't see the point in giving static values when you can use dynamic ones so it fits different devices' sizes.
So I'm building a flutter app, a screen contains a column with four containers. I haven't specified the containers heights as I want them to take up the whole screen. Is there a way to convert the mainAxisSize to a float so that I can set the height of the containers to a quarter of the axis size. Thanks
For the containers you can use the attribute heigth. Then, you can use
screenHeigth=MediaQuery.of(context).size.heigth to obtain the heigth size of the phone you are using. Last of all, you can set the Containes' heigth attribute to: screenHeigth*0.25
So, each of them are 1/4 of the screen size high!
Here's the quick solution I think you are looking for. If not, let me know what to achieve other than this:
Demo:
**Code: **
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
// Getting Quarter Height of the screen
double qtrScreen = MediaQuery.of(context).size.height * 0.25;
return Scaffold(
body: Column(
children: [
Container(
color: Colors.red,
height:
qtrScreen, // Providing the Quarter height to all Containers
),
Container(
color: Colors.green,
height: qtrScreen,
),
Container(
color: Colors.blue,
height: qtrScreen,
),
Container(
color: Colors.orange,
height: qtrScreen,
),
],
),
);
}
}
You can use expanded and define flex property as you need. You don't need to create values using media query as it makes the code more complex for beginners.
I'm trying to create a parallax background for page controller. For that purpuse I need to create a background image that is wider than the screen. I've put it inside a container like this:
#override
Widget build(BuildContext context) {
return Material(
child: Stack(
children: [
Container(
width: 4000,
height: 250,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/pizza_bg.png'),
fit: BoxFit.cover,
repeat: ImageRepeat.noRepeat
)
)
),
],
),
);
}
But the problem is that no matter what width I specify, the container (and the image, of course) never get wider than the screen. Is it possible at all?
p.s. I tried to use SizedBox and AspectRatio widgets, and they both give the same result
try this, as an option
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Stack(
children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Container(
width: 4000,
height: 250,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/pizza_bg.png'),
fit: BoxFit.cover,
repeat: ImageRepeat.noRepeat,
),
),
),
),
],
),
),
);
}
}
also you can disable scroll for user and manage scroll position via scroll controller
SingleChildScrollView(
scrollDirection: Axis.horizontal,
physics: const NeverScrollableScrollPhysics(),
controller: controller, // your ScrollController
child: Container(
width: 4000,
height: 250,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('images/pizza_bg.png'),
fit: BoxFit.cover,
repeat: ImageRepeat.noRepeat,
),
),
),
),
For images you can use Transform.scale(), as found in the documentation. Using your example:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Stack(
children: [
Align(
alignment: Alignment.center,
child: Transform.scale(
scale: 10.0,
child: Container(
width: 400,
height: 25,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/pizza_bg.png'),
fit: BoxFit.cover,
repeat: ImageRepeat.noRepeat,
),
),
),
),
),
],
),
),
);
}
}
If you want to animate the scale, you can use ScaleTransition(), explained in this page of the docs. For example:
/// Flutter code sample for ScaleTransition
// The following code implements the [ScaleTransition] as seen in the video
// above:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
/// This is the stateful widget that the main application instantiates.
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({Key key}) : super(key: key);
#override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
/// This is the private State class that goes with MyStatefulWidget.
/// AnimationControllers can be created with `vsync: this` because of TickerProviderStateMixin.
class _MyStatefulWidgetState extends State<MyStatefulWidget>
with TickerProviderStateMixin {
AnimationController _controller;
Animation<double> _animation;
#override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)..repeat(reverse: true);
_animation = CurvedAnimation(
parent: _controller,
curve: Curves.fastOutSlowIn,
);
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ScaleTransition(
scale: _animation,
child: const Padding(
padding: EdgeInsets.all(8.0),
child: FlutterLogo(size: 150.0),
),
),
),
);
}
}
NOTE: To avoid quality loss in the image, use an image of the size after scaling or a vector graphic as a source.
My Image.asset file doesn't display my image but other widgets display text, card, etc
assets:
- images/internet_image.jpg
class SplashScreen extends StatefulWidget{
#override
_SplashScreenState createState() =>
_SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen>{
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Stack(
children: <Widget>[
Column(
children: <Widget>[
Image.asset(
'images/internet_image.jpg',
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * 1/4,
fit: BoxFit.fitWidth,
),
],
),
],
),
);
}
}
assets: - images/downloaded_image.jpg
and the referenced asset should be the same:
Image.asset('images/downloaded_image.jpg'),
In your code you refer to an asset named images/internet_image.jpg
An extra layer of widget might look like the code below so that the Scaffold doesn't have to field the context call.
class SplashScreen extends StatefulWidget{
#override
_SplashScreenState createState() =>
_SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen>{
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SplashScreenStack(),
);
}
}
class SplashScreenStack extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Column(
children: <Widget>[
Image.asset(
'images/internet_image.jpg',
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * 1/4,
fit: BoxFit.fitWidth,
),
],
),
],
);
}
}
Thanks a lot every one for answering. All solutions provided would definitely fix the issue, I decided to upload my splash screen the normal way via pubspec.yaml rather than trying to create a splash screen page.