Android自訂控制項教程一:Android如何?老版優酷用戶端三級環形菜單,
轉載請附上本文連結:http://blog.csdn.net/cyp331203/article/details/40423727
先來看看效果:
一眼看上去好像還挺炫的,感覺比較複雜。。。實際上並不難,下面我們來看看如何?:
基本素材就是下面三個:
我們先來看看布局檔案怎麼寫,實際上這裡這三張圖片都差不多,我們這裡使用RelativeLayout,方便後續小表徵圖的加入,基本就是centerInParent和aliagnParentBottom,只是外圈小表徵圖的安排要稍微注意一下,這裡我們左半邊表徵圖以最左邊的一個表徵圖為基準,右半邊的表徵圖以最右邊的一個表徵圖為基準,在這裡分別是iv_channel1和iv_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>
布局完之後的效果:
之後我們就可以開始著手這個怎麼實現,我們的基本想法是(小房子表徵圖所在的為level1,第二圈灰色的部分為level2,最外圈為level3):
1、點擊小房子表徵圖,如果level2和level3都處於顯示狀態,則將這兩層都隱藏,如果這兩層都不存在,則只將level2顯示出來;如果只有level2顯示著,那麼將level2隱藏
2、點擊levle2的”三“字表徵圖,則實現隱藏和顯示level3組件
3、點擊手機的menu鍵,則實現如果level1,2,3都處於顯示狀態,則將三者都隱藏,如果只有level1、level2顯示,則將level1、2隱藏,如果只有level1顯示,則將level1隱藏;如果沒有任何level顯示著,則將level1和level2顯示出來
4、上面的顯示和隱藏的過程,都使用動畫來實現
基本邏輯關係已經理清楚了,那麼現在的問題就在於這個Animation如何寫;顯然我們這裡需要用到一個RotateAnimation旋轉動畫,由於這裡牽涉到旋出和旋入的效果,我們必須要清楚這個動畫的角度是如何定的,比如從0~180是旋入還是旋出效果?
經過實驗,我們發現,RotateAnimation的角度如下,我們可以發現,它的角度定義是按照順時針增長的:
那麼按照這個角度來看,我們如果想要組件順時針旋入,同時順時針旋出的話,角度是要如何確定的呢?
從可以比較容易看出來,順時針旋出的話,角度是從0~180度,那麼旋入呢?是不是從180~0度?,實際上這裡旋入應該是180~360度。
在角度確定好之後呢,我們可以來著手實現動畫效果,這裡由於三個組件level1、level2、level3的動畫都是一致的,所以這裡選擇使用一個工具類,來實現幾個靜態方法,來定義動畫,達到複用的效果:
工具類如下:
package com.alexchen.youkumenuexercise.utils;import android.view.View;import android.view.animation.RotateAnimation;public class AnimationUtils {//旋出的動畫,無延遲時間public static void startAnimationOut(View view) {startAnimationOut(view, 0);}//旋入的動畫,無延遲時間public static void startAnimationIn(View view) {startAnimationIn(view, 0);}//旋出的動畫//delay為動畫延遲的時間,單位是毫秒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);}//旋入的動畫//delay為動畫延遲的時間,單位是毫秒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);}}
其中設定了兩個能夠延時開啟動畫的方法,為的是讓三個組件進出的時候能夠體現出層次感,讓使用者體驗更好。
最後是Activity中的代碼,這裡沒有做任何生命週期相關的處理,只是簡單的實現功能:
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.RelativeLayout;public class MainActivity extends Activity implements OnClickListener {private RelativeLayout level1;private RelativeLayout level2;private RelativeLayout level3;private ImageView iv_icon_menu;private ImageView iv_icon_home;/** * 表示level3是否是現狀狀態,預設為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();setOnclickListenersForViews();}/** * 設定views的監聽事件 */private void setOnclickListenersForViews() {iv_icon_home.setOnClickListener(this);iv_icon_menu.setOnClickListener(this);}/** * 初始化需要的view組件 */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);}/** * activity響應的點擊事件 */@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.iv_icon_menu:if (isLevel3In) {// 如果level3是顯示的,那麼就讓出去AnimationUtils.startAnimationOut(level3);isLevel3In = false;} else {// 如果level3是不顯示的,那麼讓其進入AnimationUtils.startAnimationIn(level3);isLevel3In = true;}break;case R.id.iv_icon_home:if (isLevel2In) {// 如果level2是顯示狀態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) {// 如果是menu鍵按下的話:changeLevelState();}return super.onKeyDown(keyCode, event);}/** * 改變三個圓環的狀態 */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;}}}