Flutter

Flutter 学习之旅(十六) 可滚动控件Scrolla

2020-08-18  本文已影响0人  Tsm_2020

讲到滚动控件大家可能都比较熟悉的ListView 与 GridView ,
在flutter 中ListView 与GridView 都是继承自BoxScrollView,而 BoxScrollView 继承自ScrollView,
如果想要为一个控件添加可滚动状态,必须要包含一个组件Scrollable,这种继承关系在源码中非常简单就能找到


image.png

那我们就自上而下的开始分析 先来看一下Scrollable 的属性介绍

Scrollable

Scrollable({
    Key key,
    ///滚动方向
    this.axisDirection = AxisDirection.down,
    ///滚动控制器和事件监听
    ///在源码中是这样介绍的  ScrollController.initialScrollOffset  控制初始滚动的位置
    ///ScrollController.keepScrollOffset  控制是否应该自动在[PageStorage]中保存并恢复其滚动位      
    ///置
    ///ScrollController.offset 用来读取当前滚动位置
    this.controller,
    ///决定widget 在用户完成拖拽后的动画响应默认情况下会更护不同环境设置不同的变量
    ///ClampingScrollPhysics  android 使用的水波纹效果
    ///BouncingScrollPhysics:iOS下弹性效果  如果android 想要实现这个效果
    ///子布局高度的综合必须大于listview 的实际高度度即viewport
    this.physics,
    ///  用于生成子布局   类似android 中adapter 的getItem 方法
    @required this.viewportBuilder,
    ///
    this.incrementCalculator,
    /// 是否公开在语义数中,便于类似talkback的软件识别
    this.excludeFromSemantics = false,
    ///语义子集数
    this.semanticChildCount,
    ///处理拖动开始行为的方式与时机 
    ///有两个值 DragStartBehavior.start  DragStartBehavior.down 
    ///从字面理解就   start是从拖动开始,down是从触摸事件按下开始
    this.dragStartBehavior = DragStartBehavior.start,
  })

重要属性

axisDirection

控制滑动方向,必须一个listview想要从垂直滑动变换到水平滑动改一下这个属性就好了

controller

非常重要的属性,如果想要监听listview 的滑动偏移量和滚动到哪个条目都可以用它来实现,
但是这里面有个比较坑的地方就是controller.animateTo()他的入参是偏移量,如果你想要准确滑动的某一个条目,就需要自己去计算了,如果条目不规则,你就要计算多个了,
这里说一个比较常用的方法,

/// 创建controller 的时候可以指定 offset 偏移量,不是偏移的条目数,就是偏移的距离,单位像素
ScrollController(initialScrollOffset: 50,keepScrollOffset: true)

///同时你也可以获取他的offset
var offset=_controller.offset  ;

//controller 内部实现逻辑写这个只是为了证明offset的单位是像素
double get offset => position.pixels;

/// 为controller 添加滑动监听,源码中这样介绍的,如果没有添加任何监听,你可以忽略他,
///在控件dispose之后.你不能再调用他了,意思就是想要移出就必要在dispose之前,
///如果同一个监听,你添加了两次,那么你就必须移出两次,否则还是会有消息回来,
_controller.addListener(lis);

///移出消息监听
 _controller?.removeListener(lis);
 ///消息监听的方法,打印一下偏移量和position  
  void lis(){
    printString('offset:${_controller.offset}     positon:${_controller.position}');
  }
///controller 还可以控制滚动到固定位置,入参都是偏移量,不是item的position  
 _controller.animateTo(offset, duration: null, curve: null);////有动画
 _controller.jumpTo(value);///无动画

physics

决定widget 在用户完成拖拽后的动画响应,默认情况下会根据不同环境设置不同的变量
ClampingScrollPhysics android 使用的水波纹效果
BouncingScrollPhysics:iOS下弹性效果 如果android 想要实现这个效果
子布局高度的总和必须大于listview 的实际高度度即viewport
这里试验一下指定BouncingScrollPhysics

下面用ListView 举个例子

Scaffold(
      appBar: AppBar(
        title: Text('主页 ListView 属性'),
        centerTitle: true ,
      ),
      floatingActionButton: FloatingActionButton(
        child: inflateText("跳跃", Colors.white, 15),
        onPressed:(){
          _controller.animateTo(100, duration: Duration(milliseconds: 500), curve: Curves.ease);
        },
      ),
      body: Container(
        color: Colors.white,
        child: ListView.builder(
          ///类似ios 月结回弹的效果,但是需要列表的长度必须沾满他的viewport
          ///也就是子布局高度的总和必须大于listview 的实际高度度
          physics: BouncingScrollPhysics(),
          controller: _controller,
          scrollDirection: _direction,
          itemBuilder: (BuildContext, int) => Container(
              child: RaisedButton(
                child: Center(
                  child: Text(
                    list[int],
                    style: TextStyle(color: Colors.black87, fontSize: 16),
                  ),
                ),
                onPressed: () {
                  _onPressedItem(context, int);
                },
              )),
          itemCount: list.length,
        ),
      ),
    );
  }

  Future<void> _onPressedItem(BuildContext context, int index) async {
    switch (index) {
      case 0:
        Navigator.of(context).pushNamed(page_routes_scaffold);
        break;
      case 1:
        Navigator.of(context).pushNamed(page_routes_appbar);
        break;
      case 2:
        Navigator.of(context).pushNamed(page_routes_container);
        break;
      case 3:
        Navigator.of(context).pushNamed(page_routes_row_and_column);
        break;
      case 4:
        Navigator.of(context).pushNamed(page_routes_text);
        break;
      case 5:
        Navigator.of(context).pushNamed(page_routes_text_field);
        break;
      case 6:
        Navigator.of(context).pushNamed(page_routes_raised_button);
        break;
      case 7:
        Navigator.of(context).pushNamed(page_routes_icon);
        break;
      case 8:
        [Permission.storage, Permission.camera].request()
          ..then((value) {
            if (value[Permission.storage].isGranted) {
              if (value[Permission.camera].isGranted) {
                Navigator.of(context).pushNamed(page_routes_iamge);
              }
            }
          });
        //还有一种写法是
//      var result = await Permission.storage.request();
//      if (result.isGranted) {
//        Navigator.of(context).pushNamed(page_routes_iamge);
//      }
        break;

      case 9:///切换方向
        setState(() {
          if(_direction==Axis.vertical){
            _direction=Axis.horizontal;
          }else{
            _direction=Axis.vertical;
          }
        });
        break;
    }
  }
}

ScrollBar

如果为类似ListView GridView 等继承自ScrollView 的控件外部添加ScrollBar节点,则会显示出侧边指示条

效果


GIF 2020-8-20 15-03-19.gif

里面就包含了回弹效果,
自动跳跃到指定位置,
滑动监听
改变listview的滑动方向

我学习flutter的整个过程都记录在里面了
https://www.jianshu.com/c/36554cb4c804

最后附上demo 地址

https://github.com/tsm19911014/tsm_flutter

上一篇下一篇

猜你喜欢

热点阅读