Android Imitation QQ round head personality business card _android

Source: Internet
Author: User
Tags abs cos pow sin

First look at the effect chart:


In the middle of the circular head and Halo wave explanation please see: http://www.jb51.net/article/96508.htm
The surrounding bubble layout, because the layout ratiolayout is inherited from ViewGroup, so the layout layout can layout its child view,view.layout according to its requirements (int l,int t,int r,int b); Used to lay out the location of the child view in the parent viewgroup (relative to the parent container), so the left,top,right,bottom of all the child view is computed in ratiolayout. So how does the bubble view around the avatar calculate its left,top,right,bottom, the Bubble view is located on the outer circle of the avatar, so long as the radius of the circle is known, and then the angle between each bubble is calculated according to the number of bubbles, Radius plus angle can calculate where each bubble is located.

/** * Calculates the layout position of the bubble * @param textviews * * * private void Calculateratioframe (list<bubbleview> textviews) {if (Te 
 Xtviews.size () = = 0) return; 
 
 Mratioframelist.clear (); Double angle = 0;//record the angle of each bubble, just above the 0°double grad = Math.PI * 2/textviews.size ();/gradient, the angle between each textview (Math.PI is the mathematics of 90° Double rightangle = math.pi/2;//One lap for 360°, altogether four directions, each direction 90°, we calculate according to less than equal to 90 °, then put in the corresponding direction//cx,cy is the center point of the container, also is the center point of the circular head, calculate the bubble Is the cx,cy of the int cx = mwidth/2;//Container Center x coordinate int cy = mheight/2;//Container Center y coordinate int radius = MMINSIZE/2/2/2 
 + MMINSIZE/2/2;//The radius of the composition circle of the dynamic bubble int left = 0; 
 int top = 0; 
 int right = 0; 
 int bottom = 0; int a = 0,b = 0;//a is CX based offset, B is based on CY offset,//int r = MMINSIZE/6/2;//bubble radius for (int i = 0; i < textviews.size (); i+ +) {int r = textviews.get (i). Getmeasuredwidth ()/2;//calculated//fixed dead MMINSIZE/6/2;//bubble radius if (angle >= 0 && A Ngle < Rightangle) {//0-90 degree is calculated offset//Hold angle in 0-90 a = (int) (RADIUS * Math.sin (math.abs% rIghtangle))); 
 
 b = (int) (RADIUS * Math.Cos (math.abs (angle% rightangle))); 
 left = cx + A-R;//CX + A is the center of the bubble, and you need to subtract the radius r top = cy-b-R; 
 right = left + 2 * r; 
 
 
 Bottom = top + 2 * r; }else if (angle >= rightangle && Angle < Rightangle * 2) {//90-180 a = (int) (RADIUS * Math.sin (Math.Abs ( 
 Angle% rightangle))); 
 b = (int) (RADIUS * Math.Cos (math.abs (angle% rightangle))); 
 left = cx + b-r; 
 top = cy + a-r; 
 right = left + 2 * r; 
 
 
 Bottom = top + 2 * r; }else if (angle >= rightangle * 2 && Angle < Rightangle * 3) {//180-270 a = (int) (RADIUS * Math.sin (Math 
 . ABS (angle% rightangle)); 
 b = (int) (RADIUS * Math.Cos (math.abs (angle% rightangle))); 
 left = cx-a-R; 
 top = cy + b-r; 
 right = left + 2 * r; 
 
 Bottom = top + 2 * r; }else if (angle >= rightangle * 3 && Angle < Rightangle * 4) {//270-360 a = (int) (RADIUS * Math.sin (Math). 
 ABS (angle% rightangle)); b = (int) (RADIUS * Math.Cos (Math.Abs (Angle% rightangle))); 
 left = Cx-b-R; 
 top = cy-a-R; 
 right = left + 2 * r; 
 
 Bottom = top + 2 * r; 
 ///Will compute good left, top, right,bottom,angle to save Mratioframelist.add (new Ratioframe (left, top, right,bottom,angle)); 
 
 Angle plus a gradient value angle + = Grad; 
 } 
 }

Calculate the layout of Bubbles left,  top, Right,bottom, and then start laying out the bubbles, the code in the layout is much simpler

@Override protected void OnLayout (Boolean changed, int l, int t, int r, int b) {if (Mimageview = = null) return; int width = mimageview.getmeasuredwidth ();//compute the width int height = mimageview.getmeasuredheight () of the circular Head,//Calculate the height//of the round head the L of the round head 
 EFT, top, Right,bottom int left = MWIDTH/2-WIDTH/2; 
 int top = MHEIGHT/2-HEIGHT/2; 
 int right = MWIDTH/2 + WIDTH/2; 
 int bottom = MHEIGHT/2 + height/2; 
 Start Layout mimageview.layout (Left,top,right,bottom); 
 Layout love animation for (int i = 0; i < mlovexinlist.size (); i++) {ImageView ImageView = Mlovexinlist.get (i); 
 left = Mwidth/2 + WIDTH/4-imageview.getmeasuredwidth ()/2; 
 Bottom = Mheight/2 + HEIGHT/3; 
 top = Bottom-imageview.getmeasuredheight (); 
 
 right = left + imageview.getmeasuredwidth (); 
 Imageview.layout (Left,top,right,bottom); 
 
 }//Layout all bubbles for (int i = 0; i < mtextviews.size (); i++) {TextView TextView = Mtextviews.get (i); Ratioframe ratioframe = Mratioframelist.get (i)//use without animation
 When there is animation, the execution period left, top, and Right,bottom are all in the variable if (mcurrentratioframelist!= null) {//valueanimator animation is produced by all bubbles left, top, R 
 Ight,bottom ratioframe ratioframe = Mcurrentratioframelist.get (i); 
 Textview.layout (Ratioframe.mleft,ratioframe.mtop,ratioframe.mright,ratioframe.mbottom); 
 } 
 
 } 
 
 }

OK, static bubble typesetting here is good, the following question is how to expand the bubble from the center point to the curved path, and the size of the bubble is also from small to large changes. Here on the use of animation class Valueanimator and Scaleanimation, please refer to the detailed: http://www.jb51.net/article/96509.htm
Outward expanding effect we can use View.layout () to constantly rearrange bubble view to produce a translation effect, the following question is how to calculate the translation of the upper left, top, Right,bottom, and then request the layout again, So here's how to figure out how to compute this trajectory and analyze

Arc trajectory calculation, in fact, in line trajectory based on the addition of offset (Movex and Movey), the formation of the arc trajectory, the line trajectory is well calculated, the key is this offset, because in the first offset is small, and in the middle of the offset is large, and in different directions, The value of Movex and Movey is not the same as the positive or negative. The offset distance is from small to large and then from large to small, so we use two times function (-2 * MATH.POW (fraction,2) + 2 * fraction) to calculate the distance, with the value of the two function multiplied by a set maximum value, The maximum value is changed from small to large and then from big to small, and then the positive and negative of it is calculated from different angles.

if (endratioframe.mangle >0 && endratioframe.mangle <= rightangle) {//(0 < angle <= 90) up, move left MoveX = (int) (Temp * Math.Abs (Math.Cos (Endratioframe.mangle)); The move up should subtract movex Movey = (int) (temp * Math.Abs (Math.sin) ( 
 Endratioframe.mangle)));  }else if (Endratioframe.mangle > Rightangle && endratioframe.mangle <= rightangle * 2) {//(M < angle <= 
 180) Move right, move up MoveX = (int) (-TEMP * Math.Abs (Math.Cos (Endratioframe.mangle))); 
 Movey = (int) (temp * Math.Abs (Math.sin (Endratioframe.mangle))); }else if (Endratioframe.mangle > Rightangle * 2 && endratioframe.mangle <= Rightangle * 3) {//(180 < angle 
 <= 2700) Move down, right shift MoveX = (int) (-TEMP * Math.Abs (Math.Cos (Endratioframe.mangle))); 
 Movey = (int) (-TEMP * Math.Abs (Math.sin (Endratioframe.mangle))); }else if (Endratioframe.mangle > Rightangle * 3 && endratioframe.mangle <= rightangle * 4 | | endratioframe.ma Ngle = = 0) {//(270 < angle <= 360 or angle = 0) Move left, move Down MoveX= (int) (temp * Math.Abs (Math.Cos (Endratioframe.mangle)); 
 Movey = (int) (-TEMP * Math.Abs (Math.sin (Endratioframe.mangle))); 
 }

Depending on the value of the trigonometric function, the above code can be simplified to

MoveX = (int) (temp * Math.Cos (endratioframe.mangle)); 
Movey = (int) (temp * Math.sin (endratioframe.mangle)); 

Through the above calculation formula logic, we can get the type estimator of the bubble expansion, the implementation class, exit the bubble will be the logic back to the

Package com.cj.dynamicavatarview.ratio; 
Import Android.animation.TypeEvaluator; 
Import Android.content.Context; 
 
Import Android.util.TypedValue; 
Import java.util.ArrayList; 
 
Import java.util.List; 
 /** * Created by Chenj on 2016/10/19. 
 
 * * Public class Enterratioframeevaluator implements Typeevaluator {public static final int offset_distance = 80; 
 
 Private context Mcontext; 
 
 private int moffsetdistance; 
 Public Enterratioframeevaluator {this.mcontext = context; moffsetdistance = (int) typedvalue.applydimension (typedvalue.complex_unit_dip,offset_distance, 
 Mcontext.getresources (). Getdisplaymetrics ()); @Override Public Object evaluate (float fraction, object Startvalue, Object Endvalue) {list<ratioframe> Startratioframelist = (list<ratioframe>) startvalue;//start value list<ratioframe> endRatioFrameList = (List< ratioframe>) endvalue;//End value list<ratioframe> ratioframelist = new arraylist<> (); 
 
 for (int i = 0; i < endratioframelist.size (); i++) {Ratioframe endratioframe = Endratioframelist.get (i); 
 Ratioframe startratioframe = Startratioframelist.get (i); Compute Left,top,right,bottom Double t = (-2 * MATH.POW (fraction,2) + 2 * fraction);//tilt change rate int temp = (int) (Moffset 
 Distance) * t); 
 
 Double rightangle = MATH.PI/2; 
 int MoveX = 0,movey = 0; 
 Move the bubbles up, down, left, and right to form the translation line of radians MoveX = (int) (temp * Math.Cos (endratioframe.mangle)); 
 Movey = (int) (temp * Math.sin (endratioframe.mangle)); Re-get left, Top,right,bottom int left = (int) (Startratioframe.mleft + (endratioframe.mleft-startratioframe.mleft) * f 
 raction)-MoveX); 
 int top = (int) (Startratioframe.mtop + (endratioframe.mtop-startratioframe.mtop) * fraction)-Movey); 
 int right = (int) (Startratioframe.mright + (endratioframe.mright-startratioframe.mright) * fraction)-MoveX); int bottom = (int) (Startratioframe.mbottom + (endratioframe.mbottom-startratioframe.mbottom) * fraction)-moVey); 
 Ratioframelist.add (New Ratioframe (Left,top,right,bottom)); 
 return ratioframelist; 
 } 
}

The following can be used Valueanimator to achieve the arc translation trajectory

Valueanimator manimatorenetr = valueanimator.ofobject (New Enterratioframeevaluator (GetContext ()), Getratioframecenterlist (mratioframecenter,mratioframelist), mratioframelist); 
 Manimatorenetr.addupdatelistener (New Valueanimator.animatorupdatelistener () { 
 @Override public 
 Void Onanimationupdate (Valueanimator animation) { 
 //Get new layout value 
 mcurrentratioframelist = (list<ratioframe>) Animation.getanimatedvalue (); 
 Request a 
 requestlayout (); 
 } 
 ); 
 Manimatorenetr.setduration (Open_bubble_time); 
 
 

OK, the Arc animation that expands from the center point to this is achieved, and then add the zoom animation can be, zoom animation using view animation can be achieved.

/** 
 * Bubbles from small to large scale 
 * @param textviews 
 /private void Scalesmalltolarge (list<bubbleview> textviews { 
 //view Center as the zoom point, from the initial state to see 
 scaleanimation animation = new Scaleanimation ( 
 0.0f, 1.0f,//a little bit smaller know to see so far 
 0.0f, 1.0f, 
 Animation.relative_to_self, 0.5f, animation.relative_to_self, 0.5f//Intermediate scaling 
 ); 
 Animation.setduration (Open_bubble_time)//To peacefully move the time consistent for 
 (int i = 0; i < textviews.size (); i++) { 
 //Execute animation C14/>textviews.get (i). Startanimation (animation); 
 } 
 
  

The following solution is to expand, the bubble began to float, click on the bubble stopped floating after the finger after the bubble to move after the finger, release the bubble back to the original position, the return of the animation effect and bubble unfolded animation effect is very similar, bubbles follow the finger movement is also very good to achieve, Just set the bubble view to Ontouch event, then ontouch the distance of the slide, and then View.layout () again, so we can solve the floating problem here. Floating is irregular, and floating distance and speed is not the same, I use the view animation to achieve the effect is not very good, and then instead of the property animation to achieve. Just move the view to the X and Y axes, so that the translation is different in distance and time, and it looks like an irregular movement, so that it can be repeated to do so to achieve the effect of floating.

/** * Set floating effect on the specified view * @param view * @return/private Animatorset setanimfloat (view view) {List<animato 
 r> animators = new arraylist<> (); GETRANDOMDP () gets a random value objectanimator Translationxanim = objectanimator.offloat (view, "Translationx", 0f, 
 GETRANDOMDP (), GETRANDOMDP (), 0); 
 Translationxanim.setduration (Getrandomtime ()); Translationxanim.setrepeatcount (valueanimator.infinite);//infinite Loop Translationxanim.setrepeatmode ( 
 Valueanimator.infinite);//Translationxanim.setinterpolator (New Linearinterpolator ()); 
 Translationxanim.start (); 
 Animators.add (Translationxanim); 
 Objectanimator Translationyanim = objectanimator.offloat (view, "Translationy", 0F,GETRANDOMDP (), getRandomDp (), 0); 
 Translationyanim.setduration (Getrandomtime ()); 
 Translationyanim.setrepeatcount (Valueanimator.infinite); 
 Translationyanim.setrepeatmode (Valueanimator.infinite); 
 Translationxanim.setinterpolator (New Linearinterpolator ()); 
 Translationyanim.start (); Animators.aDD (Translationyanim); 
 Animatorset animatorset = new Animatorset (); 
 Animatorset.playtogether (animators); 
 Animatorset.setstartdelay (delay); 
 Animatorset.start (); 
 return animatorset; 
 }

Hold and stop the float, loosen the time first, and then float again, if Animator.end () method, return to start floating when the phenomenon will appear flashing, because the property animation, although can change the position of view, but will not change the view of the Left,top,right, Bottom, so the flicker occurs when you start floating again, because x = Mleft + Translationx, when you start over, the property animation is recreated, Translationx starts at 0, and therefore flashes.

Final Animatorset Animatorset = manimatorsetlist.get (position); 
 for (animator Animator:animatorSet.getChildAnimations ()) { 
 //execute to the end of the animation, revert to the original position, or start floating again, there will be a flashing bug 
 if ( Animator.isrunning ()) { 
 animator.end ();//execute to animation last 
 animator.cancel ();//Cancel Animation 
 } 
 } 

The process is almost there, but when the bubbles move to the inside of the round head release, the bubble should have a scaling effect back to the position, and then there should be an interface callback, tell the caller, I went to the middle of the release, you can do some corresponding processing. Now let's look at how to calculate that the bubbles have moved into the avatar, in fact, through the Circle Head Center point and the center of the bubble to form a direct triangle, and then through the Pythagorean theorem, calculate the length of the right angle and the radius of the circular head, if less than the radius of the circle head, it is already into the avatar inside.

/** * Determine if the bubble center point is inside the picture * @param view * @param where current is currently moving * @param endratioframe If in the middle, the value is used to reset to the original location * @return * Private Boolean isinpicturecenter (int position,view view,ratioframe current,ratioframe endratioframe) {RatioPoin 
 T centerpoint = new Ratiopoint (MWIDTH/2,MHEIGHT/2); Ratiopoint currentpoint = new Ratiopoint (Current.mleft + ((current.mright-current.mleft)/2), Current.mtop + ((current.m 
 Bottom-current.mtop)/2)); 
 int x = Math.Abs (centerpoint.x-currentpoint.x); 
 int y = Math.Abs (CENTERPOINT.Y-CURRENTPOINT.Y); 
 The distance int edge = (int) math.sqrt (Math.pow (x,2) + Math.pow (y,2)) is computed by the Pythagorean theorem. 
 int pictureradius = Mimageview.getpictureradius (); Then and the inner picture of the half catty comparison, less than Pictureradius, on the internal if (Pictureradius > Edge) {//Enter into the internal if (Minnercenterlistener!= null) {Minner 
 Centerlistener.innercenter (position, (TextView) view). GetText (). toString ()); 
 }//Description to center, perform bubble scaling revesescaleview (position, view,current,endratioframe); 
 return true; Return FalsE 
 }

Bubble Execution Scaling

/** * Zoom picture (motion Tween) * @param view * @param The starting point for panning after the current zoom @param endratioframe the end of the zoom for translation * * public void R Evesescaleview (final int position, Final view view, Final Ratioframe current, final Object endratioframe) {//To view Center for Zoom point, from the initial state narrowed to see scaleanimation animation = new Scaleanimation (1.0f, 0.0f,//a little smaller know not see so far 1.0f, 0.0f, Animation.rel 
 Ative_to_self, 0.5f, animation.relative_to_self, 0.5f//intermediate scaling); 
 Animation.setduration (Bubble_enter_center_scale_time); 
 Animation.setrepeatmode (Animation.reverse); 
 Animation.setrepeatcount (1); Animation.setanimationlistener (New Animation.animationlistener () {@Override public void Onanimationstart (animation a nimation) {} @Override public void Onanimationend (Animation Animation) {//after scaling, let bubbles return to the position, after the end, perform interface callback Homingbu 
 Bbleview (True,position,view, Current, endratioframe); 
 @Override public void Onanimationrepeat (Animation Animation) {}}); 
 View.startanimation (animation); 
 }

Interface callback definition for bubbles into the center

public interface innercenterlistener{ 
 //Enter the center, loosen the return position and invoke 
 void innercenterhominged (int position, String text); 
 Enter Center, call 
 void innercenter (int position, String text) when released; 
  

The following is left to perform plus 1 operation and play Love animation, the two animation is to perform two view animation, here is not posted, to the high imitation QQ personalized business card on the end, if not good or have questions to welcome the message
SOURCE Download: GitHub
Download 2

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.