Android custom control tutorial 1: how to implement the three-level ring menu of the old Youku Client,
Reprinted Please attach this article link: http://blog.csdn.net/cyp331203/article/details/40423727
Let's take a look at the effect:
At a glance, it seems quite dazzling and complicated... In fact, it is not difficult. Let's take a look at how to implement it:
The basic material is as follows:
Let's take a look at how to write the layout file. In fact, the three images are similar. Here we use RelativeLayout to facilitate the addition of small icons.CenterInParentAndAliagnParentBottomOnly a little attention should be paid to the arrangement of the small icon in the outer ring. Here, the left half-side icon uses the leftmost icon as the benchmark, and the right half-side icon uses the rightmost icon as the benchmark, here areIv_channel1AndIv_channel7:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="${relativePackage}.${activityClass}" > <RelativeLayout android:id="@+id/level1" android:layout_width="100dp" android:layout_height="50dp" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:background="@drawable/level1" > <ImageView android:id="@+id/iv_icon_home" android:layout_width="50dp" android:layout_height="50dp" android:layout_centerInParent="true" android:src="@drawable/icon_home" /> </RelativeLayout> <RelativeLayout android:id="@+id/level2" android:layout_width="180dp" android:layout_height="90dp" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:background="@drawable/level2" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_margin="10dp" android:src="@drawable/icon_search" > </ImageView> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_margin="10dp" android:src="@drawable/icon_myyouku" > </ImageView> <ImageView android:id="@+id/iv_icon_menu" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginTop="5dp" android:src="@drawable/icon_menu" /> </RelativeLayout> <RelativeLayout android:id="@+id/level3" android:layout_width="260dp" android:layout_height="130dp" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:background="@drawable/level3" > <ImageView android:id="@+id/iv_channel1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_marginBottom="10dp" android:layout_marginLeft="5dp" android:src="@drawable/channel1" /> <ImageView android:id="@+id/iv_channel2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@id/iv_channel1" android:layout_alignLeft="@id/iv_channel1" android:layout_marginBottom="7dp" android:layout_marginLeft="18dp" android:src="@drawable/channel2" /> <ImageView android:id="@+id/iv_channel3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@id/iv_channel2" android:layout_alignLeft="@id/iv_channel2" android:layout_marginBottom="2dp" android:layout_marginLeft="35dp" android:src="@drawable/channel3" /> <ImageView android:id="@+id/iv_channel4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginTop="5dp" android:src="@drawable/channel4" /> <ImageView android:id="@+id/iv_channel7" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_marginBottom="10dp" android:layout_marginRight="5dp" android:src="@drawable/channel7" /> <ImageView android:id="@+id/iv_channel6" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@id/iv_channel7" android:layout_alignRight="@id/iv_channel7" android:layout_marginBottom="7dp" android:layout_marginRight="18dp" android:src="@drawable/channel6" /> <ImageView android:id="@+id/iv_channel5" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@id/iv_channel6" android:layout_alignRight="@id/iv_channel6" android:layout_marginBottom="2dp" android:layout_marginRight="35dp" android:src="@drawable/channel5" /> </RelativeLayout></RelativeLayout>
Effect after layout:
Then we can start how to implement this. Our basic idea is (level1 is the small house icon, level2 is the gray part of the second circle, and level3 is the outermost circle ):
1. Click the small house icon. If both level2 and level3 are displayed, the two layers are hidden. If neither of the two layers does exist, only level2 is displayed; if only level2 is displayed, hide level2
2. Click the "3" icon in levle2 to hide and display the level3 component.
3. Click the menu key of the mobile phone. If level1, 2, and 3 are both displayed, all three are hidden. If only level1 and level2 are displayed, level1 and 2 are hidden, if only level1 is displayed, level1 is hidden. If no level is displayed, level1 and level2 are displayed.
4. The above display and hiding processes are all implemented using animations.
The basic logical relationship has been clearly understood by the manager, so the question now is how to write the Animation. Obviously, we need to useRotateAnimationSince the rotation animation involves the spin-out and spin-in effects, we must be clear about thisHow is the animation angle determined?For example, from 0 ~ 180 is the spin-in or spin-out effect?
After experiments, we found that,RotateAnimationWe can find that,Its angle is defined to grow clockwise.:
From this perspective, if we want to rotate the components clockwiseHow can we determine the clockwise rotation angle??
It can be easily seen that the clockwise rotation is from 0 ~ 180 degrees, how about turning in? Is it from 180 ~ 0 degrees ?, In fact, the value here should be 180 ~ 360 degrees.
After the angle is determined, we can start to implement the animation effect. Here, because the three components level1, level2, and level3 are consistent, we choose to use oneTool class to implement several static methodsTo define the animation for reuse:
Tool class:
Package com. alexchen. youkumenuexercise. utils; import android. view. view; import android. view. animation. rotateAnimation; public class AnimationUtils {// spin-out animation, no delay time public static void startAnimationOut (View view) {startAnimationOut (view, 0);} // spin-in animation, no delay Time public static void startAnimationIn (View view) {startAnimationIn (view, 0);} // The animation to be rotated // delay indicates the animation delay time, the Unit is millisecond public static void startAnimationOut (View view, long delay) {RotateAnimation animation = new RotateAnimation (0,180, view. getWidth ()/2, view. getHeight (); animation. setDuration (500); animation. setStartOffset (delay); animation. setFillAfter (true); view. startAnimation (animation);} // The converted animation // delay is the animation delay time, in milliseconds public static void startAnimationIn (View view, long delay) {RotateAnimation animation = new RotateAnimation (180,360, view. getWidth ()/2, view. getHeight (); animation. setDuration (500); animation. setStartOffset (delay); animation. setFillAfter (true); view. startAnimation (animation );}}
There are two ways to enable animation with latency, in order to make the three components show a sense of excitement when they are in and out, so that the user experience is better.
FinallyCode in Activity, There is no lifecycle-related processing here, but the simple implementation function is as follows:
Package com. alexchen. youkumenuexercise; import com. alexchen. youkumenuexercise. utils. animationUtils; import android. app. activity; import android. OS. bundle; import android. view. keyEvent; import android. view. view; import android. view. view. onClickListener; import android. widget. imageView; import android. widget. attributes; public class MainActivity extends Activity implements OnClickListener {private RelativeLayout level1; private RelativeLayout level2; private RelativeLayout level3; private ImageView attributes;/*** indicates whether level3 is in the current state, the default value is true */private boolean isLevel3In; private boolean isLevel2In; private boolean isLevel1In; @ Overrideprotected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); isLevel3In = true; isLevel2In = true; isLevel1In = true; initViews (); listener ();}/*** sets the listener event of views */private void setOnclickListenersForViews () {iv_icon_home.setOnClickListener (this); initialize (this);}/*** initialize the required view component */private void initViews () {level1 = (RelativeLayout) findViewById (R. id. level1); level2 = (RelativeLayout) findViewById (R. id. level2); level3 = (RelativeLayout) findViewById (R. id. level3); iv_icon_menu = (ImageView) findViewById (R. id. iv_icon_menu); iv_icon_home = (ImageView) findViewById (R. id. iv_icon_home);}/*** Click Event of activity response */@ Overridepublic void onClick (View v) {switch (v. getId () {case R. id. iv_icon_menu: if (isLevel3In) {// if level3 is displayed, let it go out to AnimationUtils. startAnimationOut (level3); isLevel3In = false;} else {// If level3 is not displayed, set it to AnimationUtils. startAnimationIn (level3); isLevel3In = true;} break; case R. id. iv_icon_home: if (isLevel2In) {// if level2 is in the display status of AnimationUtils. startAnimationOut (level2, 200); isLevel2In = false;} else {AnimationUtils. startAnimationIn (level2); isLevel2In = true;} if (isLevel3In) {AnimationUtils. startAnimationOut (level3); isLevel3In = false;} break; default: break; }}@ Overridepublic boolean onKeyDown (int keyCode, KeyEvent event) {if (keyCode = KeyEvent. KEYCODE_MENU) {// If the menu key is pressed: changeLevelState ();} return super. onKeyDown (keyCode, event);}/*** change the state of the three rings */private void changeLevelState () {if (isLevel1In) {AnimationUtils. startAnimationOut (level1, 400); isLevel1In = false;} else {AnimationUtils. startAnimationIn (level1); isLevel1In = true;} if (isLevel2In) {AnimationUtils. startAnimationOut (level2, 200); isLevel2In = false;} else {AnimationUtils. startAnimationIn (level2, 200); isLevel2In = true;} if (isLevel3In) {AnimationUtils. startAnimationOut (level3); isLevel3In = false ;}}}