Flutter绘制k线图——第二节增加水平滑动和双指缩放

733 阅读2分钟

**首先效果上图:

再上代码

注意开头的时候,动态增加了4条数据,柱子和线都变了,如果你们用websocket或者tcp传输不间断数据,就动态了。 now,let‘s go。

分为三节:

1、完成静态单页面K线图

2、增加水平滑动和双指缩放

3、增加当前值水平线,最后的柱子跟随变化,长按事件

思想:利用GestureDetector和RawGestureDetector,处理一下滑动冲突,笔者再发现缩放时,取消滑动事件。

这里时滑动,当缩放开始时allowDrag = false;阻止两者一起动。

      onHorizontalDragUpdate: allowDrag ? _dragUpdate : null,
        onHorizontalDragStart: _dragStart,
        onHorizontalDragEnd: _dragEnd,
  _dragUpdate(DragUpdateDetails details) {
  //此处的 *1为系数,可以改变这个值来改变offsetNum, 即可当成滑动阻尼来用。
    int offsetNum = (details.delta.dx *  1).toInt();
    //offsetNum只让慢慢改变
    if(offsetNum <0 && offsetNum> -1){
      offsetNum = -1;
    }else if(offsetNum >0 && offsetNum< 1){
      offsetNum = 1;
    }
    //用来确定显示的数据集,通过_subList()
    start = start - offsetNum;
    end = end - offsetNum;
    //保证不越界
    if (end >=  widget.dataList.length) {
      end =  widget.dataList.length;
      start = end -  lastNum;
    }
    if (start <=  widget.maxPreDay) {
      start =  widget.maxPreDay;
      end = start +  lastNum;
    }
   //计算出出现在屏幕上的数据集
    _data = _subList(start, end: end);
    setState(() {});
  }

从整个数据中通过start和end,抽取一部分到屏幕上

 //获取段落
  List _subList(int start, {int end}) {
    List result;
    if (end != null) {
      result =  widget.dataList.sublist(start, end);
    } else {
      result =  widget.dataList.sublist(start);
    }
    return result;
  }

这里需要用自定义的Recognizer,通过重写rejectGesture方法来改变冲突时的决定 此处,当该手势竞争失败时,强行执行竞争成功的方法,不过此时两个手势都会执行,我们会在update中禁止其中之一

 @override
  void rejectGesture(int pointer) {
  //当battle失败后执行的语句
    acceptGesture(pointer);//强行执行竞争成功的方法,
  }
RawGestureDetector(
          gestures: {
            ScaleEveryGestureRecognizer:GestureRecognizerFactoryWithHandlers<ScaleEveryGestureRecognizer>(
                    () =>ScaleEveryGestureRecognizer(),
                    (ScaleEveryGestureRecognizer instance){
                  instance.onUpdate = (ScaleUpdateDetails de){
                    if(de.horizontalScale != 1.0){
                      _scaleUpload(de);
                    };
                  };
                  instance.onStart = handleScaleStart;
                  instance.onEnd = _scaleEnd;
                }

//缩放时的事件

  _scaleUpload(ScaleUpdateDetails details) {
    allowDrag = false;//禁止滑动事件
    //if(details.horizontalScale != 1.0){
      double ho = (details.horizontalScale - 1).abs();
      double ve = (details.verticalScale - 1).abs();
        if (isFirstScaleFrame) {
          isFirstScaleFrame = false;
          return;
       }
        double scale = details.horizontalScale;
        //决定当前显示k柱总数
        currentNum = ((1 / scale) * lastNum).floor();
        currentNum = (currentNum *  widget.scaleDamp).toInt();
        currentNum = clamp(widget.minNum, widget.dataList.length -  widget.maxPreDay, currentNum);
        //改变起始值和结束值
        double center = (end + start)/2;//保证缩放时中心不变, 当你发现中心改变了的时候,请再观察是否已经到了终点
        //加0.5保证均衡性,要是不加会发现缩放时一边倒
        end =  (center + currentNum/2 +0.5).toInt();
        start = (center - currentNum/2).toInt();
        if (end >=  widget.dataList.length) {
          end =  widget.dataList.length;
          start = end -  currentNum;
        }
        if (start <=  widget.maxPreDay) {
          start =  widget.maxPreDay;
          end = start +  currentNum;
        }
        //重新取值
        _data = _subList(start, end: end);
        setState(() {});
     
    }

本节核心就这些,详情看源码。如果觉得可以一看,请看下节。