ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

5)Learning diary for flutter

2020-02-05 18:42:51  阅读:260  来源: 互联网

标签:widget Point width pathA diary Learning data flutter size


No update for a long time.

This is about an interesting e-reader.

At present,The function is no prefect.

The main part is the widget be used to display the book content.

The code about this part seems  a little  long 

So in order to look more concise,first delete the detailed code 

The widget implements the path  calculation  according to the position of the finger.

The class pageClipper display the area of the page according to the path.


import 'dart:math';
import 'package:flutter/material.dart';


class BookWidget extends StatefulWidget {
  BookWidgetData data;
  bool enable;
  var callBack;
  var onFingerDown;

  BookWidget(this.data, this.enable, func(bool isNext, int page),
      func2(bool isNext, int page))
      : super() {
    print(data.bgStr);
    print(data.colorpos);
    callBack = func;
    onFingerDown = func2;
  }

  State state;

  State<StatefulWidget> createState() {
    state = BookWidgetState();
    return state;
  }

  void upData(BookWidgetData data) {
    if(data.page==-1||data.page==-2){
      data.bgStr="images/bg.jpeg";
    }
    (state as BookWidgetState).upData(data);
  }
}


class BookWidgetState extends State<BookWidget>  {
 

  void upData(BookWidgetData data) {
//    print("更新页面方法"+ widget.data.content);

    setState(() {
      widget.data = data;
//      widget.color = data.color;
//      widget.colorPos = data.colorpos;
      reset();
    });
//    print("更新页面方法end"+ widget.data.content);
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    isright = false;
    isleft = false;
    reset();
  }

  @override
  Widget build(BuildContext context) {
//    width=context.size.width;
//    height=context.size.height;
 

    return Listener(
      child: Stack(
        fit: StackFit.expand,
        children: [
          ClipPath(
            clipper: pageCliper(getPathBFromLower),
            child: Container(
              color: Colors.white,
              child: Text(""),
            ),
          ),
          ClipPath(
              clipper: pageCliper(getPathAFromLower),
              child: Container(
//            color: widget.data.page==-1||widget.data.page==-1
//                ? Colors.white
//                : null,
                child: Padding(
                  padding: const EdgeInsets.only(top: 30, left: 5, right: 5),
                  child: Text(
                    widget.data.content,
                    style: TextStyle(
                        color: Colors.black87,
                        fontSize: 24,
                        decoration: TextDecoration.none),
                  ),
                ),
                decoration: BoxDecoration(
                    image: DecorationImage(
                            image: AssetImage(widget.data.bgStr != null?widget.data.bgStr:"images/bg.jpeg"),
                            fit: BoxFit.cover)
                        ),
              ))
        ],
      ),
      onPointerMove: widget.enable ? onFingerMove : null,
      onPointerUp: widget.enable ? onFingerUp : null,
      onPointerDown: widget.enable ? onFingerDown : null,
    );
  }

  void reset() {
   
  }

  void onFingerDown(PointerDownEvent event) {
   
  }

  void onFingerUp(PointerUpEvent event) {

  }

  void onFingerMove(PointerMoveEvent details) {
   
  }

  Path getPathAFromLower(size) {
 
  }

  Path getPathAFromLowerLeft(Size size) {
   
  }

  Path getPathAFromLowerRight(Size size) {
   
  }

  Path getPathBFromLowerRight(Size size) {
   
  }

  Path getPathBFromLowerLeft(Size size) {
    
  }

 



class pageCliper extends CustomClipper<Path> {
  var getPath;

  pageCliper(fun(Size size)) : super() {
    this.getPath = fun;
  }

  @override
  Path getClip(Size size) {
//    print("重绘");
    return getPath(size);
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    // TODO: implement shouldReclip
    return true;
  }
}

Here is the complete code

The path algorithm draws on a blog about Android's native development of e-book source code

It has been modified and only a few of them are used to achieve the same effect of turning left and right pages


import 'dart:math';
import 'package:flutter/material.dart';

class BookWidgetData {
  String content;
  int page;
  Color color;
  String bgStr;
  int colorpos;

  BookWidgetData();

  BookWidgetData.name(this.content, this.page);

  Object get colorPos => null;
}

class BookWidget extends StatefulWidget {
  BookWidgetData data;
  bool enable;
  var callBack;
  var onFingerDown;

  BookWidget(this.data, this.enable, func(bool isNext, int page),
      func2(bool isNext, int page))
      : super() {
    print(data.bgStr);
    print(data.colorpos);
    callBack = func;
    onFingerDown = func2;
  }

  State state;

  State<StatefulWidget> createState() {
    state = BookWidgetState();
    return state;
  }

  void upData(BookWidgetData data) {
    if(data.page==-1||data.page==-2){
      data.bgStr="images/bg.jpeg";
    }
    (state as BookWidgetState).upData(data);
  }
}

bool isright, isleft;

class BookWidgetState extends State<BookWidget> with TickerProviderStateMixin {
  Point a, f, g, e, h, c, j, b, k, d, i;
  double width, height;
  double lPathAShadowDis, rPathAShadowDis;
  AnimationController animationController;
  AnimationController animationController2;
  Animation<double> animation;

  void upData(BookWidgetData data) {
//    print("更新页面方法"+ widget.data.content);

    setState(() {
      widget.data = data;
//      widget.color = data.color;
//      widget.colorPos = data.colorpos;
      reset();
    });
//    print("更新页面方法end"+ widget.data.content);
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    isright = false;
    isleft = false;
    reset();
  }

  double startx, starty, endx;
  double scale;

  void startAnimal() {
//    count++;
    startx = a.x;
    starty = a.y;
    if (endx == width) {
      scale = (height - a.y) / (width - a.x);
    } else {
      scale = (height - a.y) / a.x;
    }
//    print("调用了一次$count");
    f.x = width;
    f.y = height;
    animation = new Tween(begin: startx, end: endx).animate(animationController)
      ..addListener(() {
        setState(() {
          a.x = animation.value;
          double add = animation.value - startx;
//          print(widget.data.content +
//              "增长值$add" +
//              "比率$scale" +
//              "stratX开始值$startx startY开始值");
          if (endx == width) {
            a.y = starty + add * scale;
          } else {
            a.y = starty - add * scale;
          }
          if (isleft) {
            a.x = width - a.x;
          }
          calcPointsXY(a, f);
        });
      })
      ..addStatusListener((AnimationStatus state) {
        if(state==AnimationStatus.dismissed){
          setState(() {
            reset();
          });

        }
        if (state == AnimationStatus.completed) {
//         animationController.reset();
          setState(() {
            reset();
          });
        }
      });
    animationController.forward();
  }

  void startAnimal2() {
//    count++;
    startx = a.x;
    starty = a.y;
    if (endx == width) {
      scale = (height - a.y) / (width - a.x);
    } else {
      scale = (height - a.y) / a.x;
    }
//    print("调用了一次$count");

    f.x = width;
    f.y = height;
    animation =
        new Tween(begin: startx, end: endx).animate(animationController2)
          ..addListener(() {
            setState(() {
              a.x = animation.value;
              double add = animation.value - startx;
//              print(widget.data.content +
//                  "增长值$add" +
//                  "比率$scale" +
//                  "stratX开始值$startx startY开始值");
              if (endx == width) {
                a.y = starty + add * scale;
              } else {
                a.y = starty - add * scale;
              }
              if (isleft) {
                a.x = width - a.x;
              }
//              print("x值");
//              print(a.x);
              calcPointsXY(a, f);
            });
          })
          ..addStatusListener((AnimationStatus state) {
            if(state==AnimationStatus.dismissed){
              setState(() {
                reset();
              });

            }
            if (state == AnimationStatus.completed) {
//         animationController.reset();
              setState(() {
                reset();
              });

              if (isright) {
                widget.callBack(true, widget.data.page);
              } else {
                widget.callBack(false, widget.data.page);
              }
            }
          });
    animationController2.forward();
  }

  @override
  Widget build(BuildContext context) {
//    width=context.size.width;
//    height=context.size.height;
    animationController = new AnimationController(
        duration: const Duration(milliseconds: 500), vsync: this);

    animationController2 = new AnimationController(
        duration: const Duration(milliseconds: 500), vsync: this);

    return Listener(
      child: Stack(
        fit: StackFit.expand,
        children: [
          ClipPath(
            clipper: pageCliper(getPathBFromLower),
            child: Container(
              color: Colors.white,
              child: Text(""),
            ),
          ),
          ClipPath(
              clipper: pageCliper(getPathAFromLower),
              child: Container(
//            color: widget.data.page==-1||widget.data.page==-1
//                ? Colors.white
//                : null,
                child: Padding(
                  padding: const EdgeInsets.only(top: 30, left: 5, right: 5),
                  child: Text(
                    widget.data.content,
                    style: TextStyle(
                        color: Colors.black87,
                        fontSize: 24,
                        decoration: TextDecoration.none),
                  ),
                ),
                decoration: BoxDecoration(
                    image: DecorationImage(
                            image: AssetImage(widget.data.bgStr != null?widget.data.bgStr:"images/bg.jpeg"),
                            fit: BoxFit.cover)
                        ),
              ))
        ],
      ),
      onPointerMove: widget.enable ? onFingerMove : null,
      onPointerUp: widget.enable ? onFingerUp : null,
      onPointerDown: widget.enable ? onFingerDown : null,
    );
  }

  void reset() {
    a = Point();
    a.x = -1;
    a.y = -1;
    f = Point();
    g = Point();
    e = Point();
    h = Point();
    c = Point();
    j = Point();
    b = Point();
    k = Point();
    d = Point();
    i = Point();
  }

  void onFingerDown(PointerDownEvent event) {
    isright = false;
    isleft = false;
    if (event.position.dx > width - 100 && event.position.dy > height - 100) {
      isright = true;
      widget.onFingerDown(true, widget.data.page);
    } else if (event.position.dx < 100 && event.position.dy > height - 100) {
      isleft = true;
      widget.onFingerDown(false, widget.data.page);
    }
  }

  void onFingerUp(PointerUpEvent event) {

    a.x = event.position.dx;
    a.y = event.position.dy;
    if (isright && a.x < 100) {
//      reset();
      endx =0;
      a.x = event.position.dx;
      a.y = event.position.dy;
      if(a.x==0){
        a.x=1;
      }
      startAnimal2();
//      widget.callBack(true, widget.data.page);
    } else if (isleft && a.x > width - 100) {
//      reset();
      endx = width;
      a.x = event.position.dx;
      a.y = event.position.dy;
      startAnimal2();
//      widget.callBack(false, widget.data.page);
    } else if(isright||isleft){
      reset();
      a.x = event.position.dx;
      a.y = event.position.dy;
      if (isright)
        endx = width;
      else
        endx = 0;
      startAnimal();
//      setState(() {
//        reset();
//      });
    }
  }

  void onFingerMove(PointerMoveEvent details) {
    if (isleft || isright) {
      setState(() {
        a.x = details.localPosition.dx;
        a.y = details.localPosition.dy;
        f.x = width;
        f.y = height;
        if (isleft) {
          a.x = width - a.x;
        }
        calcPointsXY(a, f);
      });
    }
  }

  Path getPathAFromLower(size) {
    if (isright) {
      return getPathAFromLowerRight(size);
    } else {
      return getPathAFromLowerLeft(size);
    }
  }

  Path getPathAFromLowerLeft(Size size) {
    var pathA = Path();
    if (a.x == -1 && a.y == -1||c.x==null) {
      width = size.width;
      height = size.height;
      pathA.lineTo(0, size.height);
      pathA.lineTo(size.width, size.height);
      pathA.lineTo(size.width, 0);
      return pathA;
    }
    pathA.lineTo(size.width, size.height); //移动到右下角
    pathA.lineTo(size.width - c.x, c.y); //移动到c点
    pathA.quadraticBezierTo(
        size.width - e.x, e.y, size.width - b.x, b.y); //从c到b画贝塞尔曲线,控制点为e
    pathA.lineTo(width - a.x, a.y); //移动到a点
    pathA.lineTo(size.width - k.x, k.y); //移动到k点
    pathA.quadraticBezierTo(
        size.width - h.x, h.y, size.width - j.x, j.y); //从k到j画贝塞尔曲线,控制点为h
    pathA.lineTo(0, 0); //移动到左上角
    pathA.lineTo(size.width, 0);
    pathA.lineTo(size.width, size.height);
    return pathA;
  }

  Path getPathAFromLowerRight(Size size) {
    var pathA = Path();
    if (a.x == -1 && a.y == -1) {
      width = size.width;
      height = size.height;
      pathA.lineTo(0, size.height);
      pathA.lineTo(size.width, size.height);
      pathA.lineTo(size.width, 0);
      return pathA;
    }
    pathA.lineTo(0, size.height); //移动到左下角
    pathA.lineTo(c.x, c.y); //移动到c点
    pathA.quadraticBezierTo(e.x, e.y, b.x, b.y); //从c到b画贝塞尔曲线,控制点为e
    pathA.lineTo(a.x, a.y); //移动到a点
    pathA.lineTo(k.x, k.y); //移动到k点
    pathA.quadraticBezierTo(h.x, h.y, j.x, j.y); //从k到j画贝塞尔曲线,控制点为h
    pathA.lineTo(size.width, 0); //移动到右上角
    pathA.close(); //闭合区域
    return pathA;
  }

  Path getPathBFromLower(size) {
    if (isright) {
      return getPathBFromLowerRight(size);
    } else {
      return getPathBFromLowerLeft(size);
    }
  }

  Path getPathBFromLowerRight(Size size) {
    Path pathB = Path();
    if (a.x == -1) {
      return pathB;
    }
    pathB.moveTo(i.x, i.y); //移动到i点
    pathB.lineTo(d.x, d.y); //移动到d点
    pathB.lineTo(b.x, b.y); //移动到b点
    pathB.lineTo(a.x, a.y); //移动到a点
    pathB.lineTo(k.x, k.y); //移动到k点
    return pathB;
  }

  Path getPathBFromLowerLeft(Size size) {
    Path pathB = Path();
    if (a.x == -1) {
      return pathB;
    }
    print(size.width);
    pathB.moveTo(size.width - i.x, i.y); //移动到i点
    pathB.lineTo(size.width - d.x, d.y); //移动到d点
    pathB.lineTo(size.width - b.x, b.y); //移动到b点
    pathB.lineTo(size.width - a.x, a.y); //移动到a点
    pathB.lineTo(size.width - k.x, k.y); //移动到k点
    return pathB;
  }

  void calcPointAByTouchPoint() {
    double w0 = width - c.x;

    double w1 = (f.x - a.x).abs();
    double w2 = width * w1 / w0;
    a.x = (f.x - w2).abs();

    double h1 = (f.y - a.y).abs();
    double h2 = w2 * h1 / w1;
    a.y = (f.y - h2).abs();
  }

  /**
   * 计算各点坐标
   * @param a
   * @param f
   */
  void calcPointsXY(Point a, Point f) {
    g.x = (a.x + f.x) / 2;
    g.y = (a.y + f.y) / 2;

    e.x = g.x - (f.y - g.y) * (f.y - g.y) / (f.x - g.x);
    e.y = f.y;

    h.x = f.x;
    h.y = g.y - (f.x - g.x) * (f.x - g.x) / (f.y - g.y);

    c.x = e.x - (f.x - e.x) / 2;
    c.y = f.y;

    j.x = f.x;
    j.y = h.y - (f.y - h.y) / 2;

    b = getIntersectionPoint(a, e, c, j);
    k = getIntersectionPoint(a, h, c, j);

    d.x = (c.x + 2 * e.x + b.x) / 4;
    d.y = (2 * e.y + c.y + b.y) / 4;

    i.x = (j.x + 2 * h.x + k.x) / 4;
    i.y = (2 * h.y + j.y + k.y) / 4;

    //计算d点到ae的距离
    double lA = a.y - e.y;
    double lB = e.x - a.x;
    double lC = a.x * e.y - e.x * a.y;

    lPathAShadowDis =
        ((lA * d.x + lB * d.y + lC) / sqrt(pow(lA, 2) + pow(lB, 2))).abs();

    //计算i点到ah的距离
    double rA = a.y - h.y;
    double rB = h.x - a.x;
    double rC = a.x * h.y - h.x * a.y;
    rPathAShadowDis =
        ((rA * i.x + rB * i.y + rC) / sqrt(pow(rA, 2) + pow(rB, 2))).abs();
  }

  /**
   * 计算两线段相交点坐标
   * @param lineOne_My_pointOne
   * @param lineOne_My_pointTwo
   * @param lineTwo_My_pointOne
   * @param lineTwo_My_pointTwo
   * @return 返回该点
   */
  Point getIntersectionPoint(
      Point lineOne_My_pointOne,
      Point lineOne_My_pointTwo,
      Point lineTwo_My_pointOne,
      Point lineTwo_My_pointTwo) {
    double x1, y1, x2, y2, x3, y3, x4, y4;
    x1 = lineOne_My_pointOne.x;
    y1 = lineOne_My_pointOne.y;
    x2 = lineOne_My_pointTwo.x;
    y2 = lineOne_My_pointTwo.y;
    x3 = lineTwo_My_pointOne.x;
    y3 = lineTwo_My_pointOne.y;
    x4 = lineTwo_My_pointTwo.x;
    y4 = lineTwo_My_pointTwo.y;

    double pointX =
        ((x1 - x2) * (x3 * y4 - x4 * y3) - (x3 - x4) * (x1 * y2 - x2 * y1)) /
            ((x3 - x4) * (y1 - y2) - (x1 - x2) * (y3 - y4));
    double pointY =
        ((y1 - y2) * (x3 * y4 - x4 * y3) - (x1 * y2 - x2 * y1) * (y3 - y4)) /
            ((y1 - y2) * (x3 - x4) - (x1 - x2) * (y3 - y4));

    return new Point.name(pointX, pointY);
  }

  /**
   * 计算C点的X值
   * @param a
   * @param f
   * @return
   */
  double calcPointCX(Point a, Point f) {
    Point g, e;
    g = new Point();
    e = new Point();
    g.x = (a.x + f.x) / 2;
    g.y = (a.y + f.y) / 2;

    e.x = g.x - (f.y - g.y) * (f.y - g.y) / (f.x - g.x);
    e.y = f.y;

    return e.x - (f.x - e.x) / 2;
  }
}

class Point {
  double x;
  double y;

  Point();

  Point.name(this.x, this.y);
}

class pageCliper extends CustomClipper<Path> {
  var getPath;

  pageCliper(fun(Size size)) : super() {
    this.getPath = fun;
  }

  @override
  Path getClip(Size size) {
//    print("重绘");
    return getPath(size);
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    // TODO: implement shouldReclip
    return true;
  }
}

 

雨痕消失 发布了26 篇原创文章 · 获赞 0 · 访问量 7938 私信 关注

标签:widget,Point,width,pathA,diary,Learning,data,flutter,size
来源: https://blog.csdn.net/u011334510/article/details/104185888

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有