flutter widget組件之-----------可滾動的組件

flutter widget組件之-----------可滾動的組件

widget分爲兩類:widgets library中的標準widget和Material Components library中的專用widget;任何應用程序都可以使用widgets library中的widget,但只有Material應用程序可以使用Material Components庫。其中Card,ListTitle就是Material Components庫中的組件。

GridView

一個可滾動的二維空間數組

  • 構造函數
GridView({
    Key key,
    Axis scrollDirection = Axis.vertical,// 滾動方向,水平和垂直
    bool reverse = false,// 子項排列是否倒序
    ScrollController controller,
    bool primary,//如果內容不足,則用戶無法滾動 而如果[primary]爲true,它們總是可以嘗試滾動
    ScrollPhysics physics,//滑動類型設置
    bool shrinkWrap = false,// 內容適配
    EdgeInsetsGeometry padding, // 內邊距

    //gridDelegate 委託類 ,類型是SliverGridDelegate 兩個常用的實現類爲SliverGridDelegateWithFixedCrossAxisCount(固定列數),SliverGridDelegateWithMaxCrossAxisExtent(用於子元素有最大寬度限制的場景)
    @required this.gridDelegate,

    bool addAutomaticKeepAlives = true,
    bool addRepaintBoundaries = true,
    bool addSemanticIndexes = true,
    double cacheExtent,
    List<Widget> children = const <Widget>[],
    int semanticChildCount,
})
GridView.builder({
    //省略其它
    @required this.gridDelegate,//網格委託
    @required IndexedWidgetBuilder itemBuilder,//子項構建者
 
})
GridView.custom({
     //省略其它
    @required this.gridDelegate, //網格委託
    @required this.childrenDelegate,// 子項委託

})
GridView.count({
     //省略其它
    @required int crossAxisCount,// 列數
  
})
GridView.extent({
     //省略其它
    @required double maxCrossAxisExtent, //子項組件大小

}) 

  • 應用示例
// 定義列表數據類型
class BaseBean {
  String name;
  int age;
  String content;
  BaseBean(this.name, this.age, this.content);
}
// 利用list.generate函數  構造列表數據集合
List<BaseBean> list = new List<BaseBean>.generate(
    60, (i) => new BaseBean("name$i", i, "content=$i"));

class MyStatePageState extends State<MyStatePage> {

  // 構建子項
  Widget BuildItem(BaseBean item){
    return Container(
      child:Column(
        children: <Widget>[
           new Text(
            "${item.name}",
            style: new TextStyle(fontSize: 18.0, color: Colors.green),
          ),
          new Text(
            "${item.age}",
            style: new TextStyle(fontSize: 18.0, color: Colors.red),
          ),
         
        ],
      ),
                  
    );
  }
  
  // gridview 構造函數構建 
  Widget GridViewLayout(){
    return GridView(
      scrollDirection: Axis.vertical,
      padding: EdgeInsets.all(20.0),
      // 
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 5,
      ), 
      children:list.map((item)=>BuildItem(item)).toList(),
    );
  }

  // gridView builder 構建視圖列表
  Widget gridViewLayoutBuilder(List<BaseBean> list) {
    return GridView.builder(
        scrollDirection: Axis.vertical,   // 主軸防線
        padding: EdgeInsets.all(10.0),
        itemCount:list.length,// 標明list的長度,不然報錯
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 4,
        ) ,
        // 創建子項widgets
        itemBuilder: (context, i) => new Container(
          child: new Row(
            children: <Widget>[
              new Text(
                "${list[i].name}",
                style: new TextStyle(fontSize: 18.0, color: Colors.red),
              ),
            ],
          ),
        ));
  }


  ///  gridView count 構建視圖列表 
  Widget gridViewLayoutCount(List<BaseBean> list) {
    return GridView.count(
      crossAxisCount: 5,//列數
      padding: EdgeInsets.symmetric(vertical: 0),
      children: list.map((item)=>BuildItem(item)).toList()
    );
  }

  ///  gridView extent 構建視圖列表 
  Widget gridViewLayoutExtent(List<BaseBean> list) {
    return GridView.extent(
      maxCrossAxisExtent: 200,// 子項組件大小
      children: list.map((item)=>BuildItem(item)).toList()
    );
  }

  /// gridView custom 構建視圖列表
  Widget gridViewLayoutCustom(List<BaseBean> list) {
      return GridView.custom(
        gridDelegate:  SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 4,
        ),
        // 構建子項的代理
        childrenDelegate: MyChildrenDelegate(
          (BuildContext context, int i) {
            return new Container(
                child: new Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                new Text(
                  "${list[i].name}",
                  style: new TextStyle(fontSize: 18.0, color: Colors.red),
                ),
            
              ],
            ));
          },
          childCount: list.length,
        ),
      
      );
    
  }

 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("list body"),),
      //  body:GridViewLayout(),
      // body:gridViewLayoutBuilder(list),
      // body:gridViewLayoutCount(list),
      // body: gridViewLayoutExtent(list),

      body:gridViewLayoutCustom(list),
    );
  }
}

// 自定義gridview佈局的代理類
class MyChildrenDelegate extends SliverChildBuilderDelegate {
  MyChildrenDelegate(
    Widget Function(BuildContext, int) builder, {
    int childCount,
    bool addAutomaticKeepAlive = true,
    bool addRepaintBoundaries = true,
  }) : super(builder,
            childCount: childCount,
            addAutomaticKeepAlives: addAutomaticKeepAlive,
            addRepaintBoundaries: addRepaintBoundaries);

  ///監聽 在可見的列表中 顯示的第一個位置和最後一個位置
  @override
  void didFinishLayout(int firstIndex, int lastIndex) {
    print('firstIndex: $firstIndex, lastIndex: $lastIndex');
  }

  // 可不重寫 重寫不能爲null  默認是true  添加進來的實例與之前的實例是否相同 相同返回true 反之false
  // listView 暫時沒有看到應用場景 源碼中使用在 SliverFillViewport 中
  @override
  bool shouldRebuild(SliverChildBuilderDelegate oldDelegate) {
    // TODO: implement shouldRebuild
    // return super.shouldRebuild(oldDelegate);
    return this !=oldDelegate;
  }
}


NestedScrollView

一個可以嵌套其它可滾動widget的widget

  • 構造函數
NestedScrollView({
    Key key,
    this.controller,
    this.scrollDirection = Axis.vertical,
    this.reverse = false,
    this.physics,
    @required this.headerSliverBuilder,
    @required this.body,
  })

  • 應用示例

SingleChildScrollView

有一個子widget的可滾動的widget,子內容超過父容器時可以滾動

  • 構造函數
SingleChildScrollView({
    Key key,
    this.scrollDirection = Axis.vertical, //滾動方向,有水平和垂直連個方向
    this.reverse = false,// 子項是否倒序排列
    this.padding,// 內邊距
    bool primary,//控制是否有滑動效果,內容不足的時候,有效果
    this.physics,// 滑動類型
    this.controller,// 控制滑動位置的控制器
    this.child,// 子項
  })
  • 應用示例
class MyStatePageState extends State<MyStatePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("singleChildScrollView"),),
      body:SingleChildScrollView( 
          scrollDirection:Axis.vertical,
          reverse: true,// 子項倒序排列
          padding: EdgeInsets.all(10),
          primary: true,// 設置爲true,即使內容少,也有滾動效果
          child: ConstrainedBox(
            constraints: BoxConstraints(
              minHeight: 500,
            ),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: <Widget>[
                Container(
                  // A fixed-height child.
                  color: const Color(0xff808000), // Yellow
                  height: 120.0,
                ),
                Container(
                  // Another fixed-height child.
                  color: const Color(0xff008000), // Green
                  height: 120.0,
                ),
              ],
            ),
          ),
        
        ),
    
    );
  } 
}

Scrollable

實現了可滾動widget的交互模型,但不包含UI顯示相關的邏輯

  • 構造函數
Scrollable({
    Key key,
    this.axisDirection = AxisDirection.down,//滾動方向
    this.controller,// 控制滾動位置的控制器
    this.physics,// 股東類型
    @required this.viewportBuilder,// 創建顯示滾動內容窗口的Builder
    this.excludeFromSemantics = false,
    this.semanticChildCount,// 帶有語義信息的子項widget的數量
  })

  • 應用示例

ScrollBar

一個Material Design 滾動條,表示當前滾動到了什麼位置

  • 構造函數
 Scrollbar({
    Key key,
    @required this.child, // 子項 滾動條,不知道怎麼用呀
  })

  • 應用示例

CustomScrollView

一個使用slivers創建自定義的滾動效果的ScrollView

  • 構造函數
CustomScrollView({
    Key key,
    Axis scrollDirection = Axis.vertical,// // 滾動方向,水平和垂直
    bool reverse = false,// 子項是否倒序排列
    ScrollController controller,// 滾動位置控制器
    bool primary,// 是否有滾動效果
    ScrollPhysics physics,// 滾動類型
    bool shrinkWrap = false,
    double cacheExtent,
    this.slivers = const <Widget>[],// 視圖窗口中的sliver組件塊
    int semanticChildCount,
  })

  • 應用示例
class MyStatePageState extends State<MyStatePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("scrollable"),),
      body:CustomScrollView(
        // sliver組件塊
        slivers: <Widget>[
          const SliverAppBar(
            pinned: true,
            expandedHeight: 250.0,
            flexibleSpace: FlexibleSpaceBar(
              title: Text('Demo'),
            ),
          ),
          SliverGrid(
            gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
              maxCrossAxisExtent: 200.0,
              mainAxisSpacing: 10.0,
              crossAxisSpacing: 10.0,
              childAspectRatio: 4.0,
            ),
            delegate: SliverChildBuilderDelegate(
              (BuildContext context, int index) {
                return Container(
                  alignment: Alignment.center,
                  color: Colors.teal[100 * (index % 9)],
                  child: Text('Grid Item $index'),
                );
              },
              childCount: 20,
            ),
          ),
          SliverFixedExtentList(
            itemExtent: 50.0,
            delegate: SliverChildBuilderDelegate(
              (BuildContext context, int index) {
                return Container(
                  alignment: Alignment.center,
                  color: Colors.lightBlue[100 * (index % 9)],
                  child: Text('List Item $index'),
                );
              },
            ),
          ),
        ],
      ),
    );
  } 
}

NotificationListener

一個用來監聽樹上冒泡通知的widget

  • 構造函數
 NotificationListener({
    Key key,
    @required this.child,// 子項
    this.onNotification,// 
  })

  • 應用示例

ScrollConfiguration

控制可滾動組件在子樹中的表現行爲

  • 構造函數
ScrollConfiguration({
    Key key,
    @required this.behavior,// 子項組件scrollable的相關配置
    @required Widget child,// 子項組件
  }) 

  • 應用示例

refreshIndicator

Material Design下拉刷新指示器,包裝一個可滾動widget

  • 構造函數
 RefreshIndicator({
    Key key,
    @required this.child,
    this.displacement = 40.0,
    @required this.onRefresh,
    this.color,
    this.backgroundColor,
    this.notificationPredicate = defaultScrollNotificationPredicate,
    this.semanticsLabel,
    this.semanticsValue,
  })

  • 應用示例
class MyStatePageState extends State<MyStatePage>{
  // TODO: implement build
  var curPage = 1;
  ScrollController _controller = new ScrollController();
  var listData = List<String>.generate(30, (i) => "CL $i");

  Future<Null> _pullToRefresh() async {
    print("object.........................................");
//    curPage = 1;
  //下拉刷新做處理
    setState(() {
      ////改變數據,這裏隨意發揮
      listData = List<String>.generate(30, (i) => "CL $i");
    });
    return null;
  }

  MyStatePageState() {
    _controller.addListener(() {
      var maxScroll = _controller.position.maxScrollExtent;
      var pixels = _controller.position.pixels;

      if (maxScroll == pixels && listData.length < 100){
//        上拉刷新做處理
        print('load more ...');
//        curPage++;
        setState(() {
          //改變數據,這裏隨意發揮
          listData = List<String>.generate(100, (i) => "CL $i");
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {

    // 創建listview 列表
    Widget listView = new ListView.builder(
      itemCount: listData.length,
      itemBuilder: (context,i) {
        //這裏填充自己想要的列表UI
        return new Container(
          height: 45.0,
          color: Colors.blue,
          child: new Text(
            "bbbbbbbbbbbbbbbbbbbbbbb___$i",
            style: new TextStyle(fontSize: 15.0),
          ),
        );
      },
      controller: _controller,
    );
    
    return new RefreshIndicator(child: listView, onRefresh: _pullToRefresh);
  }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章