英雄动画和滚动到 Flutter 中两个列表之间的位置
Hero animation and scroll to position between two list in Flutter
我将文件显示为缩略图,例如 Instagram 用户的个人资料。
当我单击某个项目(缩略图)时,我必须执行 Hero
动画以显示全屏页面。
我还想打开整个列表的全屏页面,它直接从所选 post 的给定索引开始,就像在 Instagram 中一样。
这是一个简短的 GIF,可以更好地表达我的意思:
我试过 scroll_to_index 包,但这不符合我的需要(动画坏了而且太慢了)。
请问我怎样才能做到这一点?
这就是我所做的,试试看:
import 'package:flutter/material.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: GridView.count(
crossAxisCount: 3,
children: List.generate(99, (index) {
return Container(
width: double.infinity,
height: double.infinity,
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ListPage(index: index)),
);
},
child: Hero(
tag: 'photo$index',
child: Image.network(
'https://images.unsplash.com/photo-1628701621033-50564c683bb0?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80',
fit: BoxFit.cover,
),
),
),
);
}),
),
);
}
}
class ListPage extends StatefulWidget {
final int index;
ListPage({Key key, @required this.index}) : super(key: key);
@override
_ListPageState createState() => _ListPageState();
}
class _ListPageState extends State<ListPage> {
final ItemScrollController itemScrollController = ItemScrollController();
final ItemPositionsListener itemPositionsListener =
ItemPositionsListener.create();
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return ScrollablePositionedList.builder(
initialScrollIndex: widget.index,
itemCount: 99,
itemBuilder: (context, index) {
return Column(
children: [
AspectRatio(
aspectRatio: 1,
child: Hero(
tag: 'photo$index',
child: Image.network(
'https://images.unsplash.com/photo-1628701621033-50564c683bb0?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80',
fit: BoxFit.cover,
),
),
),
Container(
height: 50,
width: MediaQuery.of(context).size.width,
child: Text('$index'),
),
],
);
},
itemScrollController: itemScrollController,
itemPositionsListener: itemPositionsListener,
);
}
}
将所选项目传递给目标小部件并动态构建 Hero
标签。
主要思想是避免匹配的英雄标签太多。
class MyImagesList extends Stateless Widget {
final String selectedItem;
final List<String> items;
const MyImagesList(this.selectedItem, this.items);
void build(BuildContext context) {
return Column(children: [
for (var item in items)
item == selectedItem
? Hero(tag: item, child: Text(item))
: Text(item)
]);
}
}
我将文件显示为缩略图,例如 Instagram 用户的个人资料。
当我单击某个项目(缩略图)时,我必须执行 Hero
动画以显示全屏页面。
我还想打开整个列表的全屏页面,它直接从所选 post 的给定索引开始,就像在 Instagram 中一样。
这是一个简短的 GIF,可以更好地表达我的意思:
我试过 scroll_to_index 包,但这不符合我的需要(动画坏了而且太慢了)。
请问我怎样才能做到这一点?
这就是我所做的,试试看:
import 'package:flutter/material.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: GridView.count(
crossAxisCount: 3,
children: List.generate(99, (index) {
return Container(
width: double.infinity,
height: double.infinity,
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ListPage(index: index)),
);
},
child: Hero(
tag: 'photo$index',
child: Image.network(
'https://images.unsplash.com/photo-1628701621033-50564c683bb0?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80',
fit: BoxFit.cover,
),
),
),
);
}),
),
);
}
}
class ListPage extends StatefulWidget {
final int index;
ListPage({Key key, @required this.index}) : super(key: key);
@override
_ListPageState createState() => _ListPageState();
}
class _ListPageState extends State<ListPage> {
final ItemScrollController itemScrollController = ItemScrollController();
final ItemPositionsListener itemPositionsListener =
ItemPositionsListener.create();
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return ScrollablePositionedList.builder(
initialScrollIndex: widget.index,
itemCount: 99,
itemBuilder: (context, index) {
return Column(
children: [
AspectRatio(
aspectRatio: 1,
child: Hero(
tag: 'photo$index',
child: Image.network(
'https://images.unsplash.com/photo-1628701621033-50564c683bb0?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80',
fit: BoxFit.cover,
),
),
),
Container(
height: 50,
width: MediaQuery.of(context).size.width,
child: Text('$index'),
),
],
);
},
itemScrollController: itemScrollController,
itemPositionsListener: itemPositionsListener,
);
}
}
将所选项目传递给目标小部件并动态构建 Hero
标签。
主要思想是避免匹配的英雄标签太多。
class MyImagesList extends Stateless Widget {
final String selectedItem;
final List<String> items;
const MyImagesList(this.selectedItem, this.items);
void build(BuildContext context) {
return Column(children: [
for (var item in items)
item == selectedItem
? Hero(tag: item, child: Text(item))
: Text(item)
]);
}
}