自定義View實例(一)仿優酷菜單

一、自定義view的幾種方式:

  • 1.通過Android已有的控件實現自定義效果
  • 2.通過繼承View類實現自定義View
  • 3.通過繼承ViewGroup類實現相應效果

二、仿優酷菜單

通過系統控件組合使用,實現仿優酷菜單的效果,效果圖:
在這裏插入圖片描述
基本實現思路:
系統基礎控件佈局+view旋轉動畫,實現起來也是很簡單,佈局文件如下,每一級的菜單用RelativeLayout來寫是爲了方便給菜單中添加按鈕

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:id="@+id/level_1"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:background="@drawable/level1"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true">
        
        <ImageView
            android:id="@+id/ic_home"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/icon_home"
            android:layout_centerInParent="true"/>
        
    </RelativeLayout>
    
    <RelativeLayout
        android:id="@+id/level_2"
        android:layout_width="180dp"
        android:layout_height="90dp"
        android:background="@drawable/level2"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true">

        <ImageView
            android:id="@+id/ic_search"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/icon_search"
            android:layout_alignParentBottom="true"
            android:layout_margin="10dp"/>
        <ImageView
            android:id="@+id/ic_menu"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/icon_menu"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="5dp"/>
        <ImageView
            android:id="@+id/ic_myyouku"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/icon_myyouku"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_margin="10dp"/>
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/level_3"
        android:layout_width="280dp"
        android:layout_height="140dp"
        android:background="@drawable/level3"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true">

        <ImageView
            android:id="@+id/ic_channerl1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/channel1"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="10dp"
            android:layout_marginLeft="10dp"/>
        <ImageView
            android:id="@+id/ic_channerl2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/channel2"
            android:layout_above="@id/ic_channerl1"
            android:layout_alignLeft="@id/ic_channerl1"
            android:layout_marginBottom="10dp"
            android:layout_marginLeft="20dp"/>
        <ImageView
            android:id="@+id/ic_channerl3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/channel3"
            android:layout_above="@id/ic_channerl2"
            android:layout_alignLeft="@id/ic_channerl2"
            android:layout_marginLeft="30dp"
            android:layout_marginBottom="6dp"
            />
        <ImageView
            android:id="@+id/ic_channerl4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/channel4"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="5dp"/>
        <ImageView
            android:id="@+id/ic_channerl5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/channel5"
            android:layout_above="@id/ic_channerl6"
            android:layout_alignRight="@id/ic_channerl6"
            android:layout_marginBottom="6dp"
            android:layout_marginRight="30dp"
            />
        <ImageView
            android:id="@+id/ic_channerl6"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/channel6"
            android:layout_above="@id/ic_channerl7"
            android:layout_alignRight="@id/ic_channerl7"
            android:layout_marginBottom="6dp"
            android:layout_marginRight="20dp"
            />
        <ImageView
            android:id="@+id/ic_channerl7"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/channel7"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_marginBottom="10dp"
            android:layout_marginRight="10dp"/>
    </RelativeLayout>
</RelativeLayout>

view動畫處理:
用旋轉動畫RotateAnimation來完成菜單的隱藏和顯示,默認的旋轉點是view的左上角,我們需要的是以下圖所示的點作爲中心點,水平右方向爲0°,順時針旋轉爲正方向,則如下圖所示:
在這裏插入圖片描述
動畫工具類:

class MyUtils {
    /*
        默認圓心是view的左上角
        水平向右爲0°
        順時針旋轉度數增加
     */

    public static void startAnimOut(RelativeLayout view) {
       startAnimOut(view,0);
    }

    public static void startAnimIn(RelativeLayout view) {
        startAnimIn(view,0);
    }

    public static void startAnimIn(RelativeLayout view, long offset) {
        //順時針進入動畫:從180°到360°
        RotateAnimation animation = new RotateAnimation(180, 360,
                view.getWidth() / 2, view.getHeight());
        animation.setDuration(500);
        //動畫完成後保持最後的狀態
        animation.setFillAfter(true);
        animation.setStartOffset(offset);
        view.startAnimation(animation);
    }

    /*
        延時執行動畫
     */
    public static void startAnimOut(RelativeLayout view, long offset) {
        //順時針離開動畫:從0°到180°
        RotateAnimation animation = new RotateAnimation(0, 180,
                view.getWidth() / 2, view.getHeight());
        animation.setDuration(500);
        //動畫完成後保持最後的狀態
        animation.setFillAfter(true);
        animation.setStartOffset(offset);
        view.startAnimation(animation);
    }
}

activity中初始化佈局然後調用,完整代碼:

package com.car.customview;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.KeyEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;

/**
 * 
 */

public class YouKuMenu extends AppCompatActivity implements View.OnClickListener{
    private ImageView icon_home;
    private ImageView icon_menu;
    private RelativeLayout level1;
    private RelativeLayout level2;
    private RelativeLayout level3;
    private boolean isLevel3Show = true;
    private boolean isLevel2Show = true;
    private boolean isLevel1Show = true;

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

    private void initView() {
        icon_home = findViewById(R.id.ic_home);
        icon_menu = findViewById(R.id.ic_menu);
        level1 = findViewById(R.id.level_1);
        level2 = findViewById(R.id.level_2);
        level3 = findViewById(R.id.level_3);
        icon_menu.setOnClickListener(this);
        icon_home.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.ic_menu:
                if (isLevel3Show){
                    //隱藏第三級菜單
                    MyUtils.startAnimOut(level3);
                }else {
                    //顯示第三級菜單
                    MyUtils.startAnimIn(level3);
                }
                isLevel3Show = !isLevel3Show;
                break;
            case R.id.ic_home:
                //如果二級菜單顯示狀態,隱藏二三級菜單
                //如果二級菜單隱藏,顯示二級菜單
                if (isLevel2Show){
                    MyUtils.startAnimOut(level2);
                    isLevel2Show = false;
                    if (isLevel3Show){
                        MyUtils.startAnimOut(level3,300);
                        isLevel3Show = false;
                    }
                }else {
                    MyUtils.startAnimIn(level2);
                    isLevel2Show = true;
                }

        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK){
            changeLevel1State();
        }
        return super.onKeyDown(keyCode, event);
    }

    private void changeLevel1State(){

        if (isLevel1Show){
            MyUtils.startAnimOut(level1);
            isLevel1Show = false;
            if (isLevel2Show){
                MyUtils.startAnimOut(level2,100);
                isLevel2Show = false;
                if (isLevel3Show){
                    MyUtils.startAnimOut(level3,200);
                    isLevel3Show = false;
                }
            }
        }else {
            MyUtils.startAnimIn(level1);
            isLevel1Show = true;
            MyUtils.startAnimIn(level2,200);
            isLevel2Show = true;
        }

    }
}

基本已經實現了優酷菜單這個自定義view,其中還有一些細節的問題,比如雙擊home按鈕時,上一個動畫還沒執行完成;因爲上述動畫使用的是補間動畫,所以會導致二級慘淡隱藏後,再點擊二級參帶的menu所處位置,會彈出三級菜單,這是因爲補間動畫並不會改變view的屬性。

只需要修改工具類裏view旋轉方法,用屬性動畫替換補間動畫就不會有這個問題了

package com.car.customview;

import android.animation.ObjectAnimator;
import android.widget.RelativeLayout;

class MyUtils {
    /*
        默認圓心是view的左上角
        水平向右爲0°
        順時針旋轉度數增加
     */

    public static void startAnimOut(RelativeLayout view) {
       startAnimOut(view,0);
    }

    public static void startAnimIn(RelativeLayout view) {
        startAnimIn(view,0);
    }

    public static void startAnimIn(RelativeLayout view, long offset) {

        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, "rotation",
                180,360);
        view.setPivotX(view.getWidth() / 2);//設置將要旋轉的view的起始點
        view.setPivotY(view.getHeight());
        objectAnimator.setRepeatCount(0);
        objectAnimator.setDuration(500);
        objectAnimator.setStartDelay(offset);
        objectAnimator.start();
        //順時針進入動畫:從180°到360°
        /*
        RotateAnimation animation = new RotateAnimation(180, 360,
                view.getWidth() / 2, view.getHeight());
        animation.setDuration(500);
        //動畫完成後保持最後的狀態
        animation.setFillAfter(true);
        animation.setStartOffset(offset);
        view.startAnimation(animation);
        */
    }

    /*
        延時執行動畫
     */
    public static void startAnimOut(RelativeLayout view, long offset) {

        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, "rotation",
                0,180);
        view.setPivotX(view.getWidth() / 2);
        view.setPivotY(view.getHeight());
        objectAnimator.setRepeatCount(0);
        objectAnimator.setDuration(500);
        objectAnimator.setStartDelay(offset);
        objectAnimator.start();

        //順時針離開動畫:從0°到180°
        /*
        RotateAnimation animation = new RotateAnimation(0, 180,
                view.getWidth() / 2, view.getHeight());
        animation.setDuration(500);
        //動畫完成後保持最後的狀態
        animation.setFillAfter(true);
        animation.setStartOffset(offset);
        view.startAnimation(animation);
        */
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章