Flutter 实现下拉刷新 非安卓原生效果

先附上连接

https://github.com/dikeboy/flutter-refrensh

这里涉及到flutter中的 几块   动画 ,事件点击, 异步,

要自定义下拉刷新   首先必须要了解Flutter 中的事件监听方法

https://flutter.io/docs/development/ui/advanced/gestures

flutter 的手势主要是两个类listener 和GestureDecetor

Listener 主要类似touchevent  包括 按下,移动,松开 取消(划出屏幕)

GestureDecetor 主要就是一些手势形成效果  点击 双击 长按之类的

 

我这里是写在基类里,因为调用到修改界面  当然你也可以改成Mixin 

因为我这里是对ListView进行处理  也就是通过修改ListView的第一个header高度来实现下拉效果

  getRow(int position){
   if(position==0){
     return getRfrenshHeader();
   }
   else{
     return  Text(list[position-1]);
   }
  }

这里 -1 是因为本身header的高度已经算一个Item了

首先看下 state 的 initState方法

@override
  initState(){
    super.initState();

    animationController = AnimationController(
        duration: const Duration(milliseconds: 300), vsync: this);  //定义了一个300毫秒的动画控制器
    animation = Tween(begin: 1.0, end: 0.0).animate(animationController); //begin  end 也就是300毫秒时间内aimation的值从1.0 到0.0变化
    animation.addListener(() {
      setState(() {
        // the animation object’s value is the changed state
        headHeight = (len-headNormalHeight) *animation.value+headNormalHeight; //从touchUp 释放开始   header偏移量从1.0 到0.0移动  最终剩下header的高度
      });
    });
  }

Listener的实例化

typedef MStartRefrensh = void Function(); //定义一个方法用户回调  类似接口回调吧
 getPullListener({Widget child, MStartRefrensh startRefrensh,double height}){
    this.pointerUpListener = startRefrensh;
    headNormalHeight  =height;      //初始化Header的高度
    if(scrollController==null){
      scrollController = ScrollController(initialScrollOffset: height);  //初始化滚动条  flutter中如果需要监听 列表滑动  都需要滚动条
    }
    Listener listener = new Listener( child: child, onPointerDown: pointDown,onPointerUp: pointUp,onPointerMove: pointMove,onPointerCancel: pointCancle,);//这里也就是我们4个手势的监听方法
    if(!firstJump){
      setState(() {
          if(!firstJump&&scrollController.hasClients){  //hasClients可以用来判断 scrollerController是否已经绑定到listview上
            firstJump =true;
            scrollController.jumpTo(headNormalHeight); //第一次加载的时候 我们直接跳到Header的高度  从而让header隐藏在屏幕上面
          }
      });
    }
    return listener;
  }

下面看下手势事件

 pointDown(PointerDownEvent event){  //没没啥特别 记录下touchdown的坐标
    dx = event.position.dx;
    dy=event.position.dy;
    isTouchDown = true;
  }
  pointUp(PointerUpEvent event){   //释放的时候 如果head大于我们初始化的head 就说明需要刷新  启动一个回滚动画

if(headHeight>headNormalHeight){ startUpAnimation(headHeight); } else{ setState((){ headHeight=headNormalHeight; //这里主要是重置 避免未知问题 }); } isTouchDown = false; } pointCancle(PointerCancelEvent event){ //cancel跟UP逻辑一样 也可以自定义 if(headHeight>headNormalHeight){ startUpAnimation(headHeight); } else{ setState((){ headHeight=headNormalHeight; }); } isTouchDown = false; } pointMove(PointerMoveEvent event){ // print(_scrollController.position.pixels); setState(() { if(event.position.dy - dy>0) headHeight = (event.position.dy - dy)/2+headNormalHeight; //这里我设置header高度是滑动距离的1/2 实际效果有些也会有越滑越慢 可以根据开根号 或者2次方实现 }); }

下面是动画

startUpAnimation(double len) {
    this.len = len;
    if (animationController.isCompleted) {
      animationController.reset();  //动画结束后重置  以便下次接着用
    }
    animationController.forward().then((_) {
      headHeight = headNormalHeight;
      pointerUpListener();  //这个是自定义的回调事件 也就是初始化的时候传入的
//
    });
  }

刷新的header

//这里就用了系统的滚动条  要重写下来动画啥的都可以修改这里
getRfrenshHeader(){
if(headHeight==headNormalHeight&&!isTouchDown){
return Container(
child: SizedBox(
child: CircularProgressIndicator(valueColor: new AlwaysStoppedAnimation<Color>(Colors.orange)),
height: 20.0,
width: 20.0,
),
alignment: Alignment.center,
height: headHeight,
);
}
else{
return Container(
child: SizedBox(
child: Row(children: <Widget>[
new Image.asset('images/drop_refrensh.png'),
Text("释放刷新")
],
mainAxisAlignment: MainAxisAlignment.center,),
height: 20.0,
),
alignment: Alignment.center,
height: headHeight,
);
}
}

刷新结束需要主动关闭  

  finishLoading(){
     if(scrollController!=null&&scrollController.hasClients){
       scrollController.animateTo(
         headNormalHeight,
         curve: Curves.easeOut,
         duration: const Duration(milliseconds: 100),
       );
     }
  }

猜你喜欢

转载自www.cnblogs.com/dikeboy/p/10162420.html