look at the aige.introduction of the Principle of Android page Flip effect introduced into the polylineThere are some computational principles here to leave a note .
x, y are the short and long edges of the folded triangle; O (A, B) point is the touch pointSet k = w-a, L = H-b
? OMA, drawn by the Pythagorean theorem,
? OMA and? Aob? The area of the APB and the area equal to the trapezoidal MOBP
substituting X, Solution
substituting the touch point (A, B) to find the current corresponding x, y
with X, Y can now find the coordinates of point A and point B .Point A (W-x, h)b Point (W, h-y)The triangle of the polyline is the moveto of path to touch point, and then LineTo to a, b two, close closed triangle
AB for the fold line, p Point in the fold formed O point should be at (0,H) as the center of the Circle, W radiusThe range of this circle is calculated by path and region: Mregionshortsizeif it's not in range, it's definitely the problem with the ordinate of the touch:
if (!mregionshortsize.contains (int) mtouchx, (int) mtouchy)) {/ * if not, the standard equation of the y-coordinate through the circle is forcibly calculated by x-coordinate : (x-a) ^2+ ( Y-b) ^2=r^2 (A, A, a, b) for the center of R is the radius x, Y is a point on the arc y-b = math.sqrt (R^2-(x-a) ^2) = y = math.sqrt (r^2-(x-a) ^2) + B
or -(y-b) = Math.sqrt (R^2-(x-a) ^2) + y =-1 * MATH.SQRT (r^2-(x-a) ^2) + b */// mtouchy = (float) ( Math.sqrt ((Math.pow (MW, 2)-Math.pow (Mtouchx, 2)) + MH); The apparent value is greater than MH, not mtouchy = (float) ( -1 * MATH.SQRT ((Math.pow (MW, 2)-Math.pow (Mtouchx, 2)) + MH);}
The calculated Mtouchy is the ordinate value of the corresponding horizontal axis on the circular trajectory .(Note: An expression in the originalMpointy = (float) (Math.sqrt ((Math.pow (Mviewwidth, 2)-Math.pow (Mpointx, 2))-mviewheight);
Mpointy = Math.Abs (mpointy) + mvalueadded; )
to the current code:
Package Com.stone.turnpage.view;import Android.content.context;import Android.graphics.canvas;import Android.graphics.color;import Android.graphics.paint;import Android.graphics.path;import Android.graphics.RectF; Import Android.graphics.region;import Android.os.build;import Android.support.annotation.requiresapi;import Android.util.attributeset;import android.view.motionevent;import android.view.view;/** * author:stone * Email: [Email protected] * TIME:16/9/20 11 18 * * Polyline page */public class Foldturnpageview extends View {private float MTOUCHX , Mtouchy; Private Path MPath; Private Paint Mpaint; private int MW, MH; Private region mregionshortsize; Public Foldturnpageview (Context context) {This (context, NULL); } public Foldturnpageview (context context, AttributeSet Attrs) {This (context, attrs, 0); } public Foldturnpageview (context context, AttributeSet attrs, int defstyleattr) {Super (context, Attrs, defstyl EATTR); MPath = new Path (); Mpaint = new Paint (); Mpaint.setcolor (color.red); Mpaint.setstyle (Paint.Style.STROKE); Mpaint.setstrokewidth (10); Mregionshortsize = new region (); } @RequiresApi (API = Build.version_codes. LOLLIPOP) Public Foldturnpageview (context context, AttributeSet attrs, int defstyleattr, int defstyleres) {Supe R (Context, Attrs, defstyleattr, defstyleres); } @Override public boolean ontouchevent (Motionevent event) {Mtouchx = Event.getx (); Mtouchy = Event.gety (); System.out.println (Mtouchy); if (!mregionshortsize.contains (int) mtouchx, (int) mtouchy)) {/* If not, forcibly re-calculates the y-coordinate by x-coordinate through the circle The standard equation: (x-a) ^2+ (b) ^2=r^2 (A, a, a, a, a) is the radius x, y for the center of the arc, and the point y-b = Math.sqrt (R^2-(x-a) ^2) = y = Math.sqrt (r^2 -(X-A) ^2) + B or-(y-b) = Math.sqrt (R^2-(x-a) ^2) + y =-1 * MATH.SQRT (r^2-(x-a) ^2) + b *///Mtouchy = (FloaT) (Math.sqrt ((Math.pow (MW, 2)-Math.pow (Mtouchx, 2)) + MH); Mtouchy = (float) ( -1 * MATH.SQRT ((Math.pow (MW, 2)-Math.pow (Mtouchx, 2)) + MH); } invalidate (); Switch (event.getaction ()) {case MotionEvent.ACTION_DOWN:break; Case MotionEvent.ACTION_MOVE:break; Case MotionEvent.ACTION_UP:break; } return true; } @Override protected void onsizechanged (int w, int h, int oldw, int oldh) {super.onsizechanged (W, H, OLDW, OLDH); MW = Getmeasuredwidth (); MH = Getmeasuredheight (); Computeshortsizeregion (); } @Override protected void OnDraw (canvas canvas) {super.ondraw (canvas); Mpath.reset (); float k = Mw-mtouchx; float L = mh-mtouchy; float C = (float) (Math.pow (k, 2) + Math.pow (L, 2)); float x = c/(2 * k); Float y = c/(2 * l); Mpath.moveto (Mtouchx, mtouchy); O-point Mpath.lineto (Mw-x, MH); A point Mpath.lineto (MW, mh-y); B point Mpath.close (); Mpaint.setcolor (color.red); Canvas.drawpath (MPath, mpaint); Mpaint.setcolor (Color.green); Mpath.reset (); Mpath.addcircle (0, MH, MW, Path.Direction.CCW); Canvas.drawpath (MPath, mpaint); /** * Calculates the effective area of the short edge */private void computeshortsizeregion () {//Short edge Round Path object Path pathshortsize = New Path (); Add Circle to Path pathshortsize.addcircle (0, MH, MW, Path.Direction.CCW); RECTF bounds = new RECTF (); Pathshortsize.computebounds (bounds, true); Region.setpath parameter region clip, used to crop Mregionshortsize.setpath (Pathshortsize, New region ((int) bounds.left, (int) Bounds.top, (int) bounds.right, (int) bounds.bottom)); }}
Auto Slidewhen the right bottom of the view is One-fourth high, slide to the right and the left one-eighth to the leftSlide Right:Right Area RA = W/4 * 3; Bottom zone ba = H/4 * 3;when touch-up, Touch-x>ra && touch-y>ba instructions in the right sliding areaa straight line equation is obtained from the touch point (x, y) to the lower right (w,h), and then when X is increased and the Y value is calculatedsolution of Y-value according to linear equation formula
Slide Left:left part of LA=W/4; Connect to (-w,h) point from Touch Point (x, Y), and also according to linear equation ...
for the excess portion of the upper end, no drawing is required:(changed here: aige it diagram, unlike the first figure: AB Point opposite)
that is ? Amn no need to draw od perpendicular to PA,? BMN and ? BOD is a similar triangle bn/mn=bd/od, so Mn=bn/bd*od? BQN and ? BAP is a similar triangle
Bn/qn=bp/ap, so Qn=bn/bp*ap
the code at this point:
Package Com.stone.turnpage.view;import Android.content.context;import Android.graphics.canvas;import Android.graphics.color;import Android.graphics.paint;import Android.graphics.path;import Android.graphics.RectF; Import Android.graphics.region;import android.os.build;import Android.os.handler;import Android.os.Message;import Android.support.annotation.intdef;import Android.support.annotation.requiresapi;import Android.util.AttributeSet ; Import Android.view.motionevent;import Android.view.view;import Java.lang.annotation.retention;import java.lang.annotation.retentionpolicy;/** * author:stone * Email: [email protected] * TIME:16/9/20 * < ;p > * Line page */public class Foldturnpageview extends View {private float mtouchx, mtouchy; Private float MTOUCHUPX, mtouchupy;//touch-up time coordinates private Path mPath; Private Paint Mpaint; private int MW, MH; Private region mregionshortsize; private int mbuffarea = 20; Bottom buffer private float mautoarearight, MautoaReabottom, Mautoarealeft; Private Boolean misslide; Whether to automatically slide private static final int left_bottom = 1; Lower left private static final int right_bottom = 2; Lower right @IntDef ({left_bottom, right_bottom}) @Retention (retentionpolicy.source) Private @interface slidedirection {} @SlideDirection private int mslide; Private Handler Mhandler = new Handler () {@Override public void Handlemessage (Message msg) {sup Er.handlemessage (msg); if (!misslide) {return; } if (mslide = = Right_bottom && Mtouchx < MW) {//swipe down MTOUCHX + = 10; /* Based on linear equation formula: (y-y1)/(Y2-y1) = (x-x1)/(X2-X1) y=y1+ (x-x1) * (y2-y1)/(x2-x1) mtouchupx <==> ; X1 mtouchupy <==> y1 mW <==> x2 mH <==> y2 changing point mtouchx <==> x mTo Uchy <==> y */mtouchy = mtouchupy + (MTOUCHX-MTOUCHUPX) * (MH -Mtouchupy)/(MW-MTOUCHUPX); Invalidate (); Sendmessagedelayed (obtainmessage (0), 25); } else if (mslide = = Left_bottom && mtouchx >-MW) {//swipe left mtouchx-= 40; Mtouchy = Mtouchupy + (MTOUCHX-MTOUCHUPX) * (mh-mtouchupy)/(-MW-MTOUCHUPX); Invalidate (); Sendmessagedelayed (obtainmessage (0), 25); } else {slidestop (); } } }; Public Foldturnpageview (Context context) {This (context, NULL); } public Foldturnpageview (context context, AttributeSet Attrs) {This (context, attrs, 0); } public Foldturnpageview (context context, AttributeSet attrs, int defstyleattr) {Super (context, Attrs, defstyl EATTR); MPath = new Path (); Mpaint = new Paint (); Mpaint.setcolor (color.red); Mpaint.setstyle (Paint.Style.STROKE); Mpaint.setstrokewidth (10); Mregionshortsize = new Region ();//Setlayertype (layer_type_software, NULL); Turn off hardware acceleration api11 above in manifest close} @RequiresApi (API = Build.version_codes. LOLLIPOP) Public Foldturnpageview (context context, AttributeSet attrs, int defstyleattr, int defstyleres) {Supe R (Context, Attrs, defstyleattr, defstyleres); } @Override public boolean ontouchevent (Motionevent event) {float x = Event.getx (); Float y = event.gety (); Mtouchx = x; Mtouchy = y; Switch (event.getaction ()) {case MotionEvent.ACTION_DOWN:mHandler.removeMessages (0); Invalidate (); Break Case MotionEvent.ACTION_MOVE:invalidate (); Break Case MotionEvent.ACTION_UP:if (x > Mautoarearight && y > Mautoareabottom) { Mslide = Right_bottom; Startslide (x, y); } else if (x < Mautoarealeft) { Mslide = Left_bottom; Startslide (x, y); } break; } return true; } private void Startslide (float x, float y) {misslide = true; MTOUCHUPX = x; Mtouchupy = y; Mhandler.sendemptymessage (0); } @Override protected void onsizechanged (int w, int h, int oldw, int oldh) {super.onsizechanged (W, H, OLDW, OLDH); MW = Getmeasuredwidth (); MH = Getmeasuredheight (); Computeshortsizeregion (); Mautoarearight = MW/4 * 3; Mautoareabottom = MH/4 * 3; Mautoarealeft = MW/8; } @Override protected void OnDraw (canvas canvas) {super.ondraw (canvas);//Canvas.clipregion (Mregionsh Ortsize); Canvas.drawcolor (Color.parsecolor ("#d8ccaa00")); if (!mregionshortsize.contains (int) mtouchx, (int) mtouchy)) {/* If not, force the Y coordinate by x coordinate through The standard equation of the circle: (x-a) ^2+ (y-b) ^2=r^2 (A, B) is the radius of the center R, X, Y, and a point on the arc Y-b = Math.sqrt (R^2-(x-a) ^2) = y = Math.sqrt (r^2-(x-a) ^2) + B or-(y-b) = Math.sqrt (R^2-(x-a) ^2) = y =-1 * MATH.SQRT (r^2-(x-a) ^2) + b *///mtouchy = (float) (Math. sqrt ((Math.pow (MW, 2)-Math.pow (Mtouchx, 2)) + MH); Using this apparent value is larger than MH large mtouchy = (float) ( -1 * MATH.SQRT ((Math.pow (MW, 2)-Math.pow (Mtouchx, 2)) + MH); }/* buffer area to determine when the B point is not on the PB line, and above the screen, then Mtouchx, left at this time Mtouchy closer to MH, the line can not form? AOB but a rectangle */float area = Mh-mbuffarea; if (mtouchy >= area &&!misslide) {mtouchy = area; } float k = Mw-mtouchx; float L = mh-mtouchy; float C = (float) (Math.pow (k, 2) + Math.pow (L, 2)); float x = c/(2 * k); Float y = c/(2 * l); Mpath.reset (); Mpath.moveto (Mtouchx, mtouchy); o point if (y > MH) {//b dot exceeds upper screen//calculation, bn edge float bn = y- MH; Mn=bn/bd*od float MN = BN/(Y-(Mh-mtouchy)) * (MW-MTOUCHX); Qn=bn/bp*ap float QN = bn/y * x; Mpath.lineto (mw-mn, 0); M-Point Mpath.lineto (mw-qn, 0); Q-Point Mpath.lineto (Mw-x, MH); A point at the bottom} else {Mpath.lineto (MW, mh-y); Point B on the right side of the Mpath.lineto (Mw-x, MH); Point A at bottom} mpath.close (); Mpaint.setcolor (color.red); Canvas.drawpath (MPath, mpaint); Mpaint.setcolor (Color.green); Mpath.reset (); Mpath.addcircle (0, MH, MW, Path.Direction.CCW); Canvas.drawpath (MPath, mpaint); /** * Calculates the effective area of the short edge */private void computeshortsizeregion () {//Short edge Round Path object Path pathshortsize = New Path (); Add Circle to Path pathshortsize.addcircle (0, MH, MW, Path.Direction.CCW); RECTF bounds = new RECTF (); Pathshortsize.computebounds (bounds, true); Region.setpath parameter Region clip, Used to crop a Boolean flag = Mregionshortsize.setpath (Pathshortsize, New region ((int) bounds.left, (int) bounds.top, (int) bounds.right, (int) bounds.bottom));//Boolean flag = Mregionshortsize.setpath (pathshortsize, new Region (0, 1920-1080, +));//System.out.println (Bounds + ",," + flag);//System.out.println (Mregionsh Ortsize); }/** * Provides an external stop method for isslide easy to release sliding animation when necessary */public void Slidestop () {misslide = false; }}
:
Final Drawing of the film: The current page picture, the picture of the collapsed area, the next picture that folds out> About the calculation of the area:
if (Y > MH) {//b dot exceeds upper screen//calculation, bn edge float bn = Y-MH; Mn=bn/bd*od float MN = BN/(Y-(Mh-mtouchy)) * (MW-MTOUCHX); Qn=bn/bp*ap float QN = bn/y * x; Mpath.lineto (mw-mn, 0); M-Point Mpath.lineto (mw-qn, 0); Q-Point Mpath.lineto (Mw-x, MH); A point at the bottom/* generates a path with collapsed and next page Omnpa Five Points */Mpathfoldandnext.lineto (MW- MN, 0); M Mpathfoldandnext.lineto (MW, 0); N Mpathfoldandnext.lineto (MW, MH); P Mpathfoldandnext.lineto (Mw-x, MH); A} else {Mpath.lineto (MW, mh-y);//b Point at right Mpath.lineto (mw-x, MH);//a Point at bottom /* Generate a path containing the collapsed and next page OBPA four points */Mpathfoldandnext.lineto (MW, mh-y); Point B at right Mpathfoldandnext.lineto (MW, MH); P-Point Mpathfoldandnext.lineto (Mw-x, MH); Point A at the bottom }
Use Mpathfoldandnext to record the collapsed area and its equal next page (right) area
the picture of the folding area drawing, more difficult to understand (aige in the last draw a picture, see not very clear, tangled for a few days)
this sketch, which indicates that the short edge is X, calculates the angle d of the x and Y axes by the inverse string function .when you pan to touch point and then rotate (90-d), the Green Line part is coincident with the X-ray on the top ,then through some canvas operation, finally can realize the folding area to draw the corresponding part of the horizontal mirror effectanother case where x is a long edge is similar in principle, and the sketch is as follows
Click the full source transfer
Android Custom View polyline page