5)Learning diary for flutter
作者:互联网
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