Flutter仿真翻頁效果
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;{if (needCancelAnim) {startCancelAnim();else {{style = PositionStyle.STYLE_LOWER_RIGHT;prePoint = CalPoint.data(-1, -1);curPoint = CalPoint.data(-1, -1);});}}{var x = d.localPosition.dx;var y = d.localPosition.dy;{curPoint = CalPoint.data(x, y);});}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;{curPoint = CalPoint.data(x, y);});}{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 =: Offset(prePoint.x, prePoint.y), end: Offset(dx, dy));animationController.forward();}{animationController = new AnimationController(vsync: this, duration: Duration(milliseconds: 300));cancelAnim = animationController.drive(CurveTween(curve: Curves.linear));cancelAnim{if (animationController.isAnimating) {{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);});}}){if (status == AnimationStatus.completed) {print("object");{style = PositionStyle.STYLE_LOWER_RIGHT;prePoint = CalPoint.data(-1, -1);curPoint = CalPoint.data(-1, -1);animationController.reset();});}});}@overridevoid initState() {super.initState();_initCancelAnim();}@overrideWidget 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({this.text,this.text2,this.viewWidth,this.viewHeight,this.frontColor,this.bgColor,CalPoint cur,CalPoint pre,this.changedPoint,this.style,bool limitAngle,}) {init(cur, pre, limitAngle);}bool shouldRepaint(CustomPainter oldDelegate) => true;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)在右下角的pathAPath _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)為epathA.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)為hpathA.lineTo(viewWidth, 0); //移動到右上角pathA.close(); //閉合區(qū)域return pathA;}///獲取f點(diǎn)在右上角的pathAPath _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)為epathA.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)為hpathA.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);Path getClip(Size size) {return path;}bool shouldReclip(CustomClipper<Path> oldClipper) {return true;}}
CalPoint
class CalPoint {CalPoint();CalPoint.data(this.x, this.y);double x = -1;double y = -1;}
評論
圖片
表情
