The implementation class is aware of the button click effect that the Android client concerns and cancels attention

Source: Internet
Author: User
Tags hypot

First of all, the project code has been uploaded to GitHub, do not want to see the long-winded can also first go to the code, control code, where do not know the point.
Code in this Https://github.com/zgzczzw/ZHFollowButton

A few days ago found that the attention of the Click Effect really praise, check the implementation of the way, just see this problem, took a day to finally realize the effect, and now to answer, unfortunately, upstairs everyone's answer is not all right, and listen to my one by one.

First, I looked at some of the effects in detail, and there was a magical place,







Look at the second picture, the circle in the diffusion of the word is still in the circle, and the new word is also on the circle, this effect is the most difficult to achieve.


First look at the upstairs answer, summed up, a total of 2 ways to achieve, ripple effect and paint on the canvas to manually draw a circle


Ripple:




Ripple is the ripple effect, is the introduction of Android API 21 after a material design element, is a touch feedback, that is, when the click of the water wave diffusion pattern, the demo (see finally) the first button is the use of the ripple effect.

The implementation is simple and implements a drawable


The first color is a ripple color, item inside specifies background normal color, can be a shape, it can be a drawable, can also be a selector.



Set as the background of the button




If the entire program is theme with Meterial, then all the basic controls with the Click Effect, such as the button, have this ripple effect. However, it is important to note that this set of APIs is only available after 21, so compatibility processing is required.




The effect is as follows:






It can be seen that even if I set the ripple to Red (#FF0000), the effect after the click is also light red, I guess because it is the water ripple effect, in order not to affect the contents of the button itself, the Android system has automatically done the transparency of the processing, it can be clearly seen that the ripples and display content is up and down two layers of , non-impact, water ripple is at the background level. This effect to do ordinary Click feedback is also good, but the absolute realization of this with a ripple to refresh the content of the effect. So it is easy to see that the clicked effect is not done with Ripple.



Paint draws a circle on the canvas

@chaossss said with the paint in the place of the click to draw a circle, and then let the circle radius of the painting gradually become larger, to achieve the spread out of the style, I realized a bit, the code is as follows:

@Overrideprotected void OnDraw (canvas canvas) {super.ondraw (canvas);        if (mshoulddoanimation) {Mmaxradius = Getmeasuredwidth () + 50;        if (Mrevealradius > MMINBETWEENWIDTHANDHEIGHT/2) Mrevealradius + = Mrevealradiusgap * 4;        else Mrevealradius + = mrevealradiusgap;//radius becomes larger paint mpaint = new paint ();        if (!mispressed) {mpaint.setcolor (color.white);        } else {mpaint.setcolor (color.red);        }//Set Brush color Mpaint.setstyle (Paint.Style.FILL);        Canvas.drawcircle (Mcenterx, Mcentery, Mrevealradius, Mpaint); if (Mrevealradius<= Mmaxradius) {//After a certain amount of time and then refresh postinvalidatedelayed (invalidate_duration);                } else {if (mispressed) {settextcolor (color.white);            This.setbackgroundcolor (color.red);                } else {SetTextColor (color.black);            This.setbackgroundcolor (Color.White);            } mshoulddoanimation = false;        Invalidate (); }    }}

Effect












It would have been almost like this, but compared with the effect of the knowledge, we can find the difference. Drawing a circle with paint can be achieved by drawing a circle at the point where it is clicked, and then slowly spreading the radius. The problem, however, is that the circle will cover the contents of the display, and the circle of the drawing cannot display the content . I tried to use the DrawText, also can not achieve the effect of the word and circle together, the solution is only,

    1. The background color and the above text are changed during the painting process.
    2. Then, after the circle is finished, erase the circle and display the background color and text below.

this will cause a text flicker problem, first the text will disappear, and then after the completion of the circle before the display . Because the circle in the diffusion of time is not to see the text, only the circle disappears, the text can be displayed. And the effect is the text and the circle brush out, and the text is still in the middle, there is no text flashing the problem, the whole process of flowing, looks very smooth, as if with a circle to uncover the curtain.

To sum up, all the answers upstairs are the answer of the Lord to see the effect of the first reaction after the realization, in fact, if I did not realize a bit, I really think the second method is known to use, but at present, it is regrettable, know to adopt a better way to achieve this effect.


What to do, I also have no idea, how to draw a circle when the word is also painted on the circle, and then the background of the circle is also there. No idea, look at the code, decompile.


The process of anti-compilation I briefly say:

    • Download the latest Knowledge apk from our website
    • Using Apktool to decompile the APK, get the resource file

    • In the resource file search follow, here at the beginning I searched is ripple, because I think this effect should be related to ripple, no result, so search follow, didn't think really search out.

Revealfollowbutton This is obviously the ripple-unfolding control we want, and that's it, so the next step is to find the control in the code. Here to remember, the position of this control is Com.zhihu.android.app.ui.widget.RevealFollowButton.


    • Anti-compilation Code

Rename apk to RAR, open, can find the class file inside


Know the use of multidex, so there will be two class files, are dragged out in Dex2jar to decompile, you can generate two jar package, put the jar in the GUI to see the code, although the code has been confused, but the basic logic can be seen.



Then, according to the path in the previous XML to find the location of Revelfollowbutton, open the code to see it.




This is the inheritance of the class, Revealfollowbutton inherit from Revealframelayout, and then inherit from Zhframelayout, this zhframelayout's parent class is framelayout, from the name we can see, Revelfollowbutton and Revealframelayout are the two classes that this effect implements.




Seeing the implementation of this effect is based on framelayout, I knew that the method we discussed before actually went in the wrong direction, what would you do if I told you to use Framelayout to achieve this effect?

My idea is to add two TextView to this layout, then a visible one gone, so switch, and then after reading the code, it proves that my idea is right.





Look, there are two textview here. So, in fact, switching TextView is very easy to achieve, the problem is how to achieve the effect of ripple switching, the first thing is to see the OnDraw function, for Groupview is Drawchild method.


Revealfollowbutton the Drawchild method is nothing, basically call the parent class, then we look at Revealframelayout drawchild method.



Here are two parts of the logic, if a condition is satisfied, do the first part, at the beginning I do not know what the condition is, the confusing code can understand the big logic, like this small logic can only take one step to see one step. So assuming that this condition is always false, see the second part, see here instantly understand, the original is the way to cut the canvas, the canvas into a circle, you can do to display the content is also on the circle, not the content is covered under the circle. Then the same way, the circular area is constantly expanding, and then constantly refreshed, is to achieve the effect of the waveform brush out the content. The code looks like this.


protected boolean drawChild(Canvas canvas, View paramView, long paramLong) {    int i = canvas.save();    mPath.reset();    //mCenterX mCenterY是点击的位置,在onTouchEvent里设置    //mRevealRadius是圆的半径,会渐渐变大    mPath.addCircle(mCenterX, mCenterY, mRevealRadius, Path.Direction.CW);    canvas.clipPath(this.mPath);    boolean bool2 = super.drawChild(canvas, paramView, paramLong);    canvas.restoreToCount(i);    return bool2;}

According to the above, there must be something similar to the timer, can constantly change the radius of the circle, and then refresh, in fact, this is found in the code is easy to find. Revealframelayout In addition to this drawchild, there is no other code. So we came to see Revealfollowbutton.


Revealfollowbutton, that's what the timer is about.






A animator object, in fact, this code I do not understand, but the logic is very simple, set a animator, timing 500ms, in the process of modifying the circle radius, and then refresh.

Math.hypot (GetWidth (), GetHeight ()))


This method is based on the Pythagorean theorem to obtain the length of the hypotenuse of the triangle, think about what we want to draw the longest circle radius, yes, is the diagonal length of the textview. So, the whole logic is simple.

I got the code, that's it.




The code for the entire method is as follows, which also includes the control FOLLOWTV and UNFOLLOWTV which display

protected void setfollowed(Boolean isfollowed, Boolean needanimate) {    misfollowed = isfollowed;    if (isfollowed) {        MUNFOLLOWTV.setvisibility(View.VISIBLE);        MFOLLOWTV.setvisibility(View.VISIBLE);        MFOLLOWTV.BringToFront();    } Else {        MUNFOLLOWTV.setvisibility(View.VISIBLE);        MFOLLOWTV.setvisibility(View.VISIBLE);        MUNFOLLOWTV.BringToFront();    }    if (needanimate) {        Valueanimator Animator = Objectanimator.offloat(MFOLLOWTV, "Empty", 0.0F, (float) Math.Hypot(Getmeasuredwidth(), Getmeasuredheight()));        Animator.setduration(500L);        Animator.Addupdatelistener(New Valueanimator.Animatorupdatelistener() {            @Override             Public void onanimationupdate(Valueanimator Animation) {                Mrevealradius = (Float) Animation.Getanimatedvalue();                Invalidate();            }        });        Animator.Start();    }}

According to the current state of the follow TextView or unfollow textview display, and then set a timer to constantly expand the radius of the circle to be drawn, according to the radius of the canvas into a gradually larger circle, and then the content is gradually displayed.

This effect came out, try to run, but also good, but always feel that there is no place, so careful observation, finally found, know the effect in the refresh, the background is not white, or before the state, such as to become concerned, the background is not concerned or in, and we achieve this , the background is white when refreshed.


That's what you know.



It's mine




So it's not so flowing, so we're missing something. At this time, I think of it, before in Revealframelayout's drawchild there is a condition of judgment, then we do not know what its logic is doing, it seems. That part of the logic is to deal with this, when you draw the child control, to draw two, Followtextview and Unfollowtextview, to the shape of the brush with the circle of the control we use to cut the canvas to draw slowly. The other control on the background does not need to be drawn slowly, as long as it is completely drawn. So, suppose the judging condition here is to judge whether the current control is to be brushed with the circle of the control, if not, just draw it directly. So modify the code as follows:


protected Boolean Drawchild(Canvas Canvas, View Paramview, Long Paramlong) {    if (Drawbackground(Paramview)) {        return Super.Drawchild(Canvas, Paramview, Paramlong);    }    int I = Canvas.Save();    MPath.Reset();    MPath.addcircle(Mcenterx, Mcentery, Mrevealradius, Path.Direction.CW);    Canvas.Clippath( This.MPath);    Boolean bool2 = Super.Drawchild(Canvas, Paramview, Paramlong);    Canvas.Restoretocount(I);    return bool2;}

The method of judging is as follows:

private boolean drawBackground(View paramView) {    if (mIsFollowed && paramView == mUnFollowTv) {        return true;    } else if (!mIsFollowed && paramView == mFollowTv) {        return true;    }    return false;}

At this point, the whole effect is exactly the same as the knowledge, the refresh process is flowing, very praise. The effect is as follows













The implementation code has been uploaded to GitHub:

Https://github.com/zgzczzw/ZHFollowButton

The implementation class is aware of the button click effect that the Android client concerns and cancels attention

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.