Android Custom view--implements Dribbble's [Open & Close] Design

Source: Internet
Author: User
Tags cos sin

1. Summary

The popular level of Open & Close in Dribbble can be ranked on all shots's homepage. And the design is relatively concise, the difficulty of implementation is relatively small, you can take to practice practiced hand. The source of this article bash: Roujiamo

2. Analysis

Before the beginning of the animation is the classic hamburger, composed of the top and bottom three lines, to L1, L2, L3, the end of the animation turned into a close button.

The closed "X" is hamburger by the L1 and L3 of the rotation. Where L1 around the right end point counterclockwise rotation 45°,l3 around the right end of the clockwise rotation of 45 °. After rotation, the y-coordinate of the L1 ends is the same as the coordinates of the left and right endpoints, and the intersection is at the center of the entire screen. This shows that there is not only a rotational transformation, but also a displacement transformation in the negative direction of the x-axis, otherwise the intersection must be right. In order to ensure the same y-coordinate after rotation, the distance between single line length linelength and L1, L3 is limited. According to the relevant knowledge of trigonometric functions can be calculated quickly, height = linelength * sin (45°). It is also known from the trigonometric functions that the linear rotation is mapped to linelength * cos (45°) on the x-axis, which translates the distance of LineLength * (1-cos (45°))/2 to the negative direction of the x-axis.

Then analyze the changes of L2 and circumscribed circle, L2 to the right and gradually transform into a curve close to the external arc, when the L2 began to turn into an arc, the arc began to gradually become larger and counterclockwise rotation. The line is gradually transformed into the animation of the curve I have not thought of how to achieve the specific, you can refer to this blog: Making a SVG HTML Burger Button. He is using SVG to achieve, roughly judge where the curve transformation part is actually just moving the rotation of a picture, this picture is an excessive curve (if there are errors, welcome to point out). This article does not intend to implement this part of the curve transformation, and will replace the animation in another way. First, let the L2 translate in the positive direction of the x-axis until the L2 left endpoint reaches circumscribed circle, while keeping the right endpoint no more than circumscribed circle. When the right endpoint reaches circumscribed circle, the circumscribed circle transformation begins, and the arc starts at 0° to 360 °, and the entire process is rotated 135 ° counterclockwise.

Finally, as can be seen from the GIF graph, many animations are not linear transformations, it is necessary to use the Android Interpolator. Refer to the Interpolator in Android for details, and the mathematical curves given in this article can quickly find the interpolator we need. Where L1, L3 can use Anticipateovershootinterpolator,l2 Anticipateinterpolator, arc is used acceleratedecelerateinterpolator. Using the Interpolator has the following problem, L2 right end point when the specific time to reach the arc, this time is not good calculation, you need to solve a three-time equation. In this paper, the time point is set to a fixed value, although not accurate, but the error is very small, acceptable.

3. Design and implementation

According to the above analysis, there is a clear outline of what to achieve, but in addition to the "painting" function, we also need to save the state, when the screen switch, can revert to the previous state. Also listen for click events to trigger animations. can be "painting" This function separate out, with drawable to achieve, the rest of the view in the implementation. The advantage of this is that the main function can be independent of any view, and the actual application limit is less. In the final application section you will recognize the advantages of doing so.

Start from the simple part, since the use of Drawable,view is chosen ImageView, because this class can be Setimagedrawable method to set up drawable, more convenient. The listening state is simple, skip. Look directly at the state of the Save, which has two states: open and close, as long as a Boolean variable is saved. When it comes to conservation, it's natural to think about the onsaveinstancestate and onrestoreinstancestate of activity. These two methods are also available in view. In this way, we only need to save and restore the state in each of these two methods. You can define a class to act as the role of the data model, and you can, of course, not do it and writeint it directly into the bundle. Let's look at the code below:

    @Override     protected parcelable onsaveinstancestate () {         parcelable superstate = super.onsaveinstancestate ();               savedstate ss = new savedstate (superstate); Gets the current state         Ss.open = Drawable.isopen ();         return ss;   }    @Override     protected void Onrestoreinstancestate (parcelable State) {        if (! ( State instanceof savedstate)) {            Super.onrestoreinstancestate (state);            return;        }        Final savedstate ss = ( savedstate) state;        super.onrestoreinstancestate (ss.getSuPerstate ());        Post (new Runnable () {             @Override             public void Run () {//sets the current state and redraws, three parameters indicate: current state, whether animation is required, whether to redraw &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&N bsp;       Setopen (Ss.open, False, True);            }       });   } private static Class        Savedstate extends Basesavedstate {Boolean open;        Savedstate (parcelable superstate) {super (superstate);            } private Savedstate (Parcel in) {super (in);        This.open = in.readint () = = 1;            } @Override public void Writetoparcel (Parcel out, int. flags) {Super.writetoparcel (out, flags);        Out.writeint (This.open 1:0);       } public static final parcelable.creator<savedstate> Creator = new Parcelable.creator<savedstate&gt                     ;() {public savedstate createfromparcel (Parcel.) {return new savedstate (in); } public savedstate[] NewArray (int size) {return new saveds                    Tate[size];    }                }; }
The code is very simple, not too many comments, of which two methods have been given a description, the implementation of a temporary no tube, know its function on the line. To be reminded, Android Honeycomb and later versions have hardware-accelerated features, it is best to disable in view, or the animation when the screen will be rotated when the bug occurs. You can disable the hardware slowdown by using the following code:
    if (Android.os.Build.VERSION.SDK_INT >= Android.os.Build.VERSION_CODES. Honeycomb) {        setlayertype (view.layer_type_software, null);    }

Finally, the main play, this article only introduces the subject of the process, the details of the analysis of readers can read the source code themselves. The above has been analyzed, is nothing more than drawing three straight lines a curve. Since the L1 and L3 are rotated around their right end points, except for the shift in the negative direction of the x-axis to ensure the centering, we can only assume that the left end is rotated around the right end. This transforms the rotation of the line segment into a point rotation. Well, assuming the coordinates of the point after the rotation and the displacement of the x-axis in the negative direction we all know, then it's easy to draw a graph.

    @Override public    void Draw (canvas canvas) {        //translate and rotate  topstartrotated L1 the coordinates after the left endpoint is rotated,  Topend L1 right end point,  TranslateX X-axis negative direction displacement        canvas.drawline (Topstartrotated.x-translatex, Topstartrotated.y, Topend.x-translatex, TOPEND.Y, paint);        Just translate  middletranslatestart L2 displacement of the left end, middletranslateend L2 displacement after the right end of        Canvas.drawline ( Middletranslatestart.x, Middletranslatestart.y, middletranslateend.x, MIDDLETRANSLATEEND.Y, paint);        Arc circumscribed circle Contour, Arcstartangle Arc's starting angle, Arcsweepangle arc angle        canvas.drawarc (arc, Arcstartangle, Arcsweepangle, False, paint);        Translate and rotate  bottomstartrotated L3 the coordinates after the left endpoint is rotated, bottomend L3 right endpoint        Canvas.drawline ( Bottomstartrotated.x-translatex, Bottomstartrotated.y, Bottomend.x-translatex, BOTTOMEND.Y, paint);    }
Just mentioned the point of rotation, then how do we calculate a point around the other point rotation after the coordinates? Here's a formula:
        Rotate        //(X0,Y0) is after (x, y) rotating around (rx0, ry0)        //x0= (x-rx0) *cos (a)-(Y-RY0) *sin (a) + rx0; c3/>//y0= (x-rx0) *sin (a) + (Y-RY0) *cos (a) + ry0;
(X0,Y0) is the coordinate of the point (x, y) around the point (rx0,ry0) after a degree is rotated. The coordinates of the starting point (x, y) can be computed in the Onboundschange method, with only the overall centering, and the height between L1 and l3 = LineLength * sin (45°).

The key point is also introduced, the following is to say the flow of animation. To be blunt, animation is achieved through constant redrawing. This article is a separate thread to do this part of the work. Constantly calculate how long the animation is going to update the progress of the animation, while updating the position of the 4 lines, and finally notify the view redraw. To conserve resources, approximately 20ms is redrawn once. At the beginning of the animation, the current time is recorded as the start time of the animation, each cycle takes the system current time minus the animation start time, this is the progress of the animation. When the animation is close, it is actually the open rewind. Simply subtract the animation start time from the current time and add the length of the animation. The notification view redraw can be done by the Invalidateself method, but it is not possible to call this method directly on a non-UI thread, with scheduleself to solve the problem.

    Private Runnable Minvalidatetask = new Runnable () {@Override public void run () {invalidates        Elf ();    }    };        private void Toggleanim () {///animation progress ratio, open for the end of the animation, whether the state is open float percent = open? 0:1;        Animation progress int timelapse;        Current time long cur;        float tmp;        Animation start time Long animstarttime = Systemclock.uptimemillis ();            While (Percent <= 1 && percent >= 0) {cur = Systemclock.uptimemillis ();            if (open) {timelapse = (int) (cur-animstarttime);            } else {timelapse = (int) (burgerdrawable.duration + animstarttime-cur);            } percent = (float) timelapse/burgerdrawable.duration;            TMP = Math.min (1, percent);            TMP = Math.max (0, TMP);            Update the animation progress of the four curves, that is, update their location, see Source Setpercentage (TMP, FALSE);            Scheduleself (Minvalidatetask, cur);                try {Thread.Sleep (20);            } catch (Interruptedexception e) {e.printstacktrace ();    }} animating = false; }
Notice that we use the Systemclock.uptimemillis () method instead of System.currenttimemillis () for system time. The former takes the time to boot until now, while the latter takes the current time of the system setup, which is likely to be modified, while the former cannot be modified.

4. Application

Burger button Of course is to combine with Actionbar to use together, click Burger, the left menu pops up or is closed. The menu on the left side of this article uses Android's own drawerlayout. The step to create a new Navigation Drawer activity,android Studio is to right-click the source directory--new--> activity--> Navigation Drawer Activity. This action automatically generates files such as activity, fragment, and so on. Open Navigationdrawerfragment.java directly, notice that there is a class actionbardrawertoggle, which is used to control the animation of the Homeasup icon, so we have to do the same work as it does. This class in the SUPPORT-V4 package, directly copied over, found that the absence of two references to the class, Actionbardrawertogglehoneycomb and ActionBarDrawerToggleJellybeanMR2, and copied out. These two classes are actually designed to be compatible with different versions of the Sethomeasupindicator method to set the Homeasup icon to our drawable. Finally, change its mslider to our implementation of the drawable, the call to the Mslider method is also modified to our, such as set state. The whole Actionbardrawertoggle class code is more, but we change the place very few, here is not affixed, see source code.

Finally, we achieve the following effects:


Android Custom view--implements Dribbble's [Open & Close] Design

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.