Back in a long long time ago, QQ realized the "one button off" function. What is "one button off"? When you have information QQ, the lower part of the number of information hint Red point, click Drag, you will see the "one button off" effect. This article combines a simple implementation of this feature on GitHub to introduce the basic implementation of this feature.
Project Address
Https://github.com/chenupt/BezierDemo
Final implementation effect
Realization Principle Analysis
I personally feel that the effect of the implementation of a very beautiful ah! So let's see what the implementation principle is.
Note: Please refer to the project source to see the following content.
In fact, from the code point of view, the implementation of the process is not complicated, the focus needs to grasp is
- Use of Path
- The use of Bezier curves.
The core of the project is Bezierview, inherited from the framelayout, when dragged, equivalent to overlay on the screen. The following operations are primarily performed in the Init () method
private void init () {path = new path ();Paint = new Paint ();Paint. Setantialias(true);Paint. SetStyle(Paint. Style. FILL_and_stroke);Paint. Setstrokewidth(2);Paint. SetColor(Color. RED);Layoutparams params = new Layoutparams (viewgroup. Layoutparams. WRAP_content, ViewGroup. Layoutparams. WRAP_content);Exploredimageview = new ImageView (GetContext ());Exploredimageview. Setlayoutparams(params);Exploredimageview. Setimageresource(R. drawable. Tip_anim);Exploredimageview. Setvisibility(View. INVISIBLE);Tipimageview = new ImageView (GetContext ());Tipimageview. Setlayoutparams(params);Tipimageview. Setimageresource(R. drawable. Skin_tips_newmessage_ninetynine);AddView (Tipimageview);AddView (Exploredimageview);}
The path and paint objects are initialized, and two ImageView are generated dynamically
- Exploredimageview is primarily used to achieve explosion effects and is not visible by default
- Tipimageview the red icon when the finger is dragged
The picture resource set by Exploredimageview is a animationdrawable, the following is the declaration in RES, which controls the order and duration of each picture, which is well understood
<?xml version= "1.0" encoding= "Utf-8"?><animation-listxmlns:android="Http://schemas.android.com/apk/res/android" android:oneshot="true"> <item android:drawable="@drawable/idp" android:duration="300" /> <item android:drawable="@drawable/idq" android:duration="300" /> <item android:drawable="@drawable/idr" android:duration= "/>" <item android:drawable="@drawable/ids" android:duration="300" /> <item android:drawable="@drawable/idt" android:duration="300" /> <item android:drawable="@android: Color/transparent" android: Duration="/> "</animation-list>
When we are learning this custom control, we can focus on the code according to the view drawing process, for example, we can
This is the order in which you will learn about this project.
- Onmeasure ()
- OnLayout ()
- OnDraw ()
- Ontouchevent ()
Because this project did not rewrite Onmeasure (), so we went straight from OnLayout to see what was done
@Override protected void onlayout ( Span class= "Hljs-keyword" >boolean changed, int left, int top, int right, int bottom) {exploredimageview.setx (Startx-exploredimageview.getwidth ()/2 ); Exploredimageview.sety (Starty-exploredimageview.getheight ()/2 ); Tipimageview.setx (Startx-tipimageview.getwidth ()/2 ); Tipimageview.sety (Starty-tipimageview.getheight ()/2 ); super . OnLayout (changed, left, top, right, bottom); }
The code is also very understanding, nothing more than initializing the location of the ImageView, where there are two variables, startx and Starty, the two variables control the initial coordinates of the red dot, the entire process will not change.
So what about OnDraw ()?
@Override protected void OnDraw (canvas canvas) {if (Isanimstart | |!istouch) {Canvas. Drawcolor(Color. TRANSPARENT, Porterduff. Mode. OVERLAY);}else{Calculate ();Canvas. Drawcolor(Color. TRANSPARENT, Porterduff. Mode. OVERLAY);Canvas. DrawPath(Path, paint);Canvas. Drawcircle(StartX, Starty, radius, paint);Canvas. Drawcircle(x,y, RADIUS, paint);} Super. OnDraw(canvas);}
The operation in OnDraw () is also not complex, if you are performing an animation or are not in touch mode, draw a transparent color, otherwise, start to draw the real interface. Calculate () This method is a focus, from the naming should be calculated some coordinate values, and then began to draw two circles, the coordinates of the two circles, one is (Startx,starty), the other is (x, y), the color and radius are the same, this is to simplify the calculation, So set the radius of the two circles to the same one.
Let's go ahead and look at what's going on in Ontouchevent ().
@Override PublicBooleanontouchevent(motioneventEvent) {if(Event. getaction () = = Motionevent.action_down) {//Determine if the touch point is in TipimageviewRect rect =NewRect ();int[] location =New int[2]; Tipimageview.getdrawingrect (rect); Tipimageview.getlocationonscreen (location); Rect.left = location[0]; Rect.top = location[1]; Rect.right = Rect.right + location[0]; Rect.bottom = Rect.bottom + location[1];if(Rect.contains (int)Event. GETRAWX (), (int)Event. Getrawy ())) {Istouch =true; } }Else if(Event. getaction () = = Motionevent.action_up | |Event. getaction () = = Motionevent.action_cancel) {Istouch =false; Tipimageview.setx (Startx-tipimageview.getwidth ()/2); Tipimageview.sety (Starty-tipimageview.getheight ()/2); } invalidate ();if(Isanimstart) {returnSuper.ontouchevent (Event); } Anchorx = (Event. GetX () + StartX)/2; Anchory = (Event. GetY () + starty)/2; x =Event. GetX (); y =Event. GetY ();return true; }
First, at the time of the press, obtained the tipimageview screen coordinate position, and then according to the location of the touch point, to determine whether the touch state, thereby changing the value of Istouch, and if not pressed time, the introduction of change Istouch, thereby touching the State, Restores the location of the Tipimageview. However, invalidate () is executed to invoke OnDraw (), where the actual circle is executed, which we will look at. Further down, you update the x, y coordinates, and the values of Anchorx and anchory, depending on whether the animation state is playing.
The value of x and Y is actually the position of the touch point, mainly used to control the position of the circle where the finger is pressed, then Anchorx and anchory? These two values are actually the coordinates of the control anchor point, used for the drawing of the Bezier curve.
Speaking of here, I believe you should understand the basic idea of implementation, but the most important thing is the pull effect, in the end how to achieve it? So let's take a look at what the most important calculate () is doing!
Before looking at this code, let's take a quick look at the Bezier curve and how to draw it.
The Bezier curve was used in 1962 by the French mathematician Pierre Bézier for the first time and gave a detailed calculation formula, so the curve is also named after its name.
The Quadto method given in path belongs to the Higes-Bessaire curve.
Take a look at HD uncensored gif, steal from Brother Love, don't tell him ^_^
From the above diagram, we can find that the quadratic Bezier curve, we only need to determine three points, we can draw a smooth curve, P0 and P2 is the starting point and the end point, and P1 is our anchor, which is mentioned above Anchorx and anchory.
So the question is, how many points do we need to know if we want to achieve this drag-and-pull effect?
Let's start with a design diagram.
As you can see, in the design diagram, there are p1-p4 four coordinate points, is the intersection coordinate of two circular tangent line and circle, because need p1-p2 and P3-P4 two Bezier curve of the same degree of distortion, so the anchor point only need to P0 to the origin of the coordinates of the line to take a point, so we need 5 coordinate points.
Let me drink my saliva ^_^
Come on, let's go!
So, now that you know what five coordinate points are needed, Anchorx and anchory are already calculated in Ontouchevent (), so what are the remaining 4 coordinate points? In fact, this is the main work done within the calculate ().
Since the radius of the two circle is set to the same, you can streamline the calculation, so the following code is also assumed two circle radius of the same operation, and then you hand in a picture of the elder brother, big picture of HD uncensored
StartX and Starty is the specified value, here we use it as the coordinate origin, the other circle coordinates (x, y), that is, the position of the finger touch coordinates, the two circle radius is the same, then the tangent line parallel, over (x, y) points do vertical lines perpendicular to two tangents.
Now, known (Startx,starty), (x, y), radius radius, there is a right angle, so we just need to know an angle, and then we can find out offsetx and offsety, also find out the P1-p4 four point coordinates ~ ~ ~
So this angle is good?
Simple, another HD uncensored big picture ~
Because
So
∠α=∠1
This is the middle school of the three paragraph style ... Forget about
So how does ∠1 beg? Simple, (x, y) all know,
tan∠1= (Y-starty)/(X-STARTX);
So you can get
∠1 = arctan ((y-starty)/(X-STARTX))
Know the angle, know radius, still can't find out offsetx and offsety?
So
float offsetX = (float) (radius*Math.sin(Math.atan((y - startY) / (x - startX))));float offsetY = (float) (radius*Math.cos(Math.atan((y - startY) / (x - startX))));
So. , and now look at the following code, you still say you do not understand it?
PrivatevoidCalculate () {float Distance= (float) Math.sqrt(Math.POW(Y-starty,2) + Math.POW(X-startx,2)); Radius =-Distance/ the+default_radius;if(Radius <9) {Isanimstart =true; Exploredimageview.setvisibility (view.visible); Exploredimageview.setimageresource (R.drawable.tip_anim); ((animationdrawable) exploredimageview.getdrawable ()). Stop (); ((animationdrawable) exploredimageview.getdrawable ()). Start (); Tipimageview.setvisibility (View.gone); }Four points of the quadrilateral are calculated according to the angle floatOffsetX = (float) (Radius*math.Sin(Math.Atan((Y-starty)/(X-STARTX)));floatOffsetY = (float) (Radius*math.Cos(Math.Atan((Y-starty)/(X-STARTX)));floatx1 = startx-offsetx;floatY1 = Starty + OffsetY;floatx2 = x-offsetx;floaty2 = y + OffsetY;floatx3 = x + OffsetX;floatY3 = y-offsety;floatx4 = StartX + OffsetX;floatY4 = starty-offsety; Path.reset (); Path.moveto (x1, y1); Path.quadto (Anchorx, anchory, x2, y2); Path.lineto (x3, y3); Path.quadto (Anchorx, Anchory, X4, Y4); Path.lineto (x1, y1);//Change the location of the iconTipimageview.setx (X-tipimageview.getwidth ()/2); Tipimageview.sety (Y-tipimageview.getheight ()/2); }
Figure out the coordinates of 4 points, and know the location of the anchor point, and connect it with path is OK
Hungry, this article is here, go down to eat rice
Related projects and articles
- Mobile phone QQ5.0 The implementation of the red dot drag and drop removal
- QQ Mobile version 5.0 "One key off work" Design summary
Related projects
- Project Address https://github.com/dodola/MetaballLoading
Respect the original, reproduced please specify: from Kaizico (http://blog.csdn.net/zhaokaiqiang1992) infringement must investigate!
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
"Open Source project resolution" QQ "one Click off" function implementation analysis-learning path and the basic use of Bezier curve