I spent few hours trying to understand why clicking on the IconButton does not toggle change its icon.
import 'package:flutter/material.dart';
import 'dart:core';
class TestIconChange extends StatefulWidget {
#override
_TestIconChangeState createState() => _TestIconChangeState();
}
class _TestIconChangeState extends State<TestIconChange>
with TickerProviderStateMixin {
IconData _iconData = Icons.add;
AnimationController _animationController1;
Widget _child;
#override
void initState() {
super.initState();
_animationController1 = AnimationController(
vsync: this,
value: 1,
duration: Duration(seconds: 1),
);
}
#override
Widget build(BuildContext context) {
if (_child == null) _child = _buildButton();
return Scaffold(
body: Container(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
AnimatedSwitcher(
duration: Duration(milliseconds: 100),
child: _child,
),
RaisedButton(
child: Text('Text Child'),
onPressed: (() {
setState(() {
_child = Text('Dummy text');
});
}),
),
RaisedButton(
child: Text('Button Child'),
onPressed: (() {
setState(() {
_child =_buildButton();
},);
}),
)
],
),
),
),
);
}
Widget _buildButton() {
return IconButton(
onPressed: () {
setState(() {
(_iconData == Icons.add)
? _iconData = Icons.remove
: _iconData = Icons.add;
});
},
icon: Icon(_iconData),
);
}
}
When you call setState it rebuild only Widgets that build in build method.
The main problem was that you didn't do it. You didn't rebuild _child in build method.
This line in your code wrong: if (_child == null) _child = _buildButton();
If you make it like this _child = _buildButton(); then work only button +/-, but not works change to text. Need refactoring of your code!
So, I made refactoring of your code and add ChildType that indicate what type of Widget you want to show: text or button. And then use it in setState method. Now it works, as you expected :)
import 'package:flutter/material.dart';
import 'dart:core';
class TestIconChange extends StatefulWidget {
#override
_TestIconChangeState createState() => _TestIconChangeState();
}
enum ChildType {text, button}
class _TestIconChangeState extends State<TestIconChange>
with TickerProviderStateMixin {
ChildType curChildType = ChildType.button;
IconData _iconData = Icons.add;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
AnimatedSwitcher(
duration: Duration(milliseconds: 100),
child: _buildButton(),
),
RaisedButton(
child: Text('Text Child'),
onPressed: (() {
setState(() {
curChildType = ChildType.text;
});
}),
),
RaisedButton(
child: Text('Button Child'),
onPressed: (() {
setState(() {
curChildType = ChildType.button;
},);
}),
)
],
),
),
);
}
Widget _buildButton() {
if (curChildType == ChildType.text) {
return Text('Dummy text');
}
else {
return IconButton(
icon: Icon(_iconData),
onPressed: () {
setState(() {
_iconData = (_iconData == Icons.add) ? Icons.remove : _iconData = Icons.add;
});
},
);
}
}
}
Good Luck!
Related
Iam trying to make a flutter windows application that can connect to a scanner device and get the image data from it, but i can't seem to find any packages that help with that so if anyone can give me the link of a library or a tutorial that can help with that.
Thanks in advance.
i have tried searching but all the packages i have found are directed to android and ios only.
Is this what you want?
I've ported the C++ code from https://github.com/twain/twain-samples and created an open source project https://github.com/yushulx/flutter_twain_scanner.
The plugin is available on https://pub.dev/packages/flutter_twain_scanner
The full code to scan documents from a connected scanner on Windows desktop:
import 'dart:io';
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter_twain_scanner/flutter_twain_scanner.dart';
import 'dart:ui' as ui;
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown';
final _flutterTwainScannerPlugin = FlutterTwainScanner();
String? _documentPath;
List<String> _scanners = []; // Option 2
String? _selectedScanner;
#override
void initState() {
super.initState();
initPlatformState();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
// We also handle the message potentially returning null.
try {
platformVersion = await _flutterTwainScannerPlugin.getPlatformVersion() ??
'Unknown platform version';
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Flutter TWAIN Scanner'),
),
body: Stack(
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(
height: 100,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
MaterialButton(
textColor: Colors.white,
color: Colors.blue,
onPressed: () async {
List<String>? scanners =
await _flutterTwainScannerPlugin
.getDataSources();
if (scanners != null) {
setState(() {
_scanners = scanners;
});
}
},
child: const Text('List Scanners')),
DropdownButton(
hint: Text(
'Select a scanner'), // Not necessary for Option 1
value: _selectedScanner,
onChanged: (newValue) {
setState(() {
_selectedScanner = newValue;
});
},
items: _scanners.map((location) {
return DropdownMenuItem(
child: new Text(location),
value: location,
);
}).toList(),
),
MaterialButton(
textColor: Colors.white,
color: Colors.blue,
onPressed: () async {
if (_selectedScanner != null) {
int index =
_scanners.indexOf(_selectedScanner!);
String? documentPath =
await _flutterTwainScannerPlugin
.scanDocument(index);
setState(() {
_documentPath = documentPath;
});
}
},
child: const Text('Scan Document')),
]),
),
SizedBox(
height: 600,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: _documentPath == null
? Image.asset('images/default.png')
: Image.file(
File(_documentPath!),
fit: BoxFit.contain,
width: 600,
height: 600,
),
))
],
),
],
),
),
);
}
}
I try to create a widget test. But I can't understand how to identify widgets can find the key in the main code and do a test?
Main. dart
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Reversi',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
var _controller;
var _reversed;
#override
void initState() {
super.initState();
_controller = TextEditingController();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Reversi'),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextField(
controller: _controller,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: "Enter string to reverse"),
),
const SizedBox(height: 10.0),
if (_reversed != null) ...[
Text(
_reversed,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
),
),
const SizedBox(height: 10.0),
],
RaisedButton(
child: Text("Reverse"),
onPressed: () {
if (_controller.text.isEmpty) return;
setState(() {
_reversed = reverseString(_controller.text);
});
},
),
],
),
),
);
}
}
String reverseString(String initial) {
return initial.split('').reversed.join();
}
This is the widget test code I created. Is this code correct to find the key in the main code and do the test?
main_widget_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_testing/main.dart';
import 'package:flutter_test/flutter_test.dart';
void main(){
testWidgets('Reverse string widget test', (WidgetTester tester) async {
await tester.pumpWidget(MyApp());
var textField = find.byType(TextField);
expect(textField, findsOneWidget);
await tester.enterText(textField, 'Hello');
expect(find.text('Hello'), findsOneWidget);
var button = find.text("Reverse");
expect(button,findsOneWidget);
await tester.tap(button);
await tester.pump();
expect(find.text("olleH"),findsOneWidget);
});
}
How can we identify whether the widget can find the key in the main code and do a test? Can someone explain to me if this code is correct?
I tried to find how to select and upload multiple images in flutter but most of the plugins are not working or I did not understand them well. I found little application but it selects and upload only one picture. How to change this code that user can select and upload multiple pictures or is there any other alternatives. Please write in details, i am freshman in coding. Thanks in advance.
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:image_picker/image_picker.dart';
import 'package:mime/mime.dart';
import 'dart:convert';
import 'package:http_parser/http_parser.dart';
import 'package:toast/toast.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Image Upload Demo',
theme: ThemeData(primarySwatch: Colors.pink),
home: ImageInput());
}
}
class ImageInput extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _ImageInput();
}
}
class _ImageInput extends State<ImageInput> {
// To store the file provided by the image_picker
File _imageFile;
// To track the file uploading state
bool _isUploading = false;
String baseUrl = 'http://YOUR_IPV4_ADDRESS/flutterdemoapi/api.php';
void _getImage(BuildContext context, ImageSource source) async {
File image = await ImagePicker.pickImage(source: source);
setState(() {
_imageFile = image;
});
// Closes the bottom sheet
Navigator.pop(context);
}
Future<Map<String, dynamic>> _uploadImage(File image) async {
setState(() {
_isUploading = true;
});
// Find the mime type of the selected file by looking at the header bytes of the file
final mimeTypeData =
lookupMimeType(image.path, headerBytes: [0xFF, 0xD8]).split('/');
// Intilize the multipart request
final imageUploadRequest =
http.MultipartRequest('POST', Uri.parse(baseUrl));
// Attach the file in the request
final file = await http.MultipartFile.fromPath('image', image.path,
contentType: MediaType(mimeTypeData[0], mimeTypeData[1]));
// Explicitly pass the extension of the image with request body
// Since image_picker has some bugs due which it mixes up
// image extension with file name like this filenamejpge
// Which creates some problem at the server side to manage
// or verify the file extension
imageUploadRequest.fields['ext'] = mimeTypeData[1];
imageUploadRequest.files.add(file);
try {
final streamedResponse = await imageUploadRequest.send();
final response = await http.Response.fromStream(streamedResponse);
if (response.statusCode != 200) {
return null;
}
final Map<String, dynamic> responseData = json.decode(response.body);
_resetState();
return responseData;
} catch (e) {
print(e);
return null;
}
}
void _startUploading() async {
final Map<String, dynamic> response = await _uploadImage(_imageFile);
print(response);
// Check if any error occured
if (response == null || response.containsKey("error")) {
Toast.show("Image Upload Failed!!!", context,
duration: Toast.LENGTH_LONG, gravity: Toast.BOTTOM);
} else {
Toast.show("Image Uploaded Successfully!!!", context,
duration: Toast.LENGTH_LONG, gravity: Toast.BOTTOM);
}
}
void _resetState() {
setState(() {
_isUploading = false;
_imageFile = null;
});
}
void _openImagePickerModal(BuildContext context) {
final flatButtonColor = Theme.of(context).primaryColor;
print('Image Picker Modal Called');
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
height: 150.0,
padding: EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
Text(
'Pick an image',
style: TextStyle(fontWeight: FontWeight.bold),
),
SizedBox(
height: 10.0,
),
FlatButton(
textColor: flatButtonColor,
child: Text('Use Camera'),
onPressed: () {
_getImage(context, ImageSource.camera);
},
),
FlatButton(
textColor: flatButtonColor,
child: Text('Use Gallery'),
onPressed: () {
_getImage(context, ImageSource.gallery);
},
),
],
),
);
});
}
Widget _buildUploadBtn() {
Widget btnWidget = Container();
if (_isUploading) {
// File is being uploaded then show a progress indicator
btnWidget = Container(
margin: EdgeInsets.only(top: 10.0),
child: CircularProgressIndicator());
} else if (!_isUploading && _imageFile != null) {
// If image is picked by the user then show a upload btn
btnWidget = Container(
margin: EdgeInsets.only(top: 10.0),
child: RaisedButton(
child: Text('Upload'),
onPressed: () {
_startUploading();
},
color: Colors.pinkAccent,
textColor: Colors.white,
),
);
}
return btnWidget;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Image Upload Demo'),
),
body: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 40.0, left: 10.0, right: 10.0),
child: OutlineButton(
onPressed: () => _openImagePickerModal(context),
borderSide:
BorderSide(color: Theme.of(context).accentColor, width: 1.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.camera_alt),
SizedBox(
width: 5.0,
),
Text('Add Image'),
],
),
),
),
_imageFile == null
? Text('Please pick an image')
: Image.file(
_imageFile,
fit: BoxFit.cover,
height: 300.0,
alignment: Alignment.topCenter,
width: MediaQuery.of(context).size.width,
),
_buildUploadBtn(),
],
),
);
}
}
I used that package:
dependencies:
multi_image_picker: ^4.6.7
Ex:
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:multi_image_picker/multi_image_picker.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<Asset> images = List<Asset>();
String _error;
#override
void initState() {
super.initState();
}
Widget buildGridView() {
if (images != null)
return GridView.count(
crossAxisCount: 3,
children: List.generate(images.length, (index) {
Asset asset = images[index];
return AssetThumb(
asset: asset,
width: 300,
height: 300,
);
}),
);
else
return Container(color: Colors.white);
}
Future<void> loadAssets() async {
setState(() {
images = List<Asset>();
});
List<Asset> resultList;
String error;
try {
resultList = await MultiImagePicker.pickImages(
maxImages: 300,
);
} on Exception catch (e) {
error = e.toString();
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
images = resultList;
if (error == null) _error = 'No Error Dectected';
});
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: const Text('Plugin example app'),
),
body: Column(
children: <Widget>[
Center(child: Text('Error: $_error')),
RaisedButton(
child: Text("Pick images"),
onPressed: loadAssets,
),
Expanded(
child: buildGridView(),
)
],
),
),
);
}
}
Add dependecy of image_picker:
image_picker: ^0.8.4+3
Then make a method for selectImages():
final ImagePicker imagePicker = ImagePicker();
List<XFile>? imageFileList = [];
void selectImages() async {
final List<XFile>? selectedImages = await
imagePicker.pickMultiImage();
if (selectedImages!.isNotEmpty) {
imageFileList!.addAll(selectedImages);
}
print("Image List Length:" + imageFileList!.length.toString());
setState((){});
}
Create a builder for showing selected Images:
return Scaffold(
appBar: AppBar(
title: Text('Multiple Images'),
),
body: SafeArea(
child: Column(
children: [
ElevatedButton(
onPressed: () {
selectImages();
},
child: Text('Select Images'),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: GridView.builder(
itemCount: imageFileList!.length,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3),
itemBuilder: (BuildContext context, int index) {
return Image.file(File(imageFileList![index].path),
fit: BoxFit.cover,);
}),
),
),
],
),
));
Complete Source code available in github link...
https://github.com/NishaJain24/multi_image_picker
I have a button with a text, and when I pressed the button, a text widget with the same text is added to the same page.
I'd like to add Hero like animation between them.
I guess what I need is SlideTransition, but I don't know how to slide from one widget position to another widget position.
Is it possible to do? What widget (or class) should I look into?
Here's the code I want to do (but doesn't work since Hero doesn't work on the same page widgets):
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<String> text = [];
String buttonTag = "0";
#override
Widget build(BuildContext context) {
List<Widget> textWidgets = [];
for (int i = 0; i < text.length; ++i) {
textWidgets.add(
Padding(
padding: const EdgeInsets.all(8.0),
child: Hero(tag: "${i}", child: Text(text[i])),
)
);
}
return SafeArea(
child: Scaffold(
body: Center(
child: Column(
children: <Widget>[
RaisedButton(
child: Hero(
tag: buttonTag,
child: Text("abcde${text.length}")),
onPressed: () {
setState(() {
text.add("abcde${text.length}");
buttonTag = "${text.length}";
});
},
)
] + textWidgets,
),
),
),
);
}
}
Not exactly the answer to the question but instead of Hero (if it's possible) you can use AnimatedList to get the same result.
Code snippet
import 'package:flutter/material.dart';
import 'dart:math';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final GlobalKey<AnimatedListState> _listKey = GlobalKey<AnimatedListState>();
final List<Text> _textWidgets = [];
var rng = new Random();
_addItem() {
setState(() {
_listKey.currentState.insertItem(_textWidgets.length,
duration: const Duration(milliseconds: 500));
int id = rng.nextInt(100);
_textWidgets.add(Text('item $id'));
});
}
Widget _buildItem(
BuildContext context, Text item, Animation<double> animation) {
final offsetAnimation = Tween<Offset>(
begin: Offset(1.0, 0.0),
end: Offset(0.0, 0.0),
).animate(animation);
return SlideTransition(
position: offsetAnimation,
child: SizedBox(
height: 50.0,
child: Center(
child: item,
),
),
);
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Column(
children: <Widget>[
RaisedButton(
child: Text("Add Item"),
onPressed: () {
setState(() {
_addItem();
});
},
),
Expanded(
child: AnimatedList(
key: _listKey,
initialItemCount: _textWidgets.length,
itemBuilder: (context, index, animation) {
return _buildItem(context, _textWidgets[index], animation);
},
),
),
],
),
),
);
}
}
I think it's possible by this llibrary which named: LocalHero
Implement your self
The AnimationController, Tween, AnimatedBuilder are key components.
This is a sample and code about this.
Don't use AnimatedController.animate in AnimatedBuilder builder.
evaluate is enough. Because the builder function is called every ticker frame.
Use AnimationController.animate as class member field.
class _AuthorizedState extends State<_Authorized> with SingleTickerProviderStateMixin {
late final _menuAC = AnimationController(vsync: this, duration: 200.ms);
late final isFilterOpen = ValueNotifier(false)..addListener(_handleFilterOpenChanged);
late final filterColor =
ColorTween(begin: context.color.primaryContainer, end: context.color.secondaryContainer)
.animate(_menuAC);
late final filterBorderRadius = Tween<double>(begin: 12, end: 0).animate(_menuAC);
void _handleFilterOpenChanged() {
print(isFilterOpen.value);
if (isFilterOpen.value) {
_menuAC.forward();
} else {
_menuAC.reverse();
}
}
#override
void dispose() {
_menuAC.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return AppScaffold(
child: LayoutBuilder(
builder: (context, cons) => Stack(
children: [
AnimatedBuilder(
animation: _menuAC,
builder: (context, child) {
return Positioned(
bottom: Tween(begin: 16.0, end: 0.0).evaluate(_menuAC),
right: Tween(begin: 16.0, end: 0.0).evaluate(_menuAC),
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(12.0),
topRight: const Radius.circular(12.0),
bottomLeft:
Radius.circular(Tween<double>(begin: 12, end: 0).evaluate(_menuAC)),
bottomRight:
Radius.circular(Tween<double>(begin: 12, end: 0).evaluate(_menuAC)),
),
child: Container(
width: Tween(begin: 56.0, end: cons.maxWidth).evaluate(_menuAC),
height: Tween(begin: 56.0, end: min(cons.maxHeight * 0.7, 500.0))
.evaluate(_menuAC),
decoration: BoxDecoration(
color: filterColor.value,
),
child: child,
),
),
);
},
child: Material(
elevation: 24,
color: Colors.transparent,
child: InkWell(
onTap: () {
isFilterOpen.value = !isFilterOpen.value;
},
child: const Center(child: Icon(MdiIcons.filter)),
),
),
),
],
),
),
);
}
}
I have a Stack of 5 Text as children. Each child is wrapped with a FadeTransition object. Outside the Stack I have 5 RaisedButton that maps to one Text each. By default, Text 1 has opacity of 1 and the rest has 0 opacity. When a button is clicked, the opacity of the text that it maps become 1 and the rest become 0.
To do that I created 5 different AnimationController and hardcoded a very long logic. I am not sure that this is the correct way to do that in Flutter.
I believe there must be some easier way.
Moreover, this is a simplified example. The issue in my real application has even complex conditions. (For example, show only Text 2 and Text 3 when Button 5 is clicked and the boolean hasViewedText1 is true .)
import 'dart:core';
import 'package:flutter/material.dart';
class Test extends StatefulWidget {
#override
_State createState() {
return _State();
}
}
class _State extends State<Test> with TickerProviderStateMixin {
AnimationController _animationController1;
AnimationController _animationController2;
AnimationController _animationController3;
AnimationController _animationController4;
AnimationController _animationController5;
#override
void initState() {
super.initState();
_animationController1 = new AnimationController(
vsync: this,
duration: new Duration(seconds: 1),
);
_animationController2 = new AnimationController(
vsync: this,
duration: new Duration(seconds: 1),
);
_animationController3 = new AnimationController(
vsync: this,
duration: new Duration(seconds: 1),
);
_animationController4 = new AnimationController(
vsync: this,
duration: new Duration(seconds: 1),
);
_animationController5 = new AnimationController(
vsync: this,
duration: new Duration(seconds: 1),
);
_everyThingBackward();
_animationController1.forward();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
elevation: 0.5,
title: new Text(
"Testing views",
style: Theme.of(context).textTheme.title,
),
),
// body: _buildBodyAnimationTest(),
// body: _buildTuto(),
// body: _builtLayoutBuilder(),
body: _builtLayoutConditionalAnimation(),
);
}
Widget _builtLayoutConditionalAnimation() {
return new Column(
children: <Widget>[
new Column(
children: <Widget>[
new RaisedButton(child: new Text("Button 1"), onPressed: () {
_everyThingBackward();
_animationController1.forward();
}),
new RaisedButton(child: new Text("Button 2"), onPressed: () {
_everyThingBackward();
_animationController2.forward();
}),
new RaisedButton(child: new Text("Button 3"), onPressed: () {
_everyThingBackward();
_animationController3.forward();
}),
new RaisedButton(child: new Text("Button 4"), onPressed: () {
_everyThingBackward();
_animationController4.forward();
}),
new RaisedButton(child: new Text("Button 5"), onPressed: () {
_everyThingBackward();
_animationController5.forward();
}),
],
),
new Stack(
children: <Widget>[
FadeTransition(opacity: _animationController1,child: new Text('Text 1 is clicked')),
FadeTransition(opacity: _animationController2,child: new Text('Text 2 is clicked')),
FadeTransition(opacity: _animationController3,child: new Text('Text 3 is clicked')),
FadeTransition(opacity: _animationController4,child: new Text('Text 4 is clicked')),
FadeTransition(opacity: _animationController5,child: new Text('Text 5 is clicked')),
],
),
],
);
}
void _everyThingBackward() {
_animationController1.reverse();
_animationController2.reverse();
_animationController3.reverse();
_animationController4.reverse();
_animationController5.reverse();
}
}
This can me made a lot simpler by using the AnimatedSwitcher widget, link to docs.
Here is a full example:
import 'package:flutter/material.dart';
void main() => runApp(App());
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(child: Center(child: Test())),
),
);
}
}
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
Widget _child = Text(
"No Button Tapped!",
key: UniqueKey(),
);
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
RaisedButton(
child: Text("Button 1"),
onPressed: () {
setState(() {
_child = Text(
"Button 1 Tapped!",
key: UniqueKey(),
);
});
},
),
RaisedButton(
child: Text("Button 2"),
onPressed: () {
setState(() {
_child = Text(
"Button 2 Tapped!",
key: UniqueKey(),
);
});
},
),
RaisedButton(
child: Text("Button 3"),
onPressed: () {
setState(() {
_child = Text(
"Button 3 Tapped!",
key: UniqueKey(),
);
});
},
),
AnimatedSwitcher(
duration: Duration(milliseconds: 200),
child: _child,
),
],
);
}
}
This medium article might be useful too: https://medium.com/flutter-community/what-do-you-know-about-aniamtedswitcher-53cc3a4bebb8