1. 程式人生 > 實用技巧 >Flutter 1.17 新 Material motion 規範的預構建動畫

Flutter 1.17 新 Material motion 規範的預構建動畫

老孟導讀:在 Flutter 1.17 釋出大會上,Flutter 團隊還發布了新的 Animations 軟體包,該軟體包提供了實現新的 Material motion 規範的預構建動畫。

軟體包 pub 地址:https://pub.dev/packages/animations

Material motion 規範:https://material.io/design/motion/the-motion-system.html

引入外掛,版本號請到 pub 上檢視最新版本號:

animations: ^1.1.1

Container transform

容器轉換模式設計用於包含容器的UI元素之間的轉換。此模式在兩個UI元素之間建立可見連線。

案例:構建GridView,點選其中一項時跳轉到期詳情頁面:

GridView.builder(
padding: EdgeInsets.all(8),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, crossAxisSpacing: 2, mainAxisSpacing: 4),
itemBuilder: (context, index) {
return OpenContainer(
transitionDuration: _duration,
closedBuilder: (BuildContext _, VoidCallback openContainer) {
return Container(
child: Image.asset(
'assets/images/b.jpg',
fit: BoxFit.fitWidth,
),
);
},
openBuilder: (BuildContext context, VoidCallback _) {
return _DetailPage();
},
);
},
itemCount: 50,
)

使用 OpenContainer 元件,closedBuilder 表示關閉狀態時到元件,在這裡表示 GridView Item,openBuilder 表示點選要跳轉的頁面,這裡表示詳情頁面。

詳情頁面程式碼如下:

class _DetailPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
width: double.infinity,
height: double.infinity,
child: Image.asset(
'assets/images/b.jpg',
fit: BoxFit.cover,
),
),
);
}
}

構建ListView

ListView.builder(
itemBuilder: (context, index) {
return OpenContainer(
transitionDuration: _duration,
closedBuilder: (BuildContext _, VoidCallback openContainer) {
return Card(
child: Container(
height: 45,
alignment: Alignment.center,
child: Text('$index'),
),
);
},
openBuilder: (BuildContext context, VoidCallback _) {
return _DetailPage();
},
);
},
itemCount: 50,
)

也可以是一個按鈕,比如 floatingActionButton

Scaffold(
body: _buildListView(),
floatingActionButton: OpenContainer(
openBuilder: (BuildContext context, VoidCallback _) {
return _DetailPage();
},
transitionDuration: _duration,
closedElevation: 6.0,
closedShape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(50),
),
),
closedColor: Theme.of(context).colorScheme.secondary,
closedBuilder: (BuildContext context, VoidCallback openContainer) {
return SizedBox(
height: 50,
width: 50,
child: Center(
child: Icon(
Icons.add,
color: Theme.of(context).colorScheme.onSecondary,
),
),
);
},
),
)

頂部輸入框

Scaffold(
appBar: AppBar(
title: OpenContainer(
transitionDuration: _duration,
closedBuilder: (BuildContext _, VoidCallback openContainer) {
return Container(
width: 300,
height: 45,
padding: EdgeInsets.only(left: 5),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.withOpacity(.5))),
alignment: Alignment.centerLeft,
child: Icon(Icons.search,color: Colors.black,),
);
},
openBuilder: (BuildContext context, VoidCallback _) {
return _DetailPage();
},
),
),
)

Shared axis

共享軸模式用於具有空間或導航關係的UI元素之間的過渡。此模式在x,y或z軸上使用共享的變換來加強元素之間的關係。

底部導航案例:

@override
Widget build(BuildContext context) {
Widget _child = _OnePage();
switch (_currentIndex) {
case 1:
_child = _TwoPage();
break;
}
return Scaffold(
body: PageTransitionSwitcher(
duration: const Duration(milliseconds: 1500),
reverse: false,
transitionBuilder: (
Widget child,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
return SharedAxisTransition(
child: child,
animation: animation,
transitionType: SharedAxisTransitionType.horizontal,
secondaryAnimation: secondaryAnimation,
);
},
child: _child,
),
bottomNavigationBar: BottomNavigationBar(
onTap: (int index) {
setState(() {
_currentIndex = index;
});
},
currentIndex: _currentIndex,
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(title: Text('首頁'), icon: Icon(Icons.home)),
BottomNavigationBarItem(
title: Text('我的'), icon: Icon(Icons.perm_identity)),
],
),
);
}

型別為 y 軸:

transitionType: SharedAxisTransitionType.vertical,

型別為 z 軸:

transitionType: SharedAxisTransitionType.scaled,

Fade through

淡入模式用於彼此之間沒有密切關係的UI元素之間的過渡。

下面案例來源於官方Demo:

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Fade through')),
body: PageTransitionSwitcher(
transitionBuilder: (
Widget child,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
return FadeThroughTransition(
animation: animation,
secondaryAnimation: secondaryAnimation,
child: child,
);
},
child: pageList[pageIndex],
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: pageIndex,
onTap: (int newValue) {
setState(() {
pageIndex = newValue;
});
},
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.photo_library),
title: Text('Albums'),
),
BottomNavigationBarItem(
icon: Icon(Icons.photo),
title: Text('Photos'),
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
title: Text('Search'),
),
],
),
);
}

效果適用於:

  1. 底部導航切換。
  2. 重新整理列表。
  3. 切換器。

Fade

淡入淡出模式用於在螢幕範圍內進入或退出的UI元素,例如在螢幕中央淡入淡出的對話方塊。

彈出對話方塊案例:

Scaffold(
body: Center(
child: RaisedButton(
onPressed: () {
showModal<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: const Text('對話方塊'),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('取消'),
),
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('確定'),
),
],
);
},
);
},
color: Theme.of(context).colorScheme.primary,
textColor: Theme.of(context).colorScheme.onPrimary,
child: const Text('彈出對話方塊'),
),
),
)

適用場景:

  1. dialog
  2. menu
  3. snackbar
  4. FloatingActionButton

交流

老孟Flutter部落格地址(330個控制元件用法):http://laomengit.com

歡迎加入Flutter交流群(微信:laomengit)、關注公眾號【老孟Flutter】: