1. 程式人生 > >Android “+”號發散選單動畫的實現--- pathMenu的實現思路

Android “+”號發散選單動畫的實現--- pathMenu的實現思路

一,引言

最近有需求,需要開發類似淘寶“問大家”進去中間那個“+”號Tab,點選散發出兩個選單按鈕的動畫,大概效果如下:
這裡寫圖片描述

然後點選“+”做發散動畫,效果大概如下

這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述

對於這樣子的動效是很多主流app都在做的,那麼我們應該怎麼做呢?

二,那麼怎麼實現這個動畫呢

下面讓我來講講要怎麼實現這樣子的pathMenu動畫
先借助前輩的一張圖來講講扇形原理:
這裡寫圖片描述

這款扇形選單實現的也是非常的好,提供半徑 radius 設定和 位置 position設定
其實說白了就是定好相隔兩個選單之間的夾角以及選單運動到的高度。
回到原點,我們上面的效果圖怎麼實現,下面看程式碼,都有註釋:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:zhy="http://schemas.android.com/apk/res-auto">
    <ImageView
        android:id="@+id/iv_icon3"
        android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_marginBottom="20dp" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:alpha="0" android:src="@drawable/a3" />
<ImageView android:id="@+id/iv_icon4" android:layout_width
="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dp" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:alpha="0" android:src="@drawable/a4" />
<ImageView android:id="@+id/iv_icon6" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/stay" android:layout_marginBottom="20dp" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" /> </RelativeLayout>

即想把三張圖片疊加在一起

package demo.wuchunmei.com.pathmenudemo;

import android.app.Activity;

import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.annotation.TargetApi;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.view.animation.BounceInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.PathInterpolator;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends Activity {
    private ImageView mIvIcon1;
    private ImageView mIvIcon2;
    private ImageView mIvBtn;
    private boolean mIsOpen = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        initView();
    }

    /**
     * 初始化檢視
     */
    private void initView() {
        setContentView(R.layout.activity_main);
        mIvIcon1 = (ImageView) findViewById(R.id.iv_icon3);
        mIvIcon2 = (ImageView) findViewById(R.id.iv_icon4);
        mIvBtn = (ImageView) findViewById(R.id.iv_icon6);
        mIvBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mIsOpen) {
                    showIcon();
                    mIsOpen = false;
                } else {
                    closeIcon();
                    mIsOpen = true;
                }
            }
        });
    }


    /**
     * 動畫實現,因為都有角度,所有,要有三角函式計算
     * 使圖示位移距離相等,實現扇形效果
     */
     private void showIcon() {
        //設定動畫時間
        int duration = 600;
        //動畫距離,螢幕寬度的30%
        float distance = getScreenWidth()*0.3f;
        //相鄰ImageView運動角度式22.5度
//        float angle1 = (float)(22.5f*Math.PI/180);
        float angle2 = (float)(135f*Math.PI/180);
        float angle3 = (float)(45.5f*Math.PI/180);

         //icon1
//         PropertyValuesHolder p31 = PropertyValuesHolder.ofFloat("TranslationX", 0f, (float) (distance * Math.cos(angle2)));
//         PropertyValuesHolder p32 = PropertyValuesHolder.ofFloat("TranslationY", 0f, -(float) (distance * Math.sin(angle2)));
//         //icon2
//         PropertyValuesHolder p41 = PropertyValuesHolder.ofFloat("TranslationX", 0f, (float) (distance * Math.cos(angle3)));
//         PropertyValuesHolder p42 = PropertyValuesHolder.ofFloat("TranslationY", 0f, -(float) (distance * Math.sin(angle3)));
//         PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha",0f,1f);
//         PropertyValuesHolder rota = PropertyValuesHolder.ofFloat("rotation", 0f, 45f);
//         PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1f, 0.4f);
//         PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1f, 0.4f);
//         ObjectAnimator animator3 = ObjectAnimator.ofPropertyValuesHolder(mIvIcon1, alpha, p31, p32);
//         ObjectAnimator animator4 = ObjectAnimator.ofPropertyValuesHolder(mIvIcon2, alpha, p41, p42);
//         ObjectAnimator animator6 = ObjectAnimator.ofPropertyValuesHolder(mIvBtn, rota, scaleX, scaleY);
//         AnimatorSet animatorSet = new AnimatorSet();
//         animatorSet.setDuration(duration);
//         animatorSet.setInterpolator(getInterpolator(0.2f, 1f, 0.2f, 1f));
//         animatorSet.playTogether(animator6, animator3, animator4);
//         animatorSet.start();
         Interpolator interpolator = getInterpolator(0.2f, 1f, 0.2f, 1f);
         float translationX_icon1 = (float) (distance * Math.cos(angle2));
         float translationY_icon1 = -(float) (distance * Math.sin(angle2));
         float translationX_icon2 = (float) (distance * Math.cos(angle3));
         float translationY_icon2 = -(float) (distance * Math.sin(angle3));
         mIvBtn.animate().rotation(45f).scaleX(0.4f).scaleY(0.4f).setDuration(duration).setInterpolator(interpolator);
         mIvIcon1.animate().alpha(1).translationX(translationX_icon1).translationY(translationY_icon1)
                 .setDuration(duration).setInterpolator(interpolator);
         mIvIcon2.animate().alpha(1).translationX(translationX_icon2).translationY(translationY_icon2)
                 .setDuration(duration).setInterpolator(interpolator);
    }


    private void closeIcon() {

        //設定動畫時間
        int duration = 600;
        //動畫距離,螢幕寬度的60%
        float distance = getScreenWidth()*0.3f;
        //相鄰ImageView運動角度式22.5度
//        float angle1 = (float)(22.5f*Math.PI/180);
        float angle2 = (float)(135f*Math.PI/180);
        float angle3 = (float)(45.5f*Math.PI/180);

        //icon1
//        PropertyValuesHolder p31 = PropertyValuesHolder.ofFloat("TranslationX", (float) (distance * Math.cos(angle2)),0f);
//        PropertyValuesHolder p32 = PropertyValuesHolder.ofFloat("TranslationY",-(float) (distance * Math.sin(angle2)), 0f);
//        //icon2
//        PropertyValuesHolder p41 = PropertyValuesHolder.ofFloat("TranslationX",(float) (distance * Math.cos(angle3)), 0f);
//        PropertyValuesHolder p42 = PropertyValuesHolder.ofFloat("TranslationY",  -(float) (distance * Math.sin(angle3)),0f);
//        PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha",1f,0f);
//        PropertyValuesHolder rota = PropertyValuesHolder.ofFloat("rotation",45f, 0f);
//        PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX",0.4f, 1f);
//        PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 0.4f,1f);
//        ObjectAnimator animator3 = ObjectAnimator.ofPropertyValuesHolder(mIvIcon1, alpha, p31, p32);
//        ObjectAnimator animator4 = ObjectAnimator.ofPropertyValuesHolder(mIvIcon2, alpha, p41, p42);
//        ObjectAnimator animator6 = ObjectAnimator.ofPropertyValuesHolder(mIvBtn, rota, scaleX, scaleY);
//
//        AnimatorSet animatorSet = new AnimatorSet();
//        animatorSet.setDuration(duration);
//        animatorSet.setInterpolator(getInterpolator(0.33f,0f,0.12f,1f));
//        animatorSet.playTogether(animator6,animator3,animator4);
//        animatorSet.start();

        Interpolator interpolator = getInterpolator(0.2f, 1f, 0.2f, 1f);
        mIvBtn.animate().rotation(0f).scaleX(1f).scaleY(1f).setDuration(duration).setInterpolator(interpolator);
        mIvIcon1.animate().alpha(0).translationX(0).translationY(0).setDuration(duration).setInterpolator(interpolator);
        mIvIcon2.animate().alpha(0).translationX(0).translationY(0).setDuration(duration).setInterpolator(interpolator);
    }

    /**
     * 豎屏時獲取螢幕寬度,橫屏時,獲取高度
     * @return
     */
    public int getScreenWidth(){
        DisplayMetrics outMetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(outMetrics);
        int x = outMetrics.widthPixels;
        int y = outMetrics.heightPixels;
        return x>y?y:x;
    }

    /**
     * 自定義動畫差值器
     * @param x1
     * @param x2
     * @param y1
     * @param y2
     * @return
     */
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private Interpolator getInterpolator(float x1, float x2, float y1, float y2) {
        final int version = Build.VERSION.SDK_INT;
        if (version >= 21) {
            return new PathInterpolator(x1, x2, y1, y2);
        } else {
            return new LinearInterpolator();
        }
    }
}