Am trying to make an animated foreground for a title text in flutter or to more accurate i want mast the text with GIF something like this Am not even sure how to do it but i think if i managed to make stack filled with a GIF then make the last layer a CustomClipper<Path> to fill the entire space but the Text shape then it will look like it, the problem is i don't know how to make the text shape !plus i don't know how to make a path that just fill the entire size except the the text shape i will provide , please any help will be appreciated or if you have any ideas that will do it but in a different way am also interested and thanks in advance .
ah, I'm late..ok, let it be
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(title: const Text('Title')),
body: Stack(
children: [
FakeAnimatedBackground(),
ShaderMask(
blendMode: BlendMode.srcOut,
shaderCallback: (bounds) => LinearGradient(colors: [Colors.black], stops: [0.0]).createShader(bounds),
child: SizedBox.expand(
child: Container(
color: Colors.transparent,
alignment: Alignment.center,
child: const Text('SOME TEXT', style: TextStyle(fontSize: 60, fontWeight: FontWeight.bold)),
),
),
),
],
),
),
);
}
}
class FakeAnimatedBackground extends StatefulWidget {
#override
_FakeAnimatedBackgroundState createState() => _FakeAnimatedBackgroundState();
}
class _FakeAnimatedBackgroundState extends State<FakeAnimatedBackground> with TickerProviderStateMixin {
AnimationController _controller;
#override
void initState() {
super.initState();
_controller = AnimationController(duration: const Duration(milliseconds: 5000), vsync: this)..repeat();
}
#override
Widget build(BuildContext context) {
return RotationTransition(
alignment: Alignment.center,
turns: Tween(begin: 0.0, end: 1.0).animate(_controller),
child: Container(
decoration: BoxDecoration(
gradient: SweepGradient(colors: [Colors.red, Colors.green, Colors.blue, Colors.red]),
),
),
);
}
}
FakeAnimationBackground class doesn't matter, it's just simulate background moving
you can use ImageShader, ShaderMask and StreamBuilder ( for gif )
import 'dart:async';
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
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: "test",
),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Stream<ui.Image> _image;
#override
initState() {
super.initState();
_image = _getImage();
}
Stream<ui.Image> _getImage() {
var _controller = new StreamController<ui.Image>();
new AssetImage('assets/b.gif')
.resolve(new ImageConfiguration())
.addListener(ImageStreamListener(
(info, _) {
_controller.add(info.image);
}
));
return _controller.stream;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: StreamBuilder<ui.Image>(
stream: _image,
builder: (context, data) {
if (data.data == null)
return Text('loading');
return ShaderMask(
child: Text("Gif !!", style: TextStyle(fontSize: 50),),
blendMode: BlendMode.srcATop,
shaderCallback: (bounds) {
return ui.ImageShader(
data.data,
TileMode.repeated,
TileMode.repeated,
Matrix4.identity().storage,
);
},
);
},
),
));
}
}
Related
I have a Flutter StatefulWidget and in initState() method I am using WidgetsBinding.instance.addPostFrameCallback to use one instance variable (late List _tracks). like -
WidgetsBinding.instance.addPostFrameCallback((_) {
for(itr = 0; itr<_tracks.length; itr++){
// some logic
}
});
As this would get invoked after all Widgets are done. In one of the CustomPaint's painter class I am initializing that variable.
SizedBox.expand(
child: CustomPaint(
painter: TrackPainter(
trackCalculationListener: (tracks) {
_tracks = tracks;
}),
),
),
It is working fine when I have one screen, i.e the same class. But, When I am adding one screen before that and trying to navigate to this screen from the new screen it is throwing _tracks is not initialized exception.
new screen is very basic -
class MainMenu extends StatefulWidget {
const MainMenu({super.key});
#override
State<MainMenu> createState() => _MainMenuState();
}
class _MainMenuState extends State<MainMenu> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.white,
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const Play(),
maintainState: false));
},
child: const Text('play game'),
),
),
);
}
}
In single screen case the paint method of painter is getting called before postFrameCallback but in case of multiple it is not getting before postFrameCallback and because of that the variable is not getting initialized.
reproducible code -
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
routes: {
'/mainMenu': (context) => const MainMenu(),
'/game': (context) => const MyHomePage(title: 'game'),
},
initialRoute: '/mainMenu',
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late List<Rect> _playerTracks;
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
print(_playerTracks.length);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
color: Colors.white,
margin: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: 1,
child: SizedBox.expand(
child: CustomPaint(
painter: RectanglePainter(
trackCalculationListener: (playerTracks) =>
_playerTracks = playerTracks),
),
),
),
)
],
),
),
);
}
}
class MainMenu extends StatefulWidget {
static String route = '/mainMenu';
const MainMenu({super.key});
#override
State<MainMenu> createState() => _MainMenuState();
}
class _MainMenuState extends State<MainMenu> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
height: 200.0,
color: Colors.white,
child: ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/game');
},
child: const Text('play game'),
),
),
),
);
}
}
class RectanglePainter extends CustomPainter {
Function(List<Rect>) trackCalculationListener;
RectanglePainter({required this.trackCalculationListener});
#override
void paint(Canvas canvas, Size size) {
final Rect rect = Offset.zero & size;
const RadialGradient gradient = RadialGradient(
center: Alignment(0.7, -0.6),
radius: 0.2,
colors: <Color>[Color(0xFFFFFF00), Color(0xFF0099FF)],
stops: <double>[0.4, 1.0],
);
canvas.drawRect(
rect,
Paint()..shader = gradient.createShader(rect),
);
List<Rect> _playerTracks = [];
_playerTracks.add(rect);
trackCalculationListener(_playerTracks);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
I am very new to flutter and would highly appreciate if someone could help me figure out what I am doing wrong here.
The widget I made for the background color is causing a problem.
There is a problem when a child widget is added to the Background Color widget I made. In this case setstate doesn't work.
Setstate not working when adding a widget to the background?
Why is the screen not updating?
Why do you think this is not happening? Where am I doing wrong?
//zemin_rengi.dart
import 'package:flutter/material.dart';
class ZeminRengi extends StatefulWidget {
final Widget childWidget;
const ZeminRengi({required this.childWidget});
#override
State<ZeminRengi> createState() => _ZeminRengiState();
}
class _ZeminRengiState extends State<ZeminRengi> {
Widget? _childWidget;
#override
void initState() {
// TODO: implement initState
super.initState();
_childWidget = widget.childWidget;
}
#override
Widget build(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Colors.blue, Colors.red]),
),
child: _childWidget,
);
}
}
//main.dart
import 'package:builk/zemin_rengi.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ZeminRengi(
childWidget: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
thanks for help.
enter image description here
When the app opens up, I want the logo and app name to pop up, and pause it for a few seconds before redirecting to the next directory. Can anyone please help me because I'm new to flutter and have been stuck for awhile >_<
import 'package:flutter/material.dart';
class wlcPage extends StatelessWidget {
const wlcPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
height: double.infinity,
width: double.infinity,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('images/appBckgrd.jpg'),
fit: BoxFit.cover
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const CircleAvatar(
radius: 80,
backgroundImage: AssetImage("images/logo.png"),
),
Text('signhouse',
style: TextStyle(
fontFamily: 'OpenSans',
fontSize: 30,
fontWeight: FontWeight.normal,
letterSpacing: 1,
color: Colors.teal[700],
),
),
],
),
),
),
);
}
}
You can use the Future.delayed function to your advantage and make it wait for a couple of seconds and then use the Navigator.push() to show your other page.
Please try below plugin to display logo and different style of text when app opens up. The duration property sets delay between the splash screen and target screen. Provider Duration in millisecond.
splash_screen_view: ^3.0.0
You can also try below code (without use of plugin) example with Timer to pause the screen for sometime
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Splash Screen',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: MyHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
Timer(Duration(seconds: 3),
()=>Navigator.pushReplacement(context,
MaterialPageRoute(builder:
(context) =>
SecondScreen()
)
)
);
}
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child:FlutterLogo(size:MediaQuery.of(context).size.height)
);
}
}
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title:Text("Data")),
body: Center(
child:Text("Home page",textScaleFactor: 2,)
),
);
}
}
I am building an app that uses lots of images and I was wondering if there is a way to get rid of the time it takes for the image to load and show up on screen when the image is being called? Here is a simple example of an image that I want to be loaded that is contained inside of a visibility widget.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool isVis = false;
Widget _showAssetImage() {
return Visibility(
visible: isVis,
child: Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.amber,
image: DecorationImage(image: AssetImage('deer.jpg'))),
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text('test app'),
),
body: _showAssetImage(),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.image),
onPressed: () {
setState(() {
isVis = true;
});
},
),
);
}
}
you can try precacheImage():
final theImage = Image.asset("deer.jpg");
#override
void didChangeDependencies() {
precacheImage(theImage.image, context);
super.didChangeDependencies();
}
use it with:
Container(
width: 100,
height: 100,
child: theImage,
),
Animations created with Flare Flutter (from 2dimensions.com) cannot switch between different animations of the same Flare Actor. If a black version is first, the white version will not display; if the white version is first, the black will display.
I am not sure if I am doing something wrong or if it is a bug. It can switch between colors, just not animations.
import 'package:flutter/material.dart';
import 'package:flare_flutter/flare_actor.dart';
const List<String> animations = ['White', 'Black'];
const List<Color> colors = [Colors.blue, Colors.black];
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Animation Tester',
debugShowCheckedModeBanner: false,
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Animation Tester'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int index = 0;
void switchAnimation() {
setState(() {
index = index < (animations.length - 1) ? index + 1 : 0;
});
}
#override
Widget build(BuildContext context) {
print(index);
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: ListView(
children: <Widget>[
GestureDetector(
onTap: switchAnimation,
child: Icon(
Icons.add,
size: 100.0,
)),
Container(
width: 200.0,
height: 200.0,
child: FlareActor(
'assets/color_wheel_loading.flr',
color: colors[index],
)),
Container(
width: 200.0,
height: 200.0,
child: FlareActor(
'assets/color_wheel_loading.flr',
animation: animations[index],
)),
Center(child: Text('$index'))
],
)),
);
}
}
I have tested your code with my own file, it works perfect. May be your animation names are not right, can you check.
Or you can test this file "https://www.2dimensions.com/a/whitewolfnegizzz/files/flare/pj" and using the code below.
import 'package:flutter/material.dart';
import 'package:flare_flutter/flare_actor.dart';
const List<String> animations = ['Build and Fade Out', 'Build'];
const List<Color> colors = [Colors.blue, Colors.black];
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Animation Tester',
debugShowCheckedModeBanner: false,
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Animation Tester'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int index = 0;
void switchAnimation() {
setState(() {
index = index < (animations.length - 1) ? index + 1 : 0;
});
}
#override
Widget build(BuildContext context) {
print(index);
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: ListView(
children: <Widget>[
GestureDetector(
onTap: switchAnimation,
child: Icon(
Icons.add,
size: 100.0,
)),
Container(
width: 200.0,
height: 200.0,
child: FlareActor(
'assets/color_wheel_loading.flr',
color: colors[index],
)),
Container(
width: 200.0,
height: 200.0,
child: FlareActor(
'assets/Pj.flr',
animation: animations[index],
)),
Center(child: Text('$index'))
],
)),
);
}
}
From what i observed, Flare animation names are case sensitive. If the animation names in the flare project are in lowercase, the animation property of your flare actor should also be in lowercase.
Add flr in assets.
initialize it in Pubsepec.yaml file
then add dependency of flare animation in pubsepec.yaml file
after this,
just use this code in your main file
Container(
height: MediaQuery.of(context).size.height *0.8,
child: FlareActor(
'assets/oncemore.flr',
animation: 'Celebrate Duplicate', // Check this, when you are downloading flr file from Flare 2D dimension website
fit: BoxFit.contain,
),
),
After this , Your Flare animation will work perfectly.