自定義控件——旋轉菜單

1. 效果圖

在這裏插入圖片描述

2. 佈局文件
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!--這裏有個坑:由於View的層級關係,這樣要先放三級菜單、再放二級菜單、最後放一級菜單,-->
    <!--否則就會出現一級菜單和二級菜單的點擊事件被蓋住了-->
    <!--三級菜單-->
    <RelativeLayout
        android:id="@+id/rl_level3"
        android:layout_alignParentBottom="true"
        android:layout_centerInParent="true"
        android:background="@mipmap/level3"
        android:layout_width="250dp"
        android:layout_height="125dp">

        <ImageView
            android:id="@+id/iv_channel1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/channel1"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="16dp"
            android:layout_marginLeft="16dp"/>

        <ImageView
            android:id="@+id/iv_channel2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/channel2"
            android:layout_toRightOf="@+id/iv_channel1"
            android:layout_above="@+id/iv_channel1"
            android:layout_marginBottom="20dp"
            android:layout_marginLeft="5dp"
            />

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/channel3"
            android:layout_toRightOf="@+id/iv_channel2"
            android:layout_above="@+id/iv_channel2"
            android:layout_marginBottom="3dp"
            android:layout_marginLeft="5dp"
            />

        <ImageView
            android:id="@+id/iv_channel4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/channel4"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="6dp"/>

        <ImageView
            android:id="@+id/iv_channel5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/channel5"
            android:layout_toLeftOf="@+id/iv_channel6"
            android:layout_above="@+id/iv_channel6"
            android:layout_marginBottom="3dp"
            android:layout_marginLeft="5dp"/>

        <ImageView
            android:id="@+id/iv_channel6"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/channel2"
            android:layout_toLeftOf="@+id/iv_channel7"
            android:layout_above="@+id/iv_channel1"
            android:layout_marginBottom="20dp"
            android:layout_marginLeft="5dp"
            />

        <ImageView
            android:id="@+id/iv_channel7"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/channel7"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_marginBottom="16dp"
            android:layout_marginRight="16dp"/>

    </RelativeLayout>

    <!--二級菜單-->
    <RelativeLayout
        android:id="@+id/rl_level2"
        android:background="@mipmap/level2"
        android:layout_width="150dp"
        android:layout_height="75dp"
        android:layout_alignParentBottom="true"
        android:layout_centerInParent="true">

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/icon_search"
            android:layout_alignParentBottom="true"
            android:layout_marginLeft="16dp"
            android:layout_marginBottom="16dp"/>

        <ImageView
            android:id="@+id/iv_menu"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/icon_menu"
            android:layout_alignParentTop="true"
            android:layout_centerInParent="true"
            android:layout_marginTop="6dp"/>

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/icon_myyouku"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_marginRight="16dp"
            android:layout_marginBottom="16dp"/>

    </RelativeLayout>

    <!--一級菜單-->
    <RelativeLayout
        android:id="@+id/rl_level1"
        android:layout_alignParentBottom="true"
        android:layout_centerInParent="true"
        android:layout_width="80dp"
        android:layout_height="40dp"
        android:background="@mipmap/level1">
        <ImageView
            android:id="@+id/iv_home"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_centerInParent="true"
            android:layout_marginBottom="6dp"
            android:background="@mipmap/icon_home"/>
    </RelativeLayout>

</RelativeLayout>
3. 動畫控制邏輯
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private ImageView mIv_home;
    private ImageView mIv_menu;
    private RelativeLayout mRl_level2;
    private RelativeLayout mRl_level3;
    boolean isMenu2Display = true;//記錄二級菜單是否顯示
    boolean isMenu3Display = true;//記錄三級菜單是否顯示

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        mIv_home = (ImageView) findViewById(R.id.iv_home);
        mIv_menu = (ImageView) findViewById(R.id.iv_menu);
        mRl_level2 = (RelativeLayout) findViewById(R.id.rl_level2);
        mRl_level3 = (RelativeLayout) findViewById(R.id.rl_level3);

        mIv_home.setOnClickListener(this);
        mIv_menu.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.iv_home:
                //判斷當前是否有動畫正在執行,如果有就返回
                if (AnimUtil.animationNum > 0) {
                    return;
                }

                //點擊home按鈕,隱藏或顯示三級菜單
                int offset = 0;
                if (isMenu3Display) {
                    AnimUtil.hideAnim(mRl_level3);
                    isMenu3Display = false;
                    offset += 200;
                }
                //點擊home按鈕,隱藏或顯示二級菜單
                if (isMenu2Display) {
                    AnimUtil.hideAnim(mRl_level2,offset);
                } else {
                    AnimUtil.showAnim(mRl_level2);
                }
                isMenu2Display = !isMenu2Display;
                break;
            case R.id.iv_menu:
                //判斷當前是否有動畫正在執行,如果有就返回
                if (AnimUtil.animationNum > 0) {
                    return;
                }

                //點擊menu按鈕,隱藏或顯示三級菜單
                if (isMenu3Display) {
                    AnimUtil.hideAnim(mRl_level3);
                } else {
                    AnimUtil.showAnim(mRl_level3);
                }
                isMenu3Display = !isMenu3Display;
                break;
        }
    }
}
4. 動畫工具類及bug分析
public class AnimUtil {

    /**
     * bug2:如果當前動畫沒有結束立馬有點擊了,那麼就會出現動畫的跳轉
     * 解決方案:使用動畫監聽去控制
     */
    private static MyAnimationListener mAnimationListener = new MyAnimationListener();
    public static int animationNum = 0;//記錄當前有多少動畫在執行

    /**
     * 隱藏動畫
     * @param container 傳入的ViewGroup
     *  隱藏動畫分析:
     *  開始角度:0 ;結束角度 180;旋轉中心點:(寬度的一般,整個高度)
     */
    public static void hideAnim(ViewGroup container) {
        hideAnim(container,0);
    }

    /**
     * 隱藏動畫
     * @param container 傳入的ViewGroup
     * @param offset 動畫延遲執行的時間
     *  隱藏動畫分析:
     *  開始角度:0 ;結束角度 180;旋轉中心點:(寬度的一般,整個高度)
     */
    public static void hideAnim(ViewGroup container,int offset) {
        /**
         * bug1:補間動畫沒有改變實際的位置,點擊事件還留在原地
         * 解決方案:隱藏動畫時將當前容器中的控件全部設置爲不可點擊
         */
        for (int i = 0; i < container.getChildCount(); i++) {
            View childView = container.getChildAt(i);
            childView.setEnabled(false);//設置控件不可用,相當於點擊事件取消了
        }
        RotateAnimation rotateAnimation = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 1.0f);
        rotateAnimation.setDuration(500);//設置動畫執行的時間
        rotateAnimation.setFillAfter(true);//讓視圖執行完補間動畫之後停留在結束的位置
        rotateAnimation.setStartOffset(offset);
        rotateAnimation.setAnimationListener(mAnimationListener);
        container.startAnimation(rotateAnimation);
    }

    /**
     * 顯示動畫
     * @param container 傳入的ViewGroup
     *  顯示動畫分析:
     *  開始角度:-180 ;結束角度 0;旋轉中心點:(寬度的一般,整個高度)
     */
    public static void showAnim(ViewGroup container) {
        /**
         * bug1:補間動畫沒有改變實際的位置,點擊事件還留在原地
         * 解決方案:顯示動畫時將當前容器中的控件全部設置爲可點擊
         */
        for (int i = 0; i < container.getChildCount(); i++) {
            View childView = container.getChildAt(i);
            childView.setEnabled(true);
        }
        RotateAnimation rotateAnimation = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 1.0f);
        rotateAnimation.setDuration(500);//設置動畫執行的時間
        rotateAnimation.setFillAfter(true);//讓視圖執行完補間動畫之後停留在結束的位置
        rotateAnimation.setAnimationListener(mAnimationListener);
        container.startAnimation(rotateAnimation);
    }

    private static class MyAnimationListener implements Animation.AnimationListener {
        @Override
        public void onAnimationStart(Animation animation) {
            animationNum++;
        }

        @Override
        public void onAnimationEnd(Animation animation) {
            animationNum--;
        }

        @Override
        public void onAnimationRepeat(Animation animation) {

        }
    }
}
非常感謝您的耐心閱讀,希望我的文章對您有幫助。歡迎點評、轉發或分享給您的朋友或技術羣。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章