Animation 在Flatter中将ListView项设置为全屏动画
我想让我的列表项在点击时执行()。我尝试使用Animation 在Flatter中将ListView项设置为全屏动画,animation,flutter,Animation,Flutter,我想让我的列表项在点击时执行()。我尝试使用AnimatedCrossFade,但它要求它的两个子项处于同一级别,例如,细节视图与列表视图而不是点击的项目交叉淡入。事实上,英雄动画似乎是唯一可以跨窗口小部件进行动画制作的动画 我在使用Hero时遇到问题。它应该包装列表项吗?如果Widget子树在Hero源/目标中显著不同,这有关系吗?此外,英雄动画可以与LocalHistoryRoutes一起使用吗 编辑 现在看起来我需要做的是使用一个覆盖图,最难的部分是我需要在屏幕上点击的相同位置将所选项目添
AnimatedCrossFade
,但它要求它的两个子项处于同一级别,例如,细节视图与列表视图而不是点击的项目交叉淡入。事实上,英雄
动画似乎是唯一可以跨窗口小部件进行动画制作的动画
我在使用Hero时遇到问题。它应该包装列表项吗?如果Widget子树在Hero源/目标中显著不同,这有关系吗?此外,英雄动画可以与LocalHistoryRoute
s一起使用吗
编辑
现在看起来我需要做的是使用一个
覆盖图
,最难的部分是我需要在屏幕上点击的相同位置将所选项目添加到覆盖图中,然后动画部分就很容易了。这里可能使用的是目标/跟随者模式,例如您可以使用英雄
小部件制作这种动画。下面是我的例子:
和源代码:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new FirstPage(title: 'Color Palette'),
);
}
}
class FirstPage extends StatefulWidget {
FirstPage({Key key, this.title}) : super(key: key);
final String title;
@override
_FirstPageState createState() => new _FirstPageState();
}
class _FirstPageState extends State<FirstPage> {
final palette = [
{'#E53935': 0xFFE53935},
{'#D81B60': 0xFFD81B60},
{'#8E24AA': 0xFF8E24AA},
{'#5E35B1': 0xFF5E35B1},
{'#3949AB': 0xFF3949AB},
{'#1E88E5': 0xFF1E88E5},
{'#039BE5': 0xFF039BE5},
{'#00ACC1': 0xFF00ACC1},
{'#00897B': 0xFF00897B},
{'#43A047': 0xFF43A047},
{'#7CB342': 0xFF7CB342},
{'#C0CA33': 0xFFC0CA33},
];
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Container(
child: new ListView.builder(
itemCount: palette.length,
itemBuilder: (context, index) => new Hero(
tag: palette[index].keys.first,
child: new GestureDetector(
onTap: () {
Navigator
.of(context)
.push(new ColorPageRoute(palette[index]));
},
child: new Container(
height: 64.0,
width: double.infinity,
color: new Color(palette[index].values.first),
child: new Center(
child: new Hero(
tag: 'text-${palette[index].keys.first}',
child: new Text(
palette[index].keys.first,
style: Theme.of(context).textTheme.title.copyWith(
color: Colors.white,
),
),
),
),
),
),
)),
),
);
}
}
class SecondPage extends StatelessWidget {
final Map<String, int> color;
SecondPage({this.color});
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Color'),
),
body: new Hero(
tag: color.keys.first,
child: new Container(
color: new Color(color.values.first),
child: new Center(
child: new Hero(
tag: 'text-${color.keys.first}',
child: new Text(
color.keys.first,
style:
Theme.of(context).textTheme.title.copyWith(color: Colors.white),
),
),
),
),
),
);
}
}
class ColorPageRoute extends MaterialPageRoute {
ColorPageRoute(Map<String, int> color)
: super(
builder: (context) => new SecondPage(
color: color,
));
@override
Widget buildTransitions(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) {
return FadeTransition(opacity: animation, child: child);
}
}
导入“包装:颤振/材料.省道”;
void main()=>runApp(新的MyApp());
类MyApp扩展了无状态小部件{
//此小部件是应用程序的根。
@凌驾
小部件构建(构建上下文){
返回新材料PP(
标题:“颤振演示”,
主题:新主题数据(
主样本:颜色。蓝色,
),
主页:新首页(标题:“调色板”),
);
}
}
类FirstPage扩展StatefulWidget{
第一页({Key,this.title}):超级(Key:Key);
最后的字符串标题;
@凌驾
_FirstPageState createState()=>新建_FirstPageState();
}
类_FirstPageState扩展了状态{
最终调色板=[
{E53935':0xFFE53935},
{'D81B60':0xFFD81B60},
{'#8E24AA':0xFF8E24AA},
{'#5E35B1':0xFF5E35B1},
{'3949AB':0xFF3949AB},
{'1E88E5':0xFF1E88E5},
{'#039BE5':0xFF039BE5},
{'#00ACC1':0xFF00ACC1},
{'#00897B':0xFF00897B},
{'#43A047':0xFF43A047},
{'#7CB342':0xFF7CB342},
{'#C0CA33':0xFFC0CA33},
];
@凌驾
小部件构建(构建上下文){
归还新脚手架(
appBar:新的appBar(
标题:新文本(widget.title),
),
主体:新容器(
子项:新建ListView.builder(
itemCount:palette.length,
itemBuilder:(上下文,索引)=>新英雄(
标记:调色板[index].keys.first,
儿童:新的手势检测器(
onTap:(){
领航员
.of(上下文)
.push(新颜色页面路由(调色板[索引]);
},
子容器:新容器(
身高:64.0,
宽度:double.infinity,
颜色:新颜色(调色板[索引].values.first),
孩子:新中心(
孩子:新英雄(
标记:“text-${palete[index].keys.first}”,
儿童:新文本(
调色板[index].keys.first,
样式:Theme.of(context).textTheme.title.copyWith(
颜色:颜色,白色,
),
),
),
),
),
),
)),
),
);
}
}
类SecondPage扩展了无状态小部件{
最终地图颜色;
第二页({this.color});
@凌驾
小部件构建(构建上下文){
归还新脚手架(
appBar:新的appBar(
标题:新文本(“颜色”),
),
身体:新英雄(
标签:color.keys.first,
子容器:新容器(
颜色:新颜色(颜色。值。第一),
孩子:新中心(
孩子:新英雄(
标记:“text-${color.keys.first}”,
儿童:新文本(
颜色。键。首先,
风格:
Theme.of(context).textTheme.title.copyWith(颜色:Colors.white),
),
),
),
),
),
);
}
}
类ColorPageRoute扩展了MaterialPageRoute{
ColorPageRoute(地图颜色)
:超级(
生成器:(上下文)=>新建第二页(
颜色:颜色,
));
@凌驾
小部件构建转换(构建上下文、动画、,
动画辅助动画,小部件子项){
返回FadeTransition(不透明度:动画,子对象:子对象);
}
}
我只是作弊,然后将整个内容包装在一个堆栈中——底层是一个带有AppBar的页面,顶层在绘制之前是透明的
onTap,将ListTile复制到上表面,然后英雄动画将填充整个屏幕。它不是很优雅,但是框架(还)没有提供轻松覆盖AppBar的功能,因此准备一个画布来绘制其他复杂的动画可能是很有帮助的 有人写了一个惊人的飞镖软件包就是为了这个目的: 然后,您需要做的就是使用MorpheusPageRoute,包处理其余部分
...
Navigator.push(
context,
MorpheusPageRoute(
builder: (context) => MyWidget(title: title),
),
);
...
我无法评论或编辑Lucas的帖子(新帐户),但您还需要提供动画开始的小部件的parentKey:
final widgetKey = GlobalKey();
...
ListTile(
key: widgetKey,
title: Text('My ListItem'),
onTap: () => Navigator.push(
context,
MorpheusPageRoute(
builder: (context) => MyNewPage(),
parentKey: widgetKey,
),
),
),
我认为它还需要覆盖appbar。因此,如果不是这样,我想也没关系。我确实想要立面部分,但它可以在导航和触发英雄动画之前运行。我还需要一两天的时间来尝试。你所做的似乎接近于我正在使用的英雄动画示例,但在我的代码中使用英雄时,它总是抱怨小部件树中存在重复的标记名。你能告诉我该抱怨的细节吗?
hero
是最简单的解决方案。但它也有一些问题。例如,仅适用于Navigator。这是我的痛苦