Is it possible to show an animation where the user clicked on the screen in flutter. I would like a small animated star to appear right where the user pressed on the screen.
I have this animation which for the moments just loops but i only want it to loop while the user presses the screen.
new Container(
alignment: Alignment(0.0, -1.0),
child: new Container(
height: 410.0,
child: FlareActor(
"assets/images/nyastar.flr",
animation: _animationName,
)
)
),
Source: https://stackoverflow.com/a/46566392/5882307
import 'package:flutter/material.dart';
class Demo extends StatefulWidget {
#override
MyHomePageState createState() => new MyHomePageState();
}
class MyHomePageState extends State<Demo> {
double posx = 100.0;
double posy = 100.0;
void onTapDown(BuildContext context, TapDownDetails details) {
final RenderBox box = context.findRenderObject();
final Offset localOffset = box.globalToLocal(details.globalPosition);
setState(() {
posx = localOffset.dx;
posy = localOffset.dy;
});
}
#override
Widget build(BuildContext context) {
return new GestureDetector(
onTapDown: (TapDownDetails details) => onTapDown(context, details),
child: new Stack(fit: StackFit.expand, children: <Widget>[
// Hack to expand stack to fill all the space. There must be a better
// way to do it.
new Container(color: Colors.white),
new Positioned(
child: Text('hello'), //your widget to be shown
left: posx,
top: posy,
)
]),
);
}
}
Related
I want to show a random picture everytime the user enters the page. I also have a Button (the red container with hovering) on this page, and when the user is hovering it, a new random picture shows, but it shouldn't change since the page was loaded. I think it has something to do with the setState(), but I don't know what to do. Code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:core';
import 'dart:math';
class Home2 extends StatefulWidget {
const Home2({Key? key}) : super(key: key);
#override
_Home2State createState() => _Home2State();
}
class _Home2State extends State<Home2> {
dynamic listCinematicImages = [
"assets/cinematic/1.jpg",
"assets/cinematic/2.jpg",
"assets/cinematic/3.jpg",
"assets/cinematic/4.jpg",
"assets/cinematic/5.jpg",
"assets/cinematic/6.jpg",
"assets/cinematic/7.jpg",
];
late Random rnd;
#override
bool isHoveringButton = false;
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Scaffold(
backgroundColor: Colors.black,
body: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: double.infinity,
width: size.width * 0.5,
alignment: Alignment.center,
child: InkWell(
onTap: () {
},
onHover: (hovering) {
setState(() => isHoveringButton = hovering);
},
child: Container(
height: 50,
width: 50,
color: Colors.red,
),
),
),
Container(
height: double.infinity,
width: size.width * 0.5,
child: img(),
),
],
),
);
}
Image img() {
int min = 0;
int max = listCinematicImages.length-1;
rnd = new Random();
int r = min + rnd.nextInt(max - min);
String image_name = listCinematicImages[r].toString();
return Image.asset(image_name, fit: BoxFit.cover,);
}
}
I dont know if this helps but this is some error given out:
Error: Expected a value of type 'Map<String, dynamic>', but got one of type 'Null'
at Object.throw_ [as throw] (http://localhost:60569/dart_sdk.js:5054:11)
at Object.castError (http://localhost:60569/dart_sdk.js:5013:15)
at Object.cast [as as] (http://localhost:60569/dart_sdk.js:5336:17)
at Function.as_C [as as] (http://localhost:60569/dart_sdk.js:4959:19)
alright there's a lot a things going on here. Let's think about this step by step. You're trying to show a new image on certain events. So we need to create a variable to keep track of the current image:
class Home2 extends StatefulWidget {
const Home2({Key? key}) : super(key: key);
#override
_Home2State createState() => _Home2State();
}
class _Home2State extends State<Home2> {
static const listCinematicImages = [
"assets/cinematic/1.jpg",
"assets/cinematic/2.jpg",
"assets/cinematic/3.jpg",
"assets/cinematic/4.jpg",
"assets/cinematic/5.jpg",
"assets/cinematic/6.jpg",
"assets/cinematic/7.jpg",
];
late String currentImage;
}
before we start worrying about the events, let's figure out how to select a random image from your list. the function you provided has the right elements but there's some funky stuff going on. a simple example I'd give is:
String _getRandomImage() {
final randomIndex = Random().nextInt(listCinematicImages.length-1);
return listCinematicImages[randomIndex];
}
now we have all the elements, we just have to update the widget at the correct time. firstly you want to set a new image every time this widget is loaded. we can do this using the initState method:
#override
void initState() {
super.initState();
final newImage = _getRandomImage();
setState(() => currentImage = newImage);
}
and you want to change the image again when a user hovers over the image. You can indeed do this with an InkWell but keep in mind according to the documentation the onHover will provide a callback every time a mouse enters AND leaves the region, so we have to make sure to only update the image when we enter the region:
InkWell(
onHover: (bool hasEntered) {
if(!hasEntered) return;
final newImage = _getRandomImage();
setState(() => currentImage = newImage);
}
);
And that's it! to put it all together with your example:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:core';
import 'dart:math';
class Home2 extends StatefulWidget {
const Home2({Key? key}) : super(key: key);
#override
_Home2State createState() => _Home2State();
}
class _Home2State extends State<Home2> {
static const listCinematicImages = [
"assets/cinematic/1.jpg",
"assets/cinematic/2.jpg",
"assets/cinematic/3.jpg",
"assets/cinematic/4.jpg",
"assets/cinematic/5.jpg",
"assets/cinematic/6.jpg",
"assets/cinematic/7.jpg",
];
late String currentImage;
#override
void initState() {
super.initState();
final newImage = _getRandomImage();
setState(() => currentImage = newImage);
}
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Scaffold(
backgroundColor: Colors.black,
body: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: double.infinity,
width: size.width * 0.5,
alignment: Alignment.center,
child: InkWell(
onHover: (bool hasEntered) {
if(!hasEntered) return;
final newImage = _getRandomImage();
setState(() => currentImage = newImage);
},
child: Container(
height: 50,
width: 50,
color: Colors.red,
),
),
),
Container(
height: double.infinity,
width: size.width * 0.5,
child: Image.asset(currentImage, fit: BoxFit.cover,);,
),
],
),
);
}
String _getRandomImage() {
final randomIndex = Random().nextInt(listCinematicImages.length-1);
return listCinematicImages[randomIndex];
}
}
I am quite new to app development and I had a few questions about Flutter I was hoping someone could help me with!
First, I am trying to code an intro-slide part in my code. I have found this code online (https://flutterawesome.com/simple-and-configurable-app-introduction-slider-for-flutter/) and when I tried executing it, using my own images, only the background color seems to print. When I remove the background colors, it is just a white screen. Is my pageImage part correct? I saved an assert folder everywhere, so I'm unsure if that is the problem. I have included my code at the end.
Thank you for your time!
class _MyHomePageState extends State<MyHomePage> {
List<Slide> slides = new List();
#override
void initState() {
super.initState();
slides.add(
new Slide(
title: "ERASER",
description: "Allow miles wound place the leave had. To sitting subject no improve studied limited",
pathImage: "assets/images/1.png",
backgroundColor: Colors.pink[200],
),
);
slides.add(
new Slide(
title: "PENCIL",
description: "Ye indulgence unreserved connection alteration appearance",
pathImage: "assets/images/1.png",
backgroundColor: Colors.blue[200],
),
);
slides.add(
new Slide(
title: "RULER",
description:
"Much evil soon high in hope do view. Out may few northward believing attempted. Yet timed being songs marry one defer men our. Although finished blessing do of",
pathImage: "assets/images/3.jpg",
),
);
}
void onDonePress() {
// TODO: go to next screen
}
void onSkipPress() {
// TODO: go to next screen
}
#override
Widget build(BuildContext context) {
return new IntroSlider(
slides: this.slides,
onDonePress: this.onDonePress,
onSkipPress: this.onSkipPress,
);
}
}
**Solution: edit assets in pubspec page
Edit:
On the left (the orange part) is how I want the blue image to appear: No scrolling and fills the whole page. However, I tried to make my image (on the right) fill the page by editing the width and height and I started having to scroll where there is the pink background below and above the image (I assume it is because it keeps having to center the image).
Is there any way to make my image my background so it is like the picture on the left? I understand the orange color background is the background color, but hopefully, by comparing the two it makes sense. Thank you!
I create new intro widget. Here is the code.
import 'package:flutter/material.dart';
class MyIntroView extends StatefulWidget {
final List<Widget> pages;
final VoidCallback onIntroCompleted;
const MyIntroView({
Key key,
#required this.pages,
#required this.onIntroCompleted,
}) : assert(pages != null),
assert(onIntroCompleted != null),
super(key: key);
#override
_MyIntroViewState createState() => _MyIntroViewState();
}
class _MyIntroViewState extends State<MyIntroView> {
PageController _pageController;
int _currentPage = 0;
#override
void initState() {
_pageController = PageController(
initialPage: _currentPage,
);
super.initState();
}
#override
void dispose() {
_pageController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
NotificationListener<ScrollEndNotification>(
onNotification: (x) {
setState(() {
_currentPage = _pageController.page.round();
});
return false;
},
child: PageView(
children: widget.pages,
controller: _pageController,
),
),
Align(
alignment: Alignment.bottomCenter,
child: _buildBottomButtons(),
),
],
);
}
bool get _isFinalPage => _currentPage == widget.pages.length - 1;
Widget _buildBottomButtons() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Opacity(
opacity: _isFinalPage ? 0.0 : 1.0,
child: _buildButton("SKIP", _gotoLastPage),
),
_buildNavIndicator(),
_isFinalPage
? _buildButton("DONE", widget.onIntroCompleted)
: _buildButton("NEXT", _gotoNextPage),
],
),
);
}
Widget _buildButton(String title, VoidCallback callback) {
return FlatButton(
child: Text(
title,
style: TextStyle(color: Colors.white),
),
onPressed: callback,
);
}
void _gotoLastPage() {
_pageController.animateToPage(
widget.pages.length - 1,
duration: const Duration(milliseconds: 600),
curve: Curves.ease,
);
}
void _gotoNextPage() {
_pageController.nextPage(
duration: const Duration(milliseconds: 600),
curve: Curves.easeInOut,
);
}
Widget _buildNavIndicator() {
final indicatorList = <Widget>[];
for (int i = 0; i < widget.pages.length; i++)
indicatorList.add(_buildIndicator(i == _currentPage));
return Row(children: indicatorList);
}
Widget _buildIndicator(bool isActive) {
return Padding(
padding: const EdgeInsets.all(5.0),
child: DecoratedBox(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: isActive ? Colors.white : Colors.white30,
),
child: SizedBox(width: 8, height: 8),
),
);
}
}
Usage:
import 'package:flutter/material.dart';
import 'package:flutter_app_test3/my_intro_view.dart';
Future<void> main() async {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MyIntroView(
pages: <Widget>[
Image.asset("assets/images/1.png", fit: BoxFit.cover),
Image.asset("assets/images/2.png", fit: BoxFit.cover),
Image.asset("assets/images/3.jpg", fit: BoxFit.cover),
],
onIntroCompleted: () {
print("Into is Completed");
//To the navigation stuff here
},
);
}
}
Ask me if you have any doubts in the comment
just try wrapping your Widget into Scaffold Widget and return
#override
Widget build(BuildContext context) {
return Scaffold(body:IntroSlider(
slides: this.slides,
onDonePress: this.onDonePress,
onSkipPress: this.onSkipPress,
));
}
I was facing the same issue and I fixed it by setting fit:Boxfit.fill for the image.
I'm trying to implement a scrollable background image (parallax).
Like in a home screen launcher.
An example:
In Evie launcher:
this video
I've tried using AnimatedBuilder mentioned here in the docs like this.
I'm using a ValueNotifier<double> as the listener for the animation of the AnimatedBuilder Widget.
The complete code is this
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'PageView Scrolling',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>{
ValueNotifier<double> _notifier;
double _prevnotifier;
double getOffset(){
if (_notifier.value == 0 && _prevnotifier != null){
return _prevnotifier;
}
return _notifier.value;
}
#override
void dispose() {
_notifier?.dispose();
super.dispose();
}
#override
void initState() {
super.initState();
_notifier = ValueNotifier<double>(0);
_prevnotifier = _notifier.value;
_notifier.addListener(
(){
print('object ${_notifier.value}');
if (_notifier.value != 0)
_prevnotifier = _notifier.value;
}
);
}
#override
Widget build(BuildContext context) {
print("Size is ${MediaQuery.of(context).size}");
return Scaffold(
body: Stack(
children: <Widget>[
AnimatedBuilder(
animation: _notifier,
builder: (context, _) {
return Transform.translate(
offset: Offset(-getOffset() * 60, 0),
child: Image.network(
"https://w.wallhaven.cc/full/r2/wallhaven-r276qj.png",
height: MediaQuery.of(context).size.height,
fit: BoxFit.fitHeight
),
);
},
),
NotifyingPageView(
notifier: _notifier,
),
],
),
);
}
}
class NotifyingPageView extends StatefulWidget {
final ValueNotifier<double> notifier;
const NotifyingPageView({Key key, this.notifier}) : super(key: key);
#override
_NotifyingPageViewState createState() => _NotifyingPageViewState();
}
class _NotifyingPageViewState extends State<NotifyingPageView> {
int _previousPage;
PageController _pageController;
void _onScroll() {
// Consider the page changed when the end of the scroll is reached
// Using onPageChanged callback from PageView causes the page to change when
// the half of the next card hits the center of the viewport, which is not
// what I want
if (_pageController.page.toInt() == _pageController.page) {
_previousPage = _pageController.page.toInt();
}
widget.notifier?.value = _pageController.page - _previousPage;
}
#override
void initState() {
_pageController = PageController(
initialPage: 0,
viewportFraction: 0.9,
)..addListener(_onScroll);
_previousPage = _pageController.initialPage;
super.initState();
}
List<Widget> _pages = List.generate(
10,
(index) {
return Container(
height: 10,
alignment: Alignment.center,
color: Colors.transparent,
child: Text(
"Card number $index",
style: TextStyle(
color: Colors.teal,
fontWeight: FontWeight.bold,
fontSize: 25,
),
),
);
},
);
#override
Widget build(BuildContext context) {
return PageView(
children: _pages,
controller: _pageController,
);
}
}
The image can be found here
Now I have two issues:
The image when using fit: BoxFit.fitHeight is not overflowing fully. It's currently like this
Because the value will become zero when the animation is done it's snapping like this:
this video
I tried storing the value just before the _notifier.value becomes zero and use it when it returns zero but it resulted in that weird transition that I've shown you in that above video.
What do you suggest can be done to make something like a scrollable wallpaper in flutter?
Something like this
Design
This is not as trivial as I thought it would be.
TLDR; Github read the comments.
I used a ValueNotifier<double> like I mentioned to control the scroll.
Then instead of Transform.translate I used an OverflowBox with its alignment property. Which is computed based on the notifier.value before rendering.
And to display the image in fullscreen mode:
I used AspectRatio with a child DecoratedBox whose decoration is a BoxDecoration with its image as an ImageProvider.
All the code can be found here on github. (Read the comments)
And this issue on github has slightly detailed info and a less complicated alternate implementation by Antonello Galipò
I have made one container with scale transition which grows from 0 height and width to 90 height and width.
Now what,I wanted to do is it should slowly fade out as it grows.Do i need to create another animation controller for opacity ? what is the best way to do it ? Can Some one Help?
My Code Look Like This
import 'package:flutter/animation.dart';
import 'package:flutter/material.dart';
void main() => runApp(new MyAnimationApp());
class MyAnimationApp extends StatefulWidget {
#override
_MyAnimationAppState createState() => _MyAnimationAppState();
}
class _MyAnimationAppState extends State<MyAnimationApp>
with TickerProviderStateMixin {
Animation<double> animation;
AnimationController _controller;
#override
void initState() {
super.initState();
_controller =
new AnimationController(vsync: this, duration: Duration(seconds: 3))
..repeat();
animation = new CurvedAnimation(parent: _controller, curve: Curves.linear);
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
body: new Container(
child: new Center(
child: new ScaleTransition(
scale: animation,
child: new Container(
decoration: new BoxDecoration(
color: Color(0XFFEC3457), shape: BoxShape.circle),
height: 90.0,
width: 90.0,
),
),
),
),
),
);
}
}
SS is here
Thanks !!! Hoping for a reply ......
You'd need to add a double value to your code:
double _opacity = 1;
And a listener for your animation controller at the end of the initState
_controller.addListener(() {
setState(() {
_opacity = 1 - _controller.value;
});
});
And on your widget tree, you can add this:
ScaleTransition(
scale: animation,
child: Opacity(
opacity: _opacity,
child: Container(
I've got a SlideAnimation on an object that get's triggered every time I tap the screen. The object simply slides up atm but when I tap the screen again the animation starts from the original position of the object again. How would I capture the position the object ended in the last animation and perform the animation from there on?
I've got the following code for the creating of the SlideTransition:
new SlideTransition(
child: new Container(
child: char,
),
position: _characterPosition,
)
And this code for the actual animation:
_characterPosition = new FractionalOffsetTween(
begin: const FractionalOffset(0.0, 0.0),
end: const FractionalOffset(0.0, -0.2),
).animate(new CurvedAnimation(
parent: _characterAnimationController,
curve: Curves.easeOut,
)
);
In the simplest case you can use your _characterAnimationController. AnimationController has two related methods stop and forward. Verify current animation's state and invoke required method:
void _onTap() {
if (_characterAnimationController.isAnimating) {
_characterAnimationController.stop(canceled: false);
} else {
_characterAnimationController.forward();
}
}
To extend animation after completion you can reset _characterAnimationController state via value(or create new one) and update position. Complete example:
class Home extends StatefulWidget {
#override
State createState() => new _HomeState();
}
class _HomeState extends State<Home> with TickerProviderStateMixin {
Animation _characterPosition;
AnimationController _characterAnimationController;
FractionalOffset _beginOffset;
FractionalOffset _endOffset;
FractionalOffset _animationOffset;
void _restartAnimation() {
_characterAnimationController.value = 0.0;
_beginOffset = _endOffset;
_endOffset = _endOffset + _animationOffset;
setState(() {
_characterPosition = _generateCharacterPosition();
});
_characterAnimationController.forward();
}
#override
void initState() {
_animationOffset = const FractionalOffset(0.0, 0.15);
_beginOffset = const FractionalOffset(0.0, 0.0);
_endOffset = _animationOffset;
_characterAnimationController = new AnimationController(
duration: new Duration(seconds: 5), vsync: this);
_characterPosition = _generateCharacterPosition();
}
#override
Widget build(BuildContext context) {
return new Material(
child: new InkWell(
child: new SlideTransition(
child: new Container(
child: new Text("Hello"),
),
position: _characterPosition,
),
onTap: _onTap,
),
);
}
void _onTap() {
if (_characterAnimationController.isAnimating) {
_characterAnimationController.stop(canceled: false);
} else if (_characterAnimationController.status ==
AnimationStatus.completed) {
_restartAnimation();
} else {
_characterAnimationController.forward();
}
}
Animation _generateCharacterPosition() => new FractionalOffsetTween(
begin: _beginOffset,
end: _endOffset,
)
.animate(new CurvedAnimation(
parent: _characterAnimationController,
curve: Curves.easeOut,
));
}