<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Flutter仿真翻頁效果

          共 24933字,需瀏覽 50分鐘

           ·

          2021-03-06 00:25

          1-2 月份的閑暇時間,我自己就試著寫過仿真翻頁效果,但能力有限,寫出來的效果不盡人意??汕傻氖亲蛱煳揖驼业絼e人寫的仿真效果的 Flutter 源碼。所以也想分享一下。但這個肯定還不是在項目中就直接用的那種,但也相差不多。

          效果

          源碼地址

          GitHub 仿真翻頁源碼地址

          https://github.com/CarGuo/gsy_flutter_demo/tree/master/lib/widget/book_pages


          全部代碼

          此處再貼一次,翻頁源碼。

          BookPage

          import 'package:flutter/material.dart';
          import 'book_painter.dart';import 'cal_point.dart';
          class BookPage extends StatefulWidget { @override _BookPageState createState() => _BookPageState();}
          class _BookPageState extends State<BookPage> with SingleTickerProviderStateMixin { CalPoint curPoint = CalPoint.data(-1, -1); CalPoint prePoint = CalPoint.data(-1, -1);
          PositionStyle style = PositionStyle.STYLE_LOWER_RIGHT; double width; double height; AnimationController animationController; Animation cancelAnim; Tween cancelValue; bool needCancelAnim = true;
          toNormal([_]) { if (needCancelAnim) { startCancelAnim(); } else { setState(() { style = PositionStyle.STYLE_LOWER_RIGHT; prePoint = CalPoint.data(-1, -1); curPoint = CalPoint.data(-1, -1); }); } }
          toDragUpdate(d) { var x = d.localPosition.dx; var y = d.localPosition.dy; setState(() { curPoint = CalPoint.data(x, y); }); }
          toDown(TapDownDetails d) { prePoint = CalPoint.data(-1, -1); var dy = d.localPosition.dy; var dx = d.localPosition.dx;
          if (dx <= width / 3) { //左 style = PositionStyle.STYLE_LEFT; } else if (dx > width / 3 && dy <= height / 3) { //上 style = PositionStyle.STYLE_TOP_RIGHT; } else if (dx > width * 2 / 3 && dy > height / 3 && dy <= height * 2 / 3) { //右 style = PositionStyle.STYLE_RIGHT; } else if (dx > width / 3 && dy > height * 2 / 3) { //下 style = PositionStyle.STYLE_LOWER_RIGHT; } else if (dx > width / 3 && dx < width * 2 / 3 && dy > height / 3 && dy < height * 2 / 3) { //中 style = PositionStyle.STYLE_MIDDLE; }
          var x = d.localPosition.dx; var y = d.localPosition.dy; setState(() { curPoint = CalPoint.data(x, y); }); }
          startCancelAnim() { double dx, dy; if (style == PositionStyle.STYLE_TOP_RIGHT) { dx = (width - 1 - prePoint.x); dy = (1 - prePoint.y); } else if (style == PositionStyle.STYLE_LOWER_RIGHT) { dx = (width - 1 - prePoint.x); dy = (height - 1 - prePoint.y); } else { dx = prePoint.x - width; dy = -prePoint.y; } cancelValue = Tween(begin: Offset(prePoint.x, prePoint.y), end: Offset(dx, dy)); animationController.forward(); }
          _initCancelAnim() { animationController = new AnimationController( vsync: this, duration: Duration(milliseconds: 300)); cancelAnim = animationController.drive(CurveTween(curve: Curves.linear)); cancelAnim ..addListener(() { if (animationController.isAnimating) { setState(() { var bdx = cancelValue.begin.dx; var bdy = cancelValue.begin.dy;
          var edx = cancelValue.end.dx; var edy = cancelValue.end.dy;
          curPoint = CalPoint.data( bdx + edx * cancelAnim.value, bdy + edy * cancelAnim.value); }); } }) ..addStatusListener((status) { if (status == AnimationStatus.completed) { print("object"); setState(() { style = PositionStyle.STYLE_LOWER_RIGHT; prePoint = CalPoint.data(-1, -1); curPoint = CalPoint.data(-1, -1); animationController.reset(); }); } }); }
          @override void initState() { super.initState(); _initCancelAnim(); }
          @override Widget build(BuildContext context) { width = MediaQuery.of(context).size.width; height = MediaQuery.of(context).size.height - kToolbarHeight; Color bgColor = Colors.tealAccent; return Scaffold( appBar: AppBar( title: new Text("BookPage"), ), body: Container( height: height, width: width, child: GestureDetector( onTapDown: toDown, onTapUp: toNormal, onPanEnd: (detail) { // needCancelAnim = false; // if (IsRight) { // needCancelAnim = false; // } else { // needCancelAnim = true; // } toNormal(); }, onPanCancel: toNormal, onPanUpdate: (detail) { toDragUpdate(detail); }, child: CustomPaint( painter: BookPainter( text: content, text2: content2, viewWidth: width, viewHeight: height, cur: curPoint, pre: prePoint, style: style, bgColor: bgColor, frontColor: Colors.yellow, limitAngle: true, changedPoint: (pre) { prePoint = pre; }, ), ), ), ), ); }}
          const content = """林語堂\n一、腰有十文錢必振衣作響;\n二、每與人言必談及貴戚;\n三、遇美人必急索登床;\n四、見到問路之人必作傲睨之態(tài);\n五、與朋友相聚便喋喋高吟其酸腐詩文;\n六、頭已花白卻喜唱艷曲;\n七、施人一小惠便廣布于眾;\n八、與人交談便借刁言以逞才;\n九、借人之債時其臉如丐,被人索償時則其態(tài)如王;\n十、見人常多蜜語而背地卻常揭人短處。""";
          const content2 = """林語堂\n1.人本過客來無處,休說故里在何方。隨遇而安無不可,人間到處有芳香?!终Z堂\n2.人生不過如此,且行且珍惜。自己永遠(yuǎn)是自己的主角,不要總在別人的戲劇里充當(dāng)著配角?!终Z堂《人生不過如此》\n3.最明亮?xí)r總是最迷茫,最繁華時也是最悲涼。——林語堂《京華煙云》\n4.理想的人并不是完美的人,通常只是受人喜愛,并且通情達(dá)理的人,而我只是努力去接近于此罷了?!终Z堂""";

          BookPainter

          import 'package:flutter/material.dart';import 'dart:ui' as ui;import 'cal_point.dart';import 'dart:math' as Math;
          ///觸摸類型enum PositionStyle { STYLE_TOP_RIGHT, STYLE_LOWER_RIGHT, STYLE_LEFT, STYLE_RIGHT, STYLE_MIDDLE,}
          ///頁面畫筆class BookPainter extends CustomPainter { CalPoint a, f, g, e, h, c, j, b, k, d, i;
          double viewWidth; double viewHeight;
          ///頂部區(qū)域 Path pathA;
          ///折疊出來的區(qū)域 Path pathC;
          ///背部區(qū)域 Path pathB;
          ///背景畫筆 Paint bgPaint;
          ///繪制區(qū)域畫筆 Paint pathAPaint, pathCPaint, pathBPaint;
          ///觸摸點(diǎn)的區(qū)域 PositionStyle style;
          ///回調(diào)數(shù)據(jù)外放 ValueChanged changedPoint;
          ///背景色 Color bgColor;
          ///前景色 Color frontColor;
          ///文本一 String text;
          ///文本二 String text2;
          ///A區(qū)域左陰影矩形短邊長度參考值 double lPathAShadowDis = 0;
          /// A區(qū)域右陰影矩形短邊長度參考值 double rPathAShadowDis = 0;
          BookPainter({ @required this.text, @required this.text2, @required this.viewWidth, @required this.viewHeight, @required this.frontColor, @required this.bgColor, @required CalPoint cur, @required CalPoint pre, @required this.changedPoint, @required this.style, bool limitAngle, }) { init(cur, pre, limitAngle); }
          @override bool shouldRepaint(CustomPainter oldDelegate) => true;
          @override void paint(Canvas canvas, Size size) { onDraw(canvas, size); }
          init(CalPoint cur, CalPoint pre, bool limitAngle) { ///初始化點(diǎn) _initPoint();
          ///選擇工作模型 _selectCalPoint(cur, pre, limitAngle: limitAngle);
          ///計算 _calcPointsXY(a, f);
          ///初始化 _initPaintAndPath(); }
          _initPoint() { ///計算起始觸摸點(diǎn) a = CalPoint();
          ///計算的位置起點(diǎn) f = CalPoint();
          ///其他坐標(biāo) g = new CalPoint(); e = new CalPoint(); h = new CalPoint(); c = new CalPoint(); j = new CalPoint(); b = new CalPoint(); k = new CalPoint(); d = new CalPoint(); i = new CalPoint();
          pathB = new Path(); pathA = new Path(); pathC = new Path(); }
          _selectCalPoint(CalPoint cur, CalPoint pre, {bool limitAngle = true}) { a.x = cur.x; a.y = cur.y; doCalAngle() { CalPoint touchPoint = CalPoint.data(cur.x, cur.y); if (f.x != null && touchPoint.x != null && (limitAngle != null && limitAngle)) { ///如果大于0則設(shè)置a點(diǎn)坐標(biāo)重新計算各標(biāo)識點(diǎn)位置,否則a點(diǎn)坐標(biāo)不變 if (_calcPointCX(touchPoint, f) > 0) { changedPoint?.call(cur); _calcPointsXY(a, f); } else { a.x = pre.x; a.y = pre.y; _calcPointsXY(a, f); } } else if (_calcPointCX(touchPoint, f) < 0) { ///如果c點(diǎn)x坐標(biāo)小于0則重新測量a點(diǎn)坐標(biāo) _calcPointAByTouchPoint(); _calcPointsXY(a, f); } else { a.x = pre.x; a.y = pre.y; } }
          switch (style) { case PositionStyle.STYLE_TOP_RIGHT: f.x = viewWidth; f.y = 0; doCalAngle(); break; case PositionStyle.STYLE_LOWER_RIGHT: f.x = viewWidth; f.y = viewHeight; doCalAngle(); break; case PositionStyle.STYLE_LEFT: case PositionStyle.STYLE_RIGHT: case PositionStyle.STYLE_MIDDLE: a.y = viewHeight - 1; f.x = viewWidth; f.y = viewHeight; _calcPointsXY(a, f); break; default: break; } }
          _initPaintAndPath() { bgPaint = new Paint(); bgPaint.color = Colors.white;
          pathAPaint = new Paint(); pathAPaint.color = bgColor; pathAPaint.isAntiAlias = true;
          pathCPaint = new Paint(); pathCPaint.color = frontColor; pathCPaint.blendMode = BlendMode.dstATop; pathCPaint.isAntiAlias = true;
          pathBPaint = new Paint(); pathBPaint.color = Colors.tealAccent; pathBPaint.blendMode = BlendMode.dstATop; pathBPaint.isAntiAlias = true;
          pathB = new Path(); }
          void onDraw(Canvas canvas, Size size) async { canvas.saveLayer(Rect.fromLTRB(0, 0, size.width, size.height), bgPaint);
          if (a.x == -1 && a.y == -1) { _drawPathAWithPic(canvas, _getPathDefault()); _drawPathCWithPic(canvas, _getPathDefault(), pathCPaint); _drawPathBWithPic(canvas, _getPathDefault()); } else { if (f.x == viewWidth && f.y == 0) { _drawPathAWithPic(canvas, _getPathAFromTopRight()); _drawPathCWithPic(canvas, _getPathAFromTopRight(), pathCPaint); _drawPathBWithPic(canvas, _getPathAFromTopRight()); } else if (f.x == viewWidth && f.y == viewHeight) { _drawPathAWithPic(canvas, _getPathAFromLowerRight()); _drawPathCWithPic(canvas, _getPathAFromLowerRight(), pathCPaint); _drawPathBWithPic(canvas, _getPathAFromLowerRight()); } }
          canvas.restore(); }
          void _drawPathAWithPic(Canvas canvas, Path pp) { canvas.save(); var pictureRecorder = ui.PictureRecorder(); var canvasBitmap = Canvas(pictureRecorder); var paint = Paint(); paint.isAntiAlias = true; canvasBitmap.drawPath(pp, pathAPaint); _drawText(canvasBitmap, text, Colors.black, viewWidth, Offset.zero); var pic = pictureRecorder.endRecording(); canvas.clipPath(pp); canvas.drawPicture(pic);
          if (style == PositionStyle.STYLE_LEFT || style == PositionStyle.STYLE_RIGHT) { _drawPathAHorizontalShadow(canvas, pathA); } else if (a.x != -1 && a.y != -1) { _drawPathALeftShadow(canvas, pp); _drawPathARightShadow(canvas, pp); }
          canvas.restore(); }
          void _drawPathALeftShadow(Canvas canvas, Path pathA) { canvas.restore(); canvas.save();
          var gradientColors = [Color(0x01333333), Color(0x33333333)];
          double left; double right; double top = e.y; double bottom = (e.y + viewHeight);
          ui.Gradient gradient; if (style == PositionStyle.STYLE_TOP_RIGHT) { left = (e.x - lPathAShadowDis / 2); right = (e.x); gradient = ui.Gradient.linear( Offset(left, top), Offset(right, top), gradientColors); } else { left = (e.x); right = (e.x + lPathAShadowDis / 2);
          gradient = ui.Gradient.linear( Offset(right, top), Offset(left, top), gradientColors); } Paint paint = new Paint()..shader = gradient;
          //裁剪出我們需要的區(qū)域 Path mPath = new Path(); mPath.moveTo(a.x - Math.max(rPathAShadowDis, lPathAShadowDis) / 2, a.y); mPath.lineTo(d.x, d.y); mPath.lineTo(e.x, e.y); mPath.lineTo(a.x, a.y); mPath.close(); //canvas.clipPath(pathA); var pn = Path.combine(PathOperation.intersect, pathA, mPath); canvas.clipPath(pn);
          canvas.translate(e.x, e.y); canvas.rotate(Math.atan2(e.x - a.x, a.y - e.y)); canvas.translate(-e.x, -e.y); var rect = Rect.fromLTRB(left, top, right, bottom); canvas.drawRect(rect, paint); }
          void _drawPathARightShadow(Canvas canvas, Path pathA) { canvas.restore(); canvas.save();
          var gradientColors = [ Color(0x33333333), Color(0x01333333), ];
          double viewDiagonalLength = _hypot(viewWidth, viewHeight); //view對角線長度 double left = h.x; double right = (h.x + viewDiagonalLength * 10); //需要足夠長的長度 double top; double bottom;
          ui.Gradient gradient; if (style == PositionStyle.STYLE_TOP_RIGHT) { top = (h.y - rPathAShadowDis / 2); bottom = h.y; gradient = ui.Gradient.linear( Offset(left, bottom), Offset(left, top), gradientColors); } else { top = h.y; bottom = (h.y + rPathAShadowDis / 2);
          gradient = ui.Gradient.linear( Offset(left, top), Offset(left, bottom), gradientColors); } Paint paint = new Paint()..shader = gradient;
          Path mPath = new Path(); mPath.moveTo(a.x - Math.max(rPathAShadowDis, lPathAShadowDis) / 2, a.y);// mPath.lineTo(i.x,i.y); mPath.lineTo(h.x, h.y); mPath.lineTo(a.x, a.y); mPath.close(); var pn = Path.combine(PathOperation.intersect, pathA, mPath); canvas.clipPath(pn);
          canvas.translate(h.x, h.y); canvas.rotate(Math.atan2(a.y - h.y, a.x - h.x)); canvas.translate(-h.x, -h.y); var rect = Rect.fromLTRB(left, top, right, bottom); canvas.drawRect(rect, paint); }
          void _drawPathAHorizontalShadow(Canvas canvas, Path pathA) { canvas.restore(); canvas.save();
          var radientColors = [Color(0x01333333), Color(0x44333333)]; //漸變顏色數(shù)組
          double maxShadowWidth = 30; //陰影矩形最大的寬度 double left = (a.x - Math.min(maxShadowWidth, (rPathAShadowDis / 2))); double right = (a.x); double top = 0; double bottom = viewHeight;
          ui.Gradient gradient = ui.Gradient.linear( Offset(left, top), Offset(right, top), radientColors); Paint paint = new Paint()..shader = gradient;
          canvas.clipPath(pathA);
          canvas.translate(a.x, a.y); canvas.rotate(Math.atan2(f.x - a.x, f.y - h.y)); canvas.translate(-a.x, -a.y); var rect = Rect.fromLTRB(left, top, right, bottom); canvas.drawRect(rect, paint); }
          void _drawPathBWithPic(Canvas canvas, Path pa) { canvas.save(); var pictureRecorder = ui.PictureRecorder(); var canvasBitmap = Canvas(pictureRecorder); var paint = Paint(); paint.isAntiAlias = true; canvasBitmap.drawPath(_getPathB(), pathBPaint); _drawText(canvasBitmap, text2, Colors.black, viewWidth, Offset.zero);
          var pic = pictureRecorder.endRecording(); var pn = Path.combine(PathOperation.reverseDifference, pa, _getPathB()); pn = Path.combine(PathOperation.reverseDifference, _getPathC(), pn); canvas.clipPath(pn); canvas.drawPicture(pic); _drawPathBShadow(canvas); //調(diào)用陰影繪制方法 canvas.restore(); }
          void _drawPathBShadow(Canvas canvas) { var gradientColors = [Color(0xf0111111), Color(0x00000000)]; //漸變顏色數(shù)組 int elevation = 6; int deepOffset = 0; //深色端的偏移值 int lightOffset = 0; //淺色端的偏移值 double aTof = _hypot((a.x - f.x), (a.y - f.y)); //a到f的距離 double viewDiagonalLength = _hypot(viewWidth, viewHeight); //對角線長度
          double left; double right; double top = c.y; double bottom = (viewDiagonalLength + c.y); ui.Gradient gradient; if (style == PositionStyle.STYLE_TOP_RIGHT) { //f點(diǎn)在右上角 //從左向右線性漸變 left = (c.x - deepOffset); //c點(diǎn)位于左上角 right = (c.x + aTof / elevation + lightOffset);
          gradient = ui.Gradient.linear( Offset(left, top), Offset(right, top), gradientColors); } else { left = (c.x - aTof / elevation - lightOffset); //c點(diǎn)位于左下角 right = (c.x + deepOffset); gradient = ui.Gradient.linear( Offset(right, top), Offset(left, top), gradientColors); }
          Paint paint = new Paint() //..color = Colors.black.withAlpha(80); //..blendMode = BlendMode.srcOver ..shader = gradient;
          canvas.translate(c.x, c.y); canvas.rotate(Math.atan2(e.x - f.x, h.y - f.y)); canvas.translate(-c.x, -c.y); var rect = Rect.fromLTRB(left, top, right, bottom); canvas.drawRect(rect, paint); }
          void _drawPathCWithPic(Canvas canvas, Path pathA, Paint pathPaint) { canvas.drawPath(_getPathC(), pathPaint);
          canvas.save(); var pictureRecorder = ui.PictureRecorder(); var canvasBitmap = Canvas(pictureRecorder); canvasBitmap.drawPath(_getPathB(), pathPaint); var pic = pictureRecorder.endRecording();
          var pn = Path.combine(PathOperation.reverseDifference, pathA, _getPathC()); canvas.clipPath(pn);
          double eh = _hypot(f.x - e.x, h.y - f.y); double sin0 = (f.x - e.x) / eh; double cos0 = (h.y - f.y) / eh; //設(shè)置翻轉(zhuǎn)和旋轉(zhuǎn)矩陣 var mMatrixArray = [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.1, 0.0, 0.0, 0.0, 0.0, 0.1 ]; mMatrixArray[0] = -(1 - 2 * sin0 * sin0); mMatrixArray[1] = 2 * sin0 * cos0; mMatrixArray[4] = 2 * sin0 * cos0; mMatrixArray[5] = 1 - 2 * sin0 * sin0;
          Matrix4 mMatrix = Matrix4.fromList(mMatrixArray);
          mMatrix.leftTranslate(e.x, e.y); mMatrix.translate(-e.x, -e.y); canvas.transform(mMatrix.storage); canvas.drawPicture(pic); _drawPathCShadow(canvas); //調(diào)用陰影繪制方法 canvas.restore(); }
          void _drawPathCShadow(Canvas canvas) { var gradientColors = [Color(0x00333333), Color(0xff111111)]; //漸變顏色數(shù)組
          int deepOffset = 1; //深色端的偏移值 int lightOffset = -30; //淺色端的偏移值 var viewDiagonalLength = _hypot(viewWidth, viewHeight); //view對角線長度 double midpointCe = (c.x + e.x) / 2; //ce中點(diǎn) double midpointJh = (j.y + h.y) / 2; //jh中點(diǎn) double minDisToControlPoint = Math.min( (midpointCe - e.x).abs(), (midpointJh - h.y).abs()); //中點(diǎn)到控制點(diǎn)的最小值
          double left; double right; double top = c.y; double bottom = (viewDiagonalLength + c.y); ui.Gradient gradient; if (style == PositionStyle.STYLE_TOP_RIGHT) { left = (c.x - lightOffset); right = (c.x + minDisToControlPoint + deepOffset);
          gradient = ui.Gradient.linear( Offset(left, top), Offset(right, top), gradientColors); } else { left = (c.x - minDisToControlPoint - deepOffset); right = (c.x + lightOffset); gradient = ui.Gradient.linear( Offset(right, top), Offset(left, top), gradientColors); } Paint paint = new Paint()..shader = gradient;
          canvas.translate(c.x, c.y); canvas.rotate(Math.atan2(e.x - f.x, h.y - f.y)); canvas.translate(-c.x, -c.y); var rect = Rect.fromLTRB(left, top, right, bottom); canvas.drawRect(rect, paint); }
          /// 計算各點(diǎn)坐標(biāo) void _calcPointsXY(CalPoint a, CalPoint 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 = _getInterPoint(a, e, c, j); k = _getInterPoint(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;
          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) / (_hypot(lA, lB)).abs());
          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) / _hypot(rA, rB)).abs(); }
          /// 計算兩線段相交點(diǎn)坐標(biāo) CalPoint _getInterPoint( CalPoint lineOneToPointOne, CalPoint lineOneToPointTwo, CalPoint lineTwoToPointOne, CalPoint lineTwoToPointTwo) { double x1, y1, x2, y2, x3, y3, x4, y4; x1 = lineOneToPointOne.x; y1 = lineOneToPointOne.y; x2 = lineOneToPointTwo.x; y2 = lineOneToPointTwo.y; x3 = lineTwoToPointOne.x; y3 = lineTwoToPointOne.y; x4 = lineTwoToPointTwo.x; y4 = lineTwoToPointTwo.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 CalPoint.data(pointX, pointY); }
          ///獲取f點(diǎn)在右下角的pathA Path _getPathAFromLowerRight() { pathA.reset(); pathA.lineTo(0, viewHeight); //移動到左下角 pathA.lineTo(c.x, c.y); //移動到c點(diǎn) pathA.quadraticBezierTo(e.x, e.y, b.x, b.y); //從c到b畫貝塞爾曲線,控制點(diǎn)為e pathA.lineTo(a.x, a.y); //移動到a點(diǎn) pathA.lineTo(k.x, k.y); //移動到k點(diǎn) pathA.quadraticBezierTo(h.x, h.y, j.x, j.y); //從k到j(luò)畫貝塞爾曲線,控制點(diǎn)為h pathA.lineTo(viewWidth, 0); //移動到右上角 pathA.close(); //閉合區(qū)域 return pathA; }
          ///獲取f點(diǎn)在右上角的pathA Path _getPathAFromTopRight() { pathA.reset(); pathA.lineTo(c.x, c.y); //移動到c點(diǎn) pathA.quadraticBezierTo(e.x, e.y, b.x, b.y); //從c到b畫貝塞爾曲線,控制點(diǎn)為e pathA.lineTo(a.x, a.y); //移動到a點(diǎn) pathA.lineTo(k.x, k.y); //移動到k點(diǎn) pathA.quadraticBezierTo(h.x, h.y, j.x, j.y); //從k到j(luò)畫貝塞爾曲線,控制點(diǎn)為h pathA.lineTo(viewWidth, viewHeight); //移動到右下角 pathA.lineTo(0, viewHeight); //移動到左下角 pathA.close(); return pathA; }
          ///翻頁折角區(qū)域 Path _getPathC() { pathC.reset(); pathC.moveTo(i.x, i.y); //移動到i點(diǎn) pathC.lineTo(d.x, d.y); //移動到d點(diǎn) pathC.lineTo(b.x, b.y); //移動到b點(diǎn) pathC.lineTo(a.x, a.y); //移動到a點(diǎn) pathC.lineTo(k.x, k.y); //移動到k點(diǎn) pathC.close(); //閉合區(qū)域 return pathC; }
          ///翻頁后剩余區(qū)域 Path _getPathB() { pathB.reset(); pathB.lineTo(0, viewHeight); //移動到左下角 pathB.lineTo(viewWidth, viewHeight); //移動到右下角 pathB.lineTo(viewWidth, 0); //移動到右上角 pathB.close(); //閉合區(qū)域 return pathB; }
          ///繪制默認(rèn)的界面 Path _getPathDefault() { pathA.reset(); pathA.lineTo(0, viewHeight); pathA.lineTo(viewWidth, viewHeight); pathA.lineTo(viewWidth, 0); pathA.close(); return pathA; }
          ///計算C點(diǎn)的X值 _calcPointCX(CalPoint a, CalPoint f) { CalPoint g, e; g = new CalPoint(); e = new CalPoint(); 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; }
          ///如果c點(diǎn)x坐標(biāo)小于0,根據(jù)觸摸點(diǎn)重新測量a點(diǎn)坐標(biāo) _calcPointAByTouchPoint() { double w0 = viewWidth - c.x;
          double w1 = (f.x - a.x).abs(); double w2 = viewWidth * 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(); }
          ///利用 Paragraph 實現(xiàn) _drawText _drawText( Canvas canvas, String text, Color color, double width, Offset offset, {TextAlign textAlign = TextAlign.start, double fontSize}) { ui.ParagraphBuilder pb = ui.ParagraphBuilder(ui.ParagraphStyle( textAlign: textAlign, fontSize: fontSize, )); pb.pushStyle(ui.TextStyle(color: color)); pb.addText(text); ui.ParagraphConstraints pc = ui.ParagraphConstraints(width: width);
          ///這里需要先layout, 后面才能獲取到文字高度 ui.Paragraph paragraph = pb.build()..layout(pc); canvas.drawParagraph(paragraph, offset); }
          //_drawTestPoint() {// _drawText(canvas, "a", Colors.red, size.width, Offset(a.x, a.y),// textAlign: TextAlign.left, fontSize: 25);// _drawText(canvas, "f", Colors.red, size.width, Offset(f.x, f.y),// textAlign: TextAlign.left, fontSize: 25);// _drawText(canvas, "g", Colors.red, size.width, Offset(g.x, g.y),// textAlign: TextAlign.left, fontSize: 25);//// _drawText(canvas, "e", Colors.red, size.width, Offset(e.x, e.y),// textAlign: TextAlign.left, fontSize: 25);// _drawText(canvas, "h", Colors.red, size.width, Offset(h.x, h.y),// textAlign: TextAlign.left, fontSize: 25);//// _drawText(canvas, "c", Colors.red, size.width, Offset(c.x, c.y),// textAlign: TextAlign.left, fontSize: 25);// _drawText(canvas, "j", Colors.red, size.width, Offset(j.x, j.y),// textAlign: TextAlign.left, fontSize: 25);//// _drawText(canvas, "b", Colors.red, size.width, Offset(b.x, b.y),// textAlign: TextAlign.left, fontSize: 25);// _drawText(canvas, "k", Colors.red, size.width, Offset(k.x, k.y),// textAlign: TextAlign.left, fontSize: 25);//// _drawText(canvas, "d", Colors.red, size.width, Offset(d.x, d.y),// textAlign: TextAlign.left, fontSize: 25);// _drawText(canvas, "i", Colors.red, size.width, Offset(i.x, i.y),// textAlign: TextAlign.left, fontSize: 25); // }
          num _hypot(num x, num y) { var first = x.abs(); var second = y.abs();
          if (y > x) { first = y.abs(); second = x.abs(); }
          if (first == 0.0) { return second; }
          final t = second / first; return first * Math.sqrt(1 + t * t); }}

          BookTextClip

          import 'package:flutter/material.dart';
          class BookTextClip extends CustomClipper<Path> { final Path path;
          BookTextClip(this.path);
          @override Path getClip(Size size) { return path; }
          @override bool shouldReclip(CustomClipper<Path> oldClipper) { return true; }}

          CalPoint

          class CalPoint {  CalPoint();
          CalPoint.data(this.x, this.y);
          double x = -1; double y = -1;}


          瀏覽 218
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天av无码天天爽AV | 日本综合在线观看 | 亚洲最大在线 | 看国产片日逼的 | 国产成人三级在线 |