How to implement animation like closing movie credits in flutter? - animation

I want to make animated scrollview like closing movie credits in flutter.
That's what i make.
That's what i want to make.
My code is:
import 'package:flutter/material.dart';
class AutoScrollPage extends StatefulWidget {
#override
AutoScrollPageState createState() => AutoScrollPageState();
}
class AutoScrollPageState extends State<AutoScrollPage> with TickerProviderStateMixin {
ScrollController _scrollController = ScrollController();
bool scroll = true;
int speedFactor = 20;
_scroll() {
double maxExtent = _scrollController.position.maxScrollExtent;
double distanceDifference = maxExtent - _scrollController.offset;
double durationDouble = distanceDifference / speedFactor;
_scrollController.animateTo(_scrollController.position.maxScrollExtent,
duration: Duration(seconds: durationDouble.toInt()),
curve: Curves.linear);
}
#override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) {
_scroll();
});
super.initState();
}
#override
void dispose() {
///Don't forget to clean up resources when you are done using it
_scrollController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
String val = '''
BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE.BUNCH OF TEXT HERE.BUNCH OF TEXT HERE.BUNCH OF TEXT HERE.BUNCH OF TEXT HERE.BUNCH OF TEXT HERE.BUNCH OF TEXT HERE. BUNCH OF TEXT HERE.v
BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE.BUNCH OF TEXT HERE.BUNCH OF TEXT HERE.BUNCH OF TEXT HERE.BUNCH OF TEXT HERE.BUNCH OF TEXT HERE.BUNCH OF TEXT HERE. BUNCH OF TEXT HERE.v
BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE.BUNCH OF TEXT HERE.BUNCH OF TEXT HERE.BUNCH OF TEXT HERE.BUNCH OF TEXT HERE.BUNCH OF TEXT HERE.BUNCH OF TEXT HERE. BUNCH OF TEXT HERE.v
BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE. BUNCH OF TEXT HERE.BUNCH OF TEXT HERE.BUNCH OF TEXT HERE.BUNCH OF TEXT HERE.BUNCH OF TEXT HERE.BUNCH OF TEXT HERE.BUNCH OF TEXT HERE. BUNCH OF TEXT HERE.v
''';
return Scaffold(
backgroundColor: Colors.black,
body: SingleChildScrollView(
controller: _scrollController,
child: Text(
val,
maxLines: 1000,
style: TextStyle(color: Colors.yellow, fontSize: 25.0),
),
),
);
}
}
Note: When my ScrollView reach to it's ends. It stop scrolling.
But in Second video example text never stop scrolling. It's moving into space until become very tiny.

You can use Transform widget for this.
Wrap your SingleChildScrollView with Transform Widget and use transform property to rotate that.
See the code below or See running example code at DartPade ClosingMovieCredits
Transform(
transform: Matrix4.identity()
..setEntry(3, 2, 0.002)
..rotateX(-0.7),
alignment: FractionalOffset.center,
child: SingleChildScrollView(
controller: _scrollController,
child: Text(
val,
maxLines: 1000,
style: TextStyle(color: Colors.yellow, fontSize: 25.0),
),
)
)
)

Related

How to move select image button forward when selecting one in flutter

I'm trying to upload multiple image not once, but like this, when user select one image then upload image image will move forward, here is the snap what i'm trying to say
on click on add button an image picker will display
then after selecting the image this should be like this
here i'm selecting one image.
final ImagePicker picker = ImagePicker();
File? _image;
Future pickImagefromGallery() async{
try{
final image=await ImagePicker().pickImage(source: ImageSource.gallery);
if(image==null) return;
// final imageTemp=File(image.path);
final imagePermanent=await saveImagePermantly(image.path);
setState(() {
this._image=imagePermanent;
});
} on PlatformException catch(e){
print("Failed to pick an image" + e.toString());
}
}
#override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.topLeft,
child: _image!=null?Image.file(_image!,
width: MediaQuery.of(context).size.width * 0.3,
height: MediaQuery.of(context).size.height * 0.13,
fit: BoxFit.cover,
):
Align(
alignment: Alignment.topLeft,
child: customImageButton(
context,
"+",
(){pickImagefromGallery()})
):}}
output:
You can put all widgets into a List with a Wrap as parent.
https://api.flutter.dev/flutter/widgets/Wrap-class.html
List<Widgets> listWidgets = [];
...
//then you can add any widget to list
//first you need to add your button to list
listWidgets.add(Align(
alignment: Alignment.topLeft,
child: customImageButton(
context,
"+",
(){pickImagefromGallery()}));
listWidgets.add(Image.file(...)); // this add widget to last position
listWidgets.insert(0, Image.file(...)); // this add to first position like you want
// when you add a widget into list need to do a setState()
// and use Wrap with a list
Wrap(
children: listWidgets,
)

Flutter - How to display multiple images and pdf in a list view?

Inside a list are images and pdfs. I am having trouble in displaying them in flutter. I can only display one image but when I try to display multiple images/ images and pdfs, that is when I get an error message. 'List<dynamic>' is not a subtype of type 'String'
Initializing list
List _babyList = List();
Here is the value of _babyList. I fetch it from the database and this is the value when I print it. print(_babyList);
[[https://brrtforce-uploads.s3.us-east-2.amazonaws.com/609feb3289f7420015514b54/request-applicant/validId/yh215ikmcot51-1.jpg, https://brrtforce-uploads.s3.us-east-2.amazonaws.com/609feb3289f7420015514b54/request-applicant/validId/breakout.jpg]]
Displaying multiple files in a listview.builder
: ListView.builder(
itemCount: _babyList.length,
itemBuilder: (BuildContext context, int index){
return Padding(
padding: EdgeInsets.all(20),
child: Card(
elevation: 20,
color: Colors.black,
child: Column(
children: <Widget>[
Image.network(_babyList[index]),
],
),
),
);
}
),
PS. what if the list consists of images and pdfs? How can I know the file type and display it in a list view?
have you try to put a typed list
List _babyList = List();

Flutter: Convert Base64 String to Image (Type File Variable)

Photos are taken with the Flutter Package image_picker and saved as variables of type "File".
These images can be viewed with Flutter.
From a jSON string photos in BASE64 format should be formatted into this data type in order to be able to display them.
Does anyone know how this works?
It is possible to directly display BASE64 images with Flutter.
The problem is that there is a "flickering" effect when rendering because the photos are reloaded each time a user types in.
The framework does not seem to notice in BASE64 images that it's always the same photo.
For photos in the file type, this problem does not occur.
Therefore I can not recommend rendering BASE64 strings directly.
So I want to apply the conversion.
Does anyone have a solution how to convert the BASE64 string into a variable of type "File"?
var picturesTaken = <File>[];
Widget _showFoto(int currentFoto) {
return Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child: Container(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Center(
child: Column(
children: <Widget>[
Image.file(picturesTaken[currentFoto])
],
),
),
),
)
);
}
Your base64 string shouldn't include the part 'data:image/jpg;base64,' etc. in prefix
List<int> imageBytes = _image.readAsBytesSync();
String imageB64 = base64Encode(imageBytes);
to show in ui
Image.memory(
img,
width: 85,
height: 85,
fit: BoxFit.cover,
)
Based on your answer, I found a solution:
Image.memory(
img,
width: 85,
height: 85,
fit: BoxFit.cover,
gaplessPlayback: true
)
import 'dart:convert';
import 'dart:typed_data';
String _base64;
Uint8List bytes = BASE64.decode(_base64);
Image.memory(bytes)
(or)
Image imageFromBase64String(String base64String) {
return Image.memory(base64Decode(base64String));
}
Uint8List dataFromBase64String(String base64String) {
return base64Decode(base64String);
}
String base64String(Uint8List data) {
return base64Encode(data);
}
There's a simpler way using 'dart:convert' package
Image.memory(base64Decode(base64String));

How can I use animation/animation not running during a Hero transition in Flutter?

I have a grid of cards depicting products. When a card is tapped, I want it to flip over (around the Y axis) to reveal the "other side" that shows the details, while simultaneously growing to fill the screen.
Duration 0.0 - Card shows front side and is in grid view
Duration 0.5 - Card is 50% of the way to full-screen and perpendicular to the screen (front side facing to the right, "back" side facing to the left)
Duration 1.0 - Card is fully expanded and the "back" card is showing.
I have managed to get a flip animation working, but am having trouble figuring out how to also get it to run during the Hero transition. From this article it seems like I may need to make use of flightShuttleBuilder to be able to animate the overlay but my animation does not run during the transition:
return Hero(
tag: 'test',
flightShuttleBuilder: (
BuildContext flightContext,
Animation<double> animation,
HeroFlightDirection flightDirection,
BuildContext fromHeroContext,
BuildContext toHeroContext,
) {
final Hero toHero = toHeroContext.widget;
return Transform(
transform: Matrix4.identity()..rotateY(-pi * animation.value),
alignment: FractionalOffset.center,
child: toHero,
);
},
child: Card(...),
);
As it turns out, flightShuttleBuilder only emits values at the start and end of the transition instead of throughout the animation. Capturing from this issue on GitHub, it is apparently expected behavior.
The workaround is to create your own transition which extends from AnimatedWidget; that will emit values normally and can be used in the flightShuttleBuilder:
class FlipcardTransition extends AnimatedWidget {
final Animation<double> flipAnim;
final Widget child;
FlipcardTransition({#required this.flipAnim, #required this.child})
: assert(flipAnim != null),
assert(child != null),
super(listenable: flipAnim);
#override
Widget build(BuildContext context) {
return Transform(
transform: Matrix4.identity()
..rotateY(-pi * flipAnim.value),
alignment: FractionalOffset.center,
child: child,
);
}
}
...
flightShuttleBuilder: (BuildContext flightContext,
Animation<double> animation,
HeroFlightDirection flightDirection,
BuildContext fromHeroContext,
BuildContext toHeroContext,) {
final Hero toHero = toHeroContext.widget;
return FlipcardTransition(
flipAnim: animation,
child: toHero,
);
},
As Matt said, the default behavior is only emitting start and end value, so we should listen the animation to get the full animatable widget. Here is an example:
Hero(
tag: "YourHeroTag",
flightShuttleBuilder: (BuildContext flightContext,
Animation<double> animation,
HeroFlightDirection flightDirection,
BuildContext fromHeroContext,
BuildContext toHeroContext,) {
return AnimatedBuilder(
animation: animation,
builder: (context, value) {
return Container(
color: Color.lerp(Colors.white, Colors.black87, animation.value),
);
},
);
},
child: Material( // Wrap in Material to prevent missing theme, mediaquery, ... features....
// ...
)
)
It's recommended to wrap in Material widget to prevent unexpected missing style.

How to create a hero style animation on the same screen route with Flutter?

I'm trying to create a dynamic animation described in the mockup above. What I need is:
A round shape that will represent an avatar (user pic, for example);
A text centered below it.
Below those (that use half of the screen) is a scrollable PageView.
The animation should be as the following:
Begin: In a Stack both centered at the begin.
Animation: Scaling down and sliding the text (with variable lenght) that must be to the right of the avatar.
End: As the second image in the mockup. Side-to-side while the content below keeps scrolling.
Thought in SliverPersistentHeader combined with CustomMultiChildLayout but the problem is that the text starts centered and ends align to the left and I can animate this dynamically. I was trying to remove the offset of the centered text in the end but it doesn't feel right.
Any help or a sample only with this animation would be appreciate. Thank you.
You will need a Sliver to animate your layout based on the scroll offset. More specifically, SliverPersistentHeader in your situation.
CustomMultiChildLayout is not necessary though, you can achieve the same result using tweens and align/padding/stuff. But you can give it a go if your layout starts to become too complex.
The trick is to use the scroll offset given by SliverPersistentHeader to compute the current progression. Then use that progression to position element between their original and final position.
Here's a raw example:
class TransitionAppBar extends StatelessWidget {
final Widget avatar;
final Widget title;
const TransitionAppBar({this.avatar, this.title, Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return SliverPersistentHeader(
pinned: true,
delegate: _TransitionAppBarDelegate(
avatar: avatar,
title: title,
),
);
}
}
class _TransitionAppBarDelegate extends SliverPersistentHeaderDelegate {
final _avatarTween =
SizeTween(begin: Size(150.0, 150.0), end: Size(50.0, 50.0));
final _avatarMarginTween =
EdgeInsetsTween(begin: EdgeInsets.zero, end: EdgeInsets.only(left: 10.0));
final _avatarAlignTween =
AlignmentTween(begin: Alignment.topCenter, end: Alignment.centerLeft);
final _titleMarginTween = EdgeInsetsTween(
begin: EdgeInsets.only(top: 150.0 + 5.0),
end: EdgeInsets.only(left: 10.0 + 50.0 + 5.0));
final _titleAlignTween =
AlignmentTween(begin: Alignment.center, end: Alignment.centerLeft);
final Widget avatar;
final Widget title;
_TransitionAppBarDelegate({this.avatar, this.title})
: assert(avatar != null),
assert(title != null);
#override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
final progress = shrinkOffset / 200.0;
final avatarSize = _avatarTween.lerp(progress);
final avatarMargin = _avatarMarginTween.lerp(progress);
final avatarAlign = _avatarAlignTween.lerp(progress);
final titleMargin = _titleMarginTween.lerp(progress);
final titleAlign = _titleAlignTween.lerp(progress);
return Stack(
fit: StackFit.expand,
children: <Widget>[
Padding(
padding: avatarMargin,
child: Align(
alignment: avatarAlign,
child: SizedBox.fromSize(size: avatarSize, child: avatar),
),
),
Padding(
padding: titleMargin,
child: Align(
alignment: titleAlign,
child: DefaultTextStyle(
style: Theme.of(context).textTheme.title, child: title),
),
)
],
);
}
#override
double get maxExtent => 200.0;
#override
double get minExtent => 100.0;
#override
bool shouldRebuild(_TransitionAppBarDelegate oldDelegate) {
return avatar != oldDelegate.avatar || title != oldDelegate.title;
}
}
which you can use with a CustomScrollView:
Scaffold(
body: CustomScrollView(
slivers: <Widget>[
TransitionAppBar(
avatar: Material(
color: Colors.blue,
elevation: 3.0,
),
title: Text("Hello World"),
),
SliverList(
delegate: SliverChildBuilderDelegate((context, index) {
return ListTile(
title: Text('$index'),
);
}),
)
],
),
);

Resources