问题描述
是否可以使用Flutter复制iOS App Store的过渡效果?
Is it possible to copy the transition effect of iOS App Store using Flutter?
我尝试通过将两个标签放置在两个小部件的根布局中来使用Hero Animation,但是动画看起来很怪异,不是我期望的那样.但是,这样做的好处是,当我使用MaterialPageRoute时,我能够向后滑动iOS.
I tried using Hero Animation by placing two tags into the root layout of both widgets, but animation looks janky or not what I expected. But good thing about this is I am able to do iOS swipe back as I'm using MaterialPageRoute.
来源
Hero(
tag: 'heroTag_destinationScreen',
transitionOnUserGestures: true,
flightShuttleBuilder: (BuildContext flightContext,
Animation<double> animation,
HeroFlightDirection flightDirection,
BuildContext fromHeroContext,
BuildContext toHeroContext,) {
final Hero toHero = toHeroContext.widget;
return ScaleTransition(
scale: animation,
child: toHero,
);
},
child: GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (BuildContext context) {
return DestinationScreen()
},
),
);
},
child: Card(
...someCardContent
),
),
)
目标屏幕
@override
Widget build(BuildContext context) {
return Hero(
tag: 'heroTag_destinationScreen',
child: Scaffold(
appBar: ...someAppBar
body: ...someMainBodyContent
),
)
}
然后我一直在四处张望,Flutter团队创建了一个程序包,可以使用容器变换来模拟这种效果.我实现了它,效果很棒,但后来我无法从左向左滑动iOS设备,无法将布局缩小到卡片视图.
Then I have been looking around and there is a package created by Flutter team which can simulate this effect using container transform. I implemented it, works awesome but then I'm not able to do iOS swipe from left to go back and shrink the layout to card view.
https://pub.dev/packages/animations
推荐答案
这是我的解决方案.
(对不起,我无法发布图片.)
(Sorry for my reputation, I can't post a image.)
我自定义了英雄过渡,以尽可能地重塑App Store的过渡.
I customize hero transition to remake App store transition as much as possible.
child: Hero(
tag: widget.product.id,
child: Image.asset(widget.product.image, fit: BoxFit.cover),
flightShuttleBuilder:
(flightContext, animation, direction, fromcontext, toContext) {
final Hero toHero = toContext.widget;
// Change push and pop animation.
return direction == HeroFlightDirection.push
? ScaleTransition(
scale: animation.drive(
Tween<double>(
begin: 0.75,
end: 1.02,
).chain(
CurveTween(
curve: Interval(0.4, 1.0, curve: Curves.easeInOut)),
),
),
child: toHero.child,
)
: SizeTransition(
sizeFactor: animation,
child: toHero.child,
);
},
),
接下来,我使用ScaleTransition
和onVerticalDragUpdate
来控制弹出动画.
Next, I use ScaleTransition
and onVerticalDragUpdate
to control pop animation.
double _initPoint = 0;
double _pointerDistance = 0;
GestureDetector(
onVerticalDragDown: (detail) {
_initPoint = detail.globalPosition.dy;
},
onVerticalDragUpdate: (detail) {
_pointerDistance = detail.globalPosition.dy - _initPoint;
if (_pointerDistance >= 0 && _pointerDistance < 200) {
// scroll up
double _scaleValue = double.parse((_pointerDistance / 100).toStringAsFixed(2));
if (_pointerDistance < 100) {
_closeController.animateTo(_scaleValue,
duration: Duration(milliseconds: 300),
curve: Curves.linear);
}
} else if (_pointerDistance >= 260) {
if (_pop) {
_pop = false;
_closeController.fling(velocity: 1).then((_) {
setState(() {
_heightController.reverse();
});
Timer(Duration(milliseconds: 100), () {
Navigator.of(context).pop();
});
});
}
} else {
// scroll down
}
},
onVerticalDragEnd: (detail) {
if (_pointerDistance >= 550) {
if (_pop) {
_closeController.fling(velocity: 1).then((_) {
setState(() {
_heightController.reverse();
});
Timer(Duration(milliseconds: 100), () {
Navigator.of(context).pop();
});
});
}
} else {
_closeController.fling(velocity: -1);
}
},
child: Hero(
tag: _product.id,
child: Image.asset(
_product.image,
fit: BoxFit.cover,
height: 300,
),
),
),
如果将Hero
用作动画,则需要自定义文本部分的过渡.
If use Hero
as a animation, you need to customize the text section transition.
此处: https://imgur.com/a/gyD6tiZ
就我而言,我通过Sizetransition
控制文本部分的过渡.
In my case, I control text section transition by Sizetransition
.
// horizontal way and vertical way.
SizeTransition(
axis: Axis.horizontal,
sizeFactor: Tween<double>(begin: 0.5, end: 1).animate(
CurvedAnimation(
curve: Curves.easeInOut, parent: _widthController),
),
child: SizeTransition(
sizeFactor: Tween<double>(begin: 0, end: 1).animate(
CurvedAnimation(
curve: Curves.easeInOut, parent: _heightController),
),
child: Container(
padding: EdgeInsets.only(
left: 20, right: 20, top: 50, bottom: 30),
width: double.infinity,
color: Colors.white,
constraints: BoxConstraints(
minHeight: 650,
),
child: Column(
// title and text
children: <Widget>[
Text('Title', style: TextStyle(fontSize: 18)),
SizedBox(height: 30),
Text(_text,
style: TextStyle(
fontSize: 15,
)),
],
),
),
),
),
尽管它与App Store不同,但我希望它对您有所帮助.
Although it isn't the same as App Store, i hope it is helpful for you.
源代码: https://github.com/HelloJunWei/app_store_transition
如果有任何建议,请随时反馈或创建请求请求. :)
If you have any suggestion, feel free to feedback or create a pull request. :)
这篇关于可以使用Flutter复制iOS App Store过渡吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!