參見: Flutter Scrolling
我們在前幾天的List&Grid中,介紹了不同的列表用法,其中在ListView, ListView.builder,GridView, GridView.builder 也使用到了基礎的滾動特效。而接續我們會介紹更多Flutter中關於「滾動效果」的特色與使用方法,方便我們在規劃app時能夠給予用戶更好的使用體驗!
參見: DraggableScrollableSheet class
DraggableScrollableSheet 元件提供我們一個在特定螢幕大小範圍內可以滾動的效果,通常用於在視窗底部(Bottom)彈出資訊的欄位。以下提供本元件用法:
- 可滾動區域,child: DraggableScrollableSheet 包含一個可拖動的區域,用戶可以通過拖動此區域來展開或收縮內容。Child通常使用 ListView、Column 或 CustomScrollView 來實現滾動效果。這個範例中我們使用ListTile作為示範
builder 函數: 包含兩個參數:
外觀: 可以自定義背景顏色、邊框、陰影等。可以用 Container 包裝方便調整。
高度調整: 包含 initialChildSize、maxChildSizem與minChildSize,分別控制預設、最大、最小與父元件的高度比例,方便根據需求自由調整大小。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| DraggableScrollableSheet(
initialChildSize: 0.5, // 初始高度佔父元件的比例 maxChildSize: 0.9, // 最大高度佔父元件的比例 minChildSize: 0.2, // 最小高度佔父元件的比例 builder: (BuildContext context, ScrollController scrollController) { return Container( color: Colors.blue[100],//背景顏色 child: ListView.builder( //主要可滾動區域 controller: scrollController,//滾動控制器 itemCount: 25, itemBuilder: (BuildContext context, int index) { return ListTile(title: Text('Item $index')); }, ), ); }, ),
|
這個範例我們示範如何用DraggableScrollableSheet元件製作個預設佔有一半螢幕空間的List效果,index從0~24
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| import 'package:flutter/material.dart';
void main() { runApp(MyApp()); }
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return const MaterialApp( home: HomePage(), ); } }
class HomePage extends StatelessWidget { const HomePage({Key? key});
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('DraggableScrollableSheet'), ), body: SizedBox.expand( child: DraggableScrollableSheet( initialChildSize: 0.5, // 初始高度佔父元件的比例 maxChildSize: 0.9, // 最大高度佔父元件的比例 minChildSize: 0.2, // 最小高度佔父元件的比例
builder: (BuildContext context, ScrollController scrollController) { return Container( color: Colors.blue[100], child: ListView.builder( controller: scrollController, itemCount: 25, itemBuilder: (BuildContext context, int index) { return ListTile(title: Text('Item $index')); }, ), ); }, ), ), ); } }
|
DraggableScrollableSheet 使用範例
藍色的List部分可以滾動,上方白色部分則可以放置原有的內容,不會跟著滾動!

參見: SliverChildBuilderDelegate class
參見: SliverList class
當我們在視窗中需要多個滾動的事件,為了達成較為複雜的滾動嵌套事件,我們會使用SilverGrid、SilverList的方式來達成。而以下我們會用SliverChildBuilderDelegate元件來介紹如何靈活運用此複雜滾動效果!
SliverChildBuilderDelegate 格式與特性介紹
以下提供本元件的範例用法:
SliverChildBuilderDelegatem元件建立一個包含兩個卡片的SliverList。 每個卡片內部包含
元件詳細內部功能細分如下:
delegate : 當我們使用字定義的元件時會使用此屬性,在CustomScrollView和Sliver中,”delegate”常用於定義子元件的生成方式來達到更靈活配置的行為
SliverChildBuilderDelegate:用於動態建立SliverList的子元件。
(BuildContext context, int index):匿名函數,包含兩個參數:
Card:每張卡片是Card widget,用於包裝內容並提供卡片效果。
Column:每個卡片內部包含一個Column,它包含了一個文字與一個嵌套ListView.builder的兩個子部分
Text(‘Grid Item $ index’):每個卡片的標題,其中$index是當前卡片的索引號碼。
Expanded:用於填滿剩餘可用空間,方便滾動不受限制。
ListView.builder:根據索引號碼建立10個ListTile子元件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { return Card( //卡片元件 margin: const EdgeInsets.all(8.0), child: Column( children: <Widget>[ Text('Grid Item $index'), Expanded( child: ListView.builder( itemCount: 10, // 列表中的項目數 itemBuilder: (BuildContext context, int subIndex) { return ListTile( title: Text('Sub Item $subIndex'), ); }, ), ), ], ), ); }, childCount: 2, //index值為0\~1 ),
|
SliverChildBuilderDelegate 使用範例
最外層我們使用CustomScrollView元件,預先設定
接下來,slivers內具有兩個SliverGrid元件,分別包含了上面提及的SliverChildBuilderDelegate元件,其中
最後我們會再由semanticIndexOffset: 2代表兩行卡片間的 index (第一行為Griditem 0-1、第二行為2-3),相差(偏移量)為2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| import 'package:flutter/material.dart';
void main() { runApp(MyApp()); }
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: const Text('CustomScrollView Example'), ), body: CustomScrollView( semanticChildCount: 4, slivers: <Widget>[ SliverGrid( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, ), delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { return Card( margin: const EdgeInsets.all(8.0), child: Column( children: <Widget>[ Text('Grid Item $index'),//設為第二行的索引號Grid item0,1 Expanded( child: ListView.builder( itemCount: 10, // 列表中的項目數 itemBuilder: (BuildContext context, int subIndex) { return ListTile( title: Text('Sub Item $subIndex'), //設為卡片索引號,為0\~9 ); }, ), ), ], ), ); }, childCount: 2, ), ), SliverGrid( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, ), delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { return Card( margin: const EdgeInsets.all(8.0), child: Column( children: <Widget>[ Text('Grid Item ${index + 2}'),//設為第二行的索引號Grid item2,3 Expanded( child: ListView.builder( itemCount: 10, // 列表中的項目數 itemBuilder: (BuildContext context, int subIndex) { return ListTile( title: Text('Sub Item ${subIndex + 5}'), //設為卡片索引號+5,為5\~14 ); }, ), ), ], ), ); }, childCount: 2, semanticIndexOffset: 2,//兩者語意項目索引的偏移量 ), ), ], ), ), ); } }
|
