Flutter Web Mouse Region Widget Triggering - flutter

I am trying to get this result with Flutter;
I am having this behaviour;
Code;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:html' as html;
class OverlayAnimatedGridElement extends StatefulWidget {
OverlayAnimatedGridElement(this.imagepath, this.postDetail, this.postTitle);
final String imagepath;
final String postTitle;
final String postDetail;
#override
_OverlayAnimatedGridElementState createState() =>
_OverlayAnimatedGridElementState();
}
class _OverlayAnimatedGridElementState extends State<OverlayAnimatedGridElement>
with TickerProviderStateMixin {
AnimationController _controller;
Animation<double> _opacityTween;
bool isHovered = false;
#override
void initState() {
_controller =
AnimationController(vsync: this, duration: Duration(milliseconds: 500));
_opacityTween = Tween<double>(begin: 0, end: 1).animate(
CurvedAnimation(parent: _controller, curve: Curves.easeInOutCirc));
super.initState();
}
hoverActivation(hoverState) {
bool hoverState;
isHovered = hoverState;
if (isHovered = true) {
_controller.forward();
} else if (isHovered = false) {
_controller.reset();
}
print("activated");
}
#override
Widget build(BuildContext context) {
_opacityTween.addListener(() {
setState(() {
print(_opacityTween.value);
});
});
return MouseRegion(
onHover: hoverActivation(true),
child: Container(
constraints: BoxConstraints(maxHeight: 360, maxWidth: 640),
child: Stack(
alignment: Alignment.bottomCenter,
children: [
Image(image: AssetImage("${widget.imagepath}")),
Opacity(
opacity: _opacityTween.value,
child: Container(
color: Color.fromRGBO(128, 128, 128, 0.5),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
Text("${widget.postDetail}"),
Text("${widget.postTitle}")
],
),
],
),
),
),
],
),
),
);
}
}
A standalone widget works okay but when I put it into gridview or pageview it automatically reads it mouse entered when I scroll into it.
I tried to use other widgets like Inkwell, Listener and others. No solution. Can someone guide me if there is better solution?
How Can I solve this?
edit:
Now having this problem. MouseRegion causes multiple controller.forwards

I am Created an Example ... please Try this,
import 'package:flutter/material.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Todos',
theme: new ThemeData(primarySwatch: Colors.deepOrange),
home: MyHome(),
);
}
}
class MyHome extends StatelessWidget{
#override
Widget build(BuildContext context) {
return GridView.count(crossAxisCount: 3,
children: List.generate(10, (index) {
return OverlayAnimatedGridElement("https://picsum.photos/300/200");
}
));
}
}
class OverlayAnimatedGridElement extends StatefulWidget {
OverlayAnimatedGridElement(this.imagepath);
final String imagepath;
// final String postTitle;
// final String postDetail;
#override
_OverlayAnimatedGridElementState createState() =>
_OverlayAnimatedGridElementState();
}
class _OverlayAnimatedGridElementState extends State<OverlayAnimatedGridElement>
with TickerProviderStateMixin {
bool isHovered = false;
#override
void initState() {
super.initState();
}
hoverActivation(hoverState) {
setState(() {
isHovered = hoverState;
});
print("activated" + hoverState.toString());
}
#override
Widget build(BuildContext context) {
return Center(
child: Container(
color: Colors.red,
height: 200,
width: 300,
child: Stack(
children: [
Image.network(widget.imagepath),
MouseRegion(
onEnter: (event){
hoverActivation(true);
},
onExit: (event){
hoverActivation(false);
},
child: AnimatedContainer(
duration: Duration(milliseconds: 200),
color: Colors.black.withOpacity(isHovered ? 0.5 : 0),
),
)
],
),
),
);
}
}

I solved my second problem by just moving addListener method to initState. Previously it was inside widget itself which was causing adding listeners in every rebuild and causing multiple rebuilds for each listener, I guess.

Related

How to make soft keyboard appearance animation smooth?

I have 2 examples with code and GIF.
Problem with first - it is not working with appropriate height.
Problem with second - when soft keyboard appears it is not animated.
What is the appropriate way to make soft keyboard appearance on the screen smooth and clean, when you have to move some objects, according to new screen height?
GIFS:
Code first:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: Example()));
}
class Example extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Spacer(),
Container(
color: Colors.red,
child: TextField(),
),
],
),
);
}
}
Code second:
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
void main() {
runApp(MaterialApp(home: Example()));
}
class Example extends StatefulWidget {
#override
State<Example> createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
double height = 0;
FocusNode node = FocusNode();
#override
void initState() {
super.initState();
node.addListener(() {
if (height == 0) {
height = 320;
} else {
height = 0;
}
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Column(
children: [
Spacer(),
Container(
color: Colors.red,
child: TextField(
focusNode: node,
),
),
AnimatedContainer(
duration: Duration(milliseconds: 370),
curve: Curves.ease,
height: height,
),
],
),
);
}
}

How to add widget on tree using slide animation on onpressed flutter

I need to add widgets using slide animation into tree on an action done on onpressed
the parent widget will be a listview in which the childrens will be added in slide down animation
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Home(),
);
}
}
class Home extends StatefulWidget {
#override
State<StatefulWidget> createState() => HomeState();
}
class HomeState extends State<Home> with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<Offset> offset;
#override
void initState() {
super.initState();
controller =
AnimationController(vsync: this, duration: Duration(seconds: 1));
offset = Tween<Offset>(begin: Offset.zero, end: Offset(0.0, 1.0))
.animate(controller);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
Center(
child: RaisedButton(
child: Text('Show / Hide'),
onPressed: () {
switch (controller.status) {
case AnimationStatus.completed:
controller.reverse();
break;
case AnimationStatus.dismissed:
controller.forward();
break;
default:
}
},
),
),
Align(
alignment: Alignment.bottomCenter,
child: SlideTransition(
position: offset,
child: Padding(
padding: EdgeInsets.all(50.0),
child: CircularProgressIndicator(),
),
),
)
],
),
);
}
}

Flutter: Where I can add Text()

I want to tap on the screen, and change background color to random color. It works fine, but I want to add Text on the center of screen, help me please.
Maybe someone have ideas, Thank you!
I try to add multiple child to AnimatedContainer.
Tried to add text in GestureDetector, but it doesn't work correctly
TopScreen.dart
import 'package:flutter/material.dart';
class TopScreen extends StatefulWidget {
final Widget child; //child widget
TopScreen({this.child});
#override
State createState() => _TopScreenState();
static _TopScreenState of (BuildContext context) {
assert(context != null);
final _TopScreenState result = context.findAncestorStateOfType();
return result;
}
}
class _TopScreenState extends State<TopScreen> {
Color _color = Colors.white;
#override
Widget build(BuildContext context) {
return Scaffold(
body: AnimatedContainer(
child: widget.child,
color: _color,
duration: Duration(milliseconds: 500),
),
);
}
void setColor(Color color) {
this._color = color;
}
}
main.dart
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:solidsoftwaretest/TopScreen.dart';
void main() => runApp(MaterialApp(home: TopScreen(child: MainScreen())));
class MainScreen extends StatefulWidget {
#override
State createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
TopScreen.of(context).setColor(Colors.primaries[Random().nextInt(Colors.primaries.length)]);
TopScreen.of(context).setState(() {});
},
);
} //build
}
UPD: if I add Child (Text) to GestureDetector - gestureDetector works only on Text.
class _MainScreenState extends State<MainScreen> {
#override
Widget build(BuildContext context) {
return GestureDetector(
child: Center(
child: Text('Hey there!')
),
onTap: () {
TopScreen.of(context).setColor(Colors.primaries[Random().nextInt(Colors.primaries.length)]);
TopScreen.of(context).setState(() {});
}
);
} //build
}
You can add Text widget inside a Container & wrap it further in GestureDetector. In order to make GestureDetector work on the whole area, give the Container a transparent color as follows:
return GestureDetector(
onTap: () {
TopScreen.of(context).setColor(Colors.primaries[Random().nextInt(Colors.primaries.length)]);
TopScreen.of(context).setState(() {});
},
child: Container(
color: Colors.transparent,
alignment: Alignment.center,
child: Text('Hey there'),
),
);
Hope, it will help
You should be able to put a Column inside your AnimatedContainer. The Column will hold multiple Widgets.
I've updated the code to show the full example.
ScaffoldColorCenterText60597839(
child: Text('Bananas'),
)
class ScaffoldColorCenterText60597839 extends StatefulWidget {
final Widget child;
ScaffoldColorCenterText60597839({
this.child
});
#override
_ScaffoldColorCenterText60597839State createState() => _ScaffoldColorCenterText60597839State();
}
class _ScaffoldColorCenterText60597839State extends State<ScaffoldColorCenterText60597839> {
Color _color = Colors.white;
#override
Widget build(BuildContext context) {
return Scaffold(
body: AnimatedContainer(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
widget.child,
Text('A text widget')
],
)
),
color: _color,
duration: Duration(milliseconds: 500),
),
);
}
}

Starting An Animation When A Button Is Pressed - Flutter

I'm new to flutter and I'm trying to create a UI in which there is a card deck and a displayed card. Whenever the user presses on the card deck I want a new Card to show up (using an animation of flipping and moving with Positioned widget).
The thing is, I can't understand how to make the animation appear every time the widget is created.
I tried to make the animation go on the init state of the widget I created, but that doesn't seem to work.
This is the app widget tree:
class _DeckState extends State<Deck> with TickerProviderStateMixin {
List<MyCard> _cards= <MyCard>[];
#override
void initState() {
super.initState();
_cards.insert(0, MyCard());
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("NLP Deck"),
),
body: Stack(
alignment: Alignment.center,
children: <Widget>[
Container(),
_cards[0],
Positioned(
top: 40.0,
child: GestureDetector(
onTap: PressedDeck,
child: Container(
width: 100.0,
height: 128.0,
decoration: BoxDecoration(color: Colors.brown),
),
),
),
],
),
);
}
void PressedDeck() {
setState(() {
_cards.insert(0, new MyCard());
});
}
}
And this is the Card widget I created (used Containers to represent the card and the card deck):
class _CardState extends State<MyCard> with TickerProviderStateMixin {
AnimationController animController;
Animation flipAnimation;
Animation positionAnimation;
#override
void initState() {
super.initState();
animController = new AnimationController(
vsync: this, duration: Duration(milliseconds: 1000));
flipAnimation = Tween<double>(begin: 1.0, end: 0).animate(animController);
positionAnimation =
Tween<double>(begin: 40.0, end: 240.0).animate(animController);
animController.forward();
}
#override
Widget build(BuildContext context) {
return PositionTransition(
position: positionAnimation,
flip: flipAnimation,
);
}
#override
void dispose() {
animController.dispose();
super.dispose();
}
}
class PositionTransition extends AnimatedWidget {
PositionTransition({
#required Animation<double> position,
#required this.flip,
}) : super(listenable: position);
final Animation<double> flip;
#override
Widget build(BuildContext context) {
final position = super.listenable as Animation<double>;
return Positioned(
top: position.value,
child: Transform(
alignment: FractionalOffset.center,
transform: Matrix4.rotationX(math.pi * flip.value),
child: flip.value >= 0.5
? Container(
width: 100,
height: 128,
decoration: BoxDecoration(color: Colors.deepOrange),
)
: Container(
width: 100,
height: 128,
decoration: BoxDecoration(color: Colors.amber),
),
),
);
}
}
Thanks!
You can copy paste run full code below
You can call animController.reset() and forward() in didUpdateWidget
For demo purpose, I change animation duration to 3 seconds
for detail you can reference https://medium.com/sk-geek/flutter-experiment-to-trigger-animation-when-parent-setstate-84e949530b64
code snippet
#override
void didUpdateWidget(MyCard oldWidget) {
animController.reset();
animController.forward();
super.didUpdateWidget(oldWidget);
}
working demo
full code
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',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Deck(),
);
}
}
class Deck extends StatefulWidget {
#override
_DeckState createState() => _DeckState();
}
class _DeckState extends State<Deck> with TickerProviderStateMixin {
List<MyCard> _cards = <MyCard>[];
#override
void initState() {
super.initState();
_cards.insert(0, MyCard());
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("NLP Deck"),
),
body: Stack(
alignment: Alignment.center,
children: <Widget>[
Container(),
_cards[0],
Positioned(
top: 40.0,
child: GestureDetector(
onTap: PressedDeck,
child: Container(
width: 100.0,
height: 128.0,
decoration: BoxDecoration(color: Colors.brown),
),
),
),
],
),
);
}
void PressedDeck() {
print("PressedDeck");
setState(() {
_cards.insert(0, new MyCard());
});
print("cards length ${_cards.length}");
}
}
class MyCard extends StatefulWidget {
#override
_MyCardState createState() => _MyCardState();
}
class _MyCardState extends State<MyCard> with TickerProviderStateMixin {
AnimationController animController;
Animation flipAnimation;
Animation positionAnimation;
#override
void initState() {
print("My card init State");
super.initState();
animController =
new AnimationController(vsync: this, duration: Duration(seconds: 3));
flipAnimation = Tween<double>(begin: 1.0, end: 0).animate(animController);
positionAnimation =
Tween<double>(begin: 40.0, end: 240.0).animate(animController);
animController.forward();
}
#override
void didUpdateWidget(MyCard oldWidget) {
animController.reset();
animController.forward();
super.didUpdateWidget(oldWidget);
}
#override
Widget build(BuildContext context) {
return PositionTransition(
position: positionAnimation,
flip: flipAnimation,
);
}
#override
void dispose() {
animController.dispose();
super.dispose();
}
}
class PositionTransition extends AnimatedWidget {
PositionTransition({
#required Animation<double> position,
#required this.flip,
}) : super(listenable: position);
final Animation<double> flip;
#override
Widget build(BuildContext context) {
final position = super.listenable as Animation<double>;
return Positioned(
top: position.value,
child: Transform(
alignment: FractionalOffset.center,
transform: Matrix4.rotationX(math.pi * flip.value),
child: flip.value >= 0.5
? Container(
width: 100,
height: 128,
decoration: BoxDecoration(color: Colors.deepOrange),
)
: Container(
width: 100,
height: 128,
decoration: BoxDecoration(color: Colors.amber),
),
),
);
}
}

how to animate collapse elements in flutter

How can i expand and collapse widget when user taps on different widget ( sibling or parent ) with animation ?
new Column(
children: <Widget>[
new header.IngridientHeader(
new Icon(
Icons.fiber_manual_record,
color: AppColors.primaryColor
),
'Voice Track 1'
),
new Grid()
],
)
I want user to be able to tap on header.IngridientHeader and then Grid widget should toggle ( hide if visible and other way around )
edit:
im trying to do something that in bootstrap is called Collapse. getbootstrap.com/docs/4.0/components/collapse
edit 2:
header.IngridientHeader should stay in place all the time
Grid() is scrollable ( horizontal ) widget.
If you want to collapse a widget to zero height or zero width that has a child that overflow when collapsed, I would recommend SizeTransition or ScaleTransition.
Here is an example of the ScaleTransition widget being used to collapse the container for the four black buttons and status text. My ExpandedSection widget is used with a column to get the following structure.
An example of a Widget that use animation with the SizeTransition widget:
class ExpandedSection extends StatefulWidget {
final Widget child;
final bool expand;
ExpandedSection({this.expand = false, this.child});
#override
_ExpandedSectionState createState() => _ExpandedSectionState();
}
class _ExpandedSectionState extends State<ExpandedSection> with SingleTickerProviderStateMixin {
AnimationController expandController;
Animation<double> animation;
#override
void initState() {
super.initState();
prepareAnimations();
_runExpandCheck();
}
///Setting up the animation
void prepareAnimations() {
expandController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 500)
);
animation = CurvedAnimation(
parent: expandController,
curve: Curves.fastOutSlowIn,
);
}
void _runExpandCheck() {
if(widget.expand) {
expandController.forward();
}
else {
expandController.reverse();
}
}
#override
void didUpdateWidget(ExpandedSection oldWidget) {
super.didUpdateWidget(oldWidget);
_runExpandCheck();
}
#override
void dispose() {
expandController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return SizeTransition(
axisAlignment: 1.0,
sizeFactor: animation,
child: widget.child
);
}
}
AnimatedContainer also works but Flutter can complain about overflow if the child is not resizable to zero width or zero height.
Alternatively you can just use an AnimatedContainer to mimic this behavior.
class AnimateContentExample extends StatefulWidget {
#override
_AnimateContentExampleState createState() => new _AnimateContentExampleState();
}
class _AnimateContentExampleState extends State<AnimateContentExample> {
double _animatedHeight = 100.0;
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text("Animate Content"),),
body: new Column(
children: <Widget>[
new Card(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new GestureDetector(
onTap: ()=>setState((){
_animatedHeight!=0.0?_animatedHeight=0.0:_animatedHeight=100.0;}),
child: new Container(
child: new Text("CLICK ME"),
color: Colors.blueAccent,
height: 25.0,
width: 100.0,
),),
new AnimatedContainer(duration: const Duration(milliseconds: 120),
child: new Text("Toggle Me"),
height: _animatedHeight,
color: Colors.tealAccent,
width: 100.0,
)
],
) ,
)
],
),
);
}
}
I think you are looking for ExpansionTile widget. This takes a title property which is equivalent to header and children property to which you can pass widgets to be shown or hidden on toggle.
You can find an example of how to use it here.
Simple Example Usage:
new ExpansionTile(title: new Text("Numbers"),
children: <Widget>[
new Text("Number: 1"),
new Text("Number: 2"),
new Text("Number: 3"),
new Text("Number: 4"),
new Text("Number: 5")
],
),
Hope that helps!
Output:
Code:
class FooPageState extends State<SoPage> {
static const _duration = Duration(seconds: 1);
int _flex1 = 1, _flex2 = 2, _flex3 = 1;
#override
Widget build(BuildContext context) {
final total = _flex1 + _flex2 + _flex3;
final height = MediaQuery.of(context).size.height;
final height1 = (height * _flex1) / total;
final height2 = (height * _flex2) / total;
final height3 = (height * _flex3) / total;
return Scaffold(
body: Column(
children: [
AnimatedContainer(
height: height1,
duration: _duration,
color: Colors.red,
),
AnimatedContainer(
height: height2,
duration: _duration,
color: Colors.green,
),
AnimatedContainer(
height: height3,
duration: _duration,
color: Colors.blue,
),
],
),
);
}
}
Thanks to #Adam Jonsson, his answer resolved my problem. And this is the demo about how to use ExpandedSection, hope to help you.
class ExpandedSection extends StatefulWidget {
final Widget child;
final bool expand;
ExpandedSection({this.expand = false, this.child});
#override
_ExpandedSectionState createState() => _ExpandedSectionState();
}
class _ExpandedSectionState extends State<ExpandedSection>
with SingleTickerProviderStateMixin {
AnimationController expandController;
Animation<double> animation;
#override
void initState() {
super.initState();
prepareAnimations();
_runExpandCheck();
}
///Setting up the animation
void prepareAnimations() {
expandController =
AnimationController(vsync: this, duration: Duration(milliseconds: 500));
animation = CurvedAnimation(
parent: expandController,
curve: Curves.fastOutSlowIn,
);
}
void _runExpandCheck() {
if (widget.expand) {
expandController.forward();
} else {
expandController.reverse();
}
}
#override
void didUpdateWidget(ExpandedSection oldWidget) {
super.didUpdateWidget(oldWidget);
_runExpandCheck();
}
#override
void dispose() {
expandController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return SizeTransition(
axisAlignment: 1.0, sizeFactor: animation, child: widget.child);
}
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(
title: Text('Demo'),
),
body: Home(),
),
);
}
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
bool _expand = false;
#override
Widget build(BuildContext context) {
return Column(
children: [
Header(
onTap: () {
setState(() {
_expand = !_expand;
});
},
),
ExpandedSection(child: Content(), expand: _expand,)
],
);
}
}
class Header extends StatelessWidget {
final VoidCallback onTap;
Header({#required this.onTap});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
color: Colors.cyan,
height: 100,
width: double.infinity,
child: Center(
child: Text(
'Header -- Tap me to expand!',
style: TextStyle(color: Colors.white, fontSize: 20),
),
),
),
);
}
}
class Content extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.lightGreen,
height: 400,
);
}
}
Another solution that doesn't require an animation controller is using AnimatedSwitcher widget with SizeTransition as a transition builder.
here is a simple example:
AnimatedSwitcher(
duration: Duration(milliseconds: 300),
transitionBuilder: (child, animation) {
return SizeTransition(sizeFactor: animation, child: child);
},
child: expanded ? YourWidget() : null,
)
Of course you can customize the curve and layout builder for the animation.