Android 屬性動畫

来源:https://www.cnblogs.com/lanjiabin/archive/2020/05/05/12831204.html
-Advertisement-
Play Games

一、ValueAnimator ValueAnimator是值的變動,可以控制控制項的一些值,從而達到變化動畫的效果。 監聽器三個 移除監聽器 當移除監聽器時,正在執行的動畫不會受到影響,但是之後再執行動畫,動畫的監聽效果將不會再呈現。 不常用函數 常用函數 效果: 二、自定義插值器 1.插值器的理解 ...


一、ValueAnimator

ValueAnimator是值的變動,可以控制控制項的一些值,從而達到變化動畫的效果。


    public void doAnimation() {
//        final ValueAnimator valueAnimatorInt = ValueAnimator.ofInt(0,400,100,555,250);
        //輸入需要變化的值,是個變化的數組,可以有int類型和float類型
        final ValueAnimator valueAnimator = ValueAnimator.ofFloat(0.0f,400.0f,100.0f,555.0f,250.0f);
        valueAnimator.setDuration(9000);//動畫持續時間
        //監聽動畫的變化時間,在變化中對控制項進行操作,也可以通過handle來做一些有趣的事情
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //獲得變化的值
                Float curValueFloat = (Float) valueAnimator.getAnimatedValue();
                //設置為整型
                int curValue = curValueFloat.intValue();
                //改變控制項的位置,layout對應的是控制項的位置
                valueTV.layout(curValue, curValue, curValue + imageView.getWidth(), curValue + imageView.getHeight());
            }
        });
        valueAnimator.start();
    }

監聽器三個
image.png


        //監聽1
        valueAnimator.addPauseListener(new Animator.AnimatorPauseListener() {
            @Override
            public void onAnimationPause(Animator animation) {
                //暫停
            }

            @Override
            public void onAnimationResume(Animator animation) {
                //運行
            }
        });

        //監聽2
        valueAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
                //開始
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                //結束
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                //取消
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
                //迴圈一次
            }
        });

        //監聽3
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //數值更新
            }
        });

移除監聽器
當移除監聽器時,正在執行的動畫不會受到影響,但是之後再執行動畫,動畫的監聽效果將不會再呈現。

/** 
 * 移除AnimatorUpdateListener 
 */  
void removeUpdateListener(AnimatorUpdateListener listener);  
void removeAllUpdateListeners();  

 /** 
  * 移除AnimatorListener 
  */  
void removeListener(AnimatorListener listener);  
void removeAllListeners();

不常用函數

/**
 * 延時多久時間開始,單位是毫秒
 */
public void setStartDelay(long startDelay)
    
/**
 * 完全克隆一個ValueAnimator實例,包括它所有的設置以及所有對監聽器代碼的處理
 */
public ValueAnimator clone()

常用函數

/**
 * 設置動畫時長,單位是毫秒
 */
ValueAnimator setDuration(long duration)
    
/**
 * 獲取ValueAnimator在運動時,當前運動點的值
 */
Object getAnimatedValue();

/**
 * 開始動畫
 */
void start()
    
/**
 * 設置迴圈次數,設置為INFINITE表示無限迴圈
 */
void setRepeatCount(int value)
    
/**
 * 設置迴圈模式
 * value取值有RESTART,REVERSE,
 */
void setRepeatMode(int value)
    
/**
 * 取消動畫
 */
void cancel()

效果:

屬性動畫.gif

二、自定義插值器

1.插值器的理解

首先看看自動自定義的插值器
勻速插值器:
看看繼承關係:LinearInterpolator---繼承--->BaseInterpolator---繼承--->Interpolator---實現-->TimeInterpolator
最後看看TimeInterpolator都寫了啥:
只定義了一個getInterpolation(float input)方法。

package android.animation;

/**
 * A time interpolator defines the rate of change of an animation. This allows animations
 * to have non-linear motion, such as acceleration and deceleration.
 */
public interface TimeInterpolator {

    /**
     * Maps a value representing the elapsed fraction of an animation to a value that represents
     * the interpolated fraction. This interpolated value is then multiplied by the change in
     * value of an animation to derive the animated value at the current elapsed animation time.
     *
     * @param input A value between 0 and 1.0 indicating our current point
     *        in the animation where 0 represents the start and 1.0 represents
     *        the end
     * @return The interpolation value. This value can be more than 1.0 for
     *         interpolators which overshoot their targets, or less than 0 for
     *         interpolators that undershoot their targets.
     */
    float getInterpolation(float input);
}

LinearInterpolator的定義


public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {

    public LinearInterpolator() {
    }

    public LinearInterpolator(Context context, AttributeSet attrs) {
    }

    public float getInterpolation(float input) {
        return input; //數值進度與時間同步
    }

    /** @hide */
    @Override
    public long createNativeInterpolator() {
        return NativeInterpolatorFactoryHelper.createLinearInterpolator();
    }
}

AccelerateInterpolator開始慢,後面一直加速插值器,也叫冪函數插值器,核心方法

 public float getInterpolation(float input) {
        if (mFactor == 1.0f) {
            return input * input;
        } else {
            //返回的是時間的次冪數,比如 input=3,mDoubleFactor=2,
            //那麼返回的就是,3的2次方,就是9
            //所以會按照幾何倍增,這是一個冪函數
            return (float)Math.pow(input, mDoubleFactor); 
        }
    }

所有的速度都離不開這個方法:getInterpolation

而最為關鍵的就是input這個數字。以下是經典解釋:

input參數代表了當前動畫的進度,而返回值則代表了當前動畫的數值進度。

上面的勻速,返回的就是時間的值,所以,動畫進度和動畫的數值持平。
冪函數的時候,隨著動畫進度的增加,動畫的數值進度也就越來越大,從而一直加速。

input的取值範圍是0~1之間,返回值可以超過1,也可以小於0,超過1表示已經超過目標位置,小於0表示遠離初始位置。

簡單的公式就是

y= -> x

y代表返回的值,也就是動畫需要的數值進度,x代表時間進度,->則是通過一些數學手段,來得到想要的y值。

  • 當一些動畫定義這些插值器的時候,返回的數值進度越大,速度越快。比如你在勻速運動的時候,時間進度是0.5s,數值進度也是0.5,那就是勻速運動。

2.定義一個簡單的插值器

我們用數學中的定義來做一個插值器。
y=1-x
把進度反過來,當進度傳入0的時候,數值進度已經在目標位置了。當傳入1時,數值則在剛開始的位置。

  class FiveInterpolator implements TimeInterpolator {

        @Override
        public float getInterpolation(float input) {
            return 1-input;
        }
    }

valueAnimator.setInterpolator(``new ``FiveInterpolator())``;
一個簡單的自定義插值器就完成了。

三、Evaluator

  • Evaluator是數值轉換器,就是將數值進度轉化為具體的數值。
  • 就是0~400的數值變換,當數值進度是50%的時候,那通過Evaluator來轉換,就變成了200
  • oflnt()函 數對應 Evauator 類名為 IntEvauaor ,而 ofFloat()函數對應的 Evauator 類名為 FloatEvaluator

自定義數值轉換器:

 	//自定義數值轉換器
    class MyFloatEvaluator implements TypeEvaluator<Float>{

        /**
         * @param fraction 代表數值進度的值,就是上面getInterpolation()的返回值
         * @param startValue  代表ofFloat(Float startValue,Float endValue)
         * @param endValue
         * */
        @Override
        public Float evaluate(float fraction, Float startValue, Float endValue) {
            //初始值
            Float startFloat=startValue;

            //當前值=初始值+總值*進度
            Float inputValue=startFloat+(endValue-startFloat)*fraction;
            return inputValue;
        }
    }

使用:

valueAnimator.setEvaluator(new MyFloatEvaluator());

所以可以通過插值器和數值轉化器來改變控制項的數值變化

valueAnimator.setInterpolator(new FiveInterpolator());
valueAnimator.setEvaluator(new MyFloatEvaluator());

四、ArgbEvaluator

ArgbEvaluator可以把顏色轉換過渡。
具體實現:

 //顏色的數值變換
    public void doColorAnimation(){
        ValueAnimator valueAnimator=ValueAnimator.ofInt(0xffffff00,0xff0000ff);
        valueAnimator.setEvaluator(new ArgbEvaluator());
        valueAnimator.setDuration(3000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int curValue=(int)animation.getAnimatedValue();
                valueTV.setBackgroundColor(curValue);
            }
        });
        valueAnimator.start();
    }

效果:

顏色變換.gif

顏色必須包含ARGB四個值。
image.png

五、ValueAnimation-ofObject

首先看看這個方法是如何傳值的。

public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) {
        ValueAnimator anim = new ValueAnimator();
        anim.setObjectValues(values);
        anim.setEvaluator(evaluator);
        return anim;
    }

TypeEvaluator evaluator需要傳入自定義的數值轉換器
Object... values 可變長參數

實例
實現一個字母從A到Z的過程

public void doObjectValue() {
        ValueAnimator valueAnimator = ValueAnimator.ofObject(new CharInterpolator(), new Character('A'), new Character('Z'));
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                char str = (char) animation.getAnimatedValue();
                valueTV.setText(String.valueOf(str));
            }
        });
        valueAnimator.setDuration(7000);
        valueAnimator.setInterpolator(new AccelerateInterpolator());
        valueAnimator.start();
    }

    class CharInterpolator implements TypeEvaluator<Character> {

        @Override
        public Character evaluate(float fraction, Character startValue, Character endValue) {
            int startInt = (int) startValue;  //ASCII轉換   A代表56 以此遞增
            int endInt = (int) endValue;
            int curInt = (int) (startInt + fraction * (endInt - startInt));
            char result = (char) curInt;
            return result;
        }
    }

效果:

A-Z的變換.gif

六、ObjectAnimator

ObjeceAnimation--繼承--->ValueAnimation
與控制項之間相關聯,從監聽動畫中解放出來。
先看看這個方法:

ObjectAnimator ofFloat(Object target, String propertyName, float... values)

具體使用

  public void doObjectAnimationByAlpha(){
        ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(valueTV,"alpha",1,0,1);
        objectAnimator.setDuration(6000);
        objectAnimator.start();
    }

Object target要控制的控制項
String propertyName要改變的動畫效果
float... values傳入的具體變化值
具體效果就是跟視圖動畫中設置的動畫是一樣的效果,透明度從1到0再到1.
“alpha”中,是對應view中的setAlpha()方法,後面的可變成參數就是可以傳入具體是變換數值。
看看view中有多少個set函數:

透明度:alpha

setAlpha(@FloatRange(from=0.0, to=1.0) float alpha)  //透明度

旋轉角度:rotation,rotationX,rotationY

setRotation(float rotation) //圍繞Z軸旋轉,Z軸指的是垂直屏幕的方向
setRotationX(float rotationX)  //圍繞X軸旋轉
setRotationY(float rotationY)  //圍繞Y軸旋轉

平移:translationX,translationY

setTranslationX(float translationX)   //X軸屏幕,右為正方向,當前控制項為原點
setTranslationY(float translationY)

縮放:scaleX,scaleY

setScaleX(float scaleX) //X軸縮放
setScaleY(float scaleY)

看看旋轉是三個效果:

 public void doObjectAnimationByAlpha(){
        ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(valueTV,"rotationY",360);
        objectAnimator.setDuration(6000);
        objectAnimator.start();
    }

Z軸:

Z軸旋轉.gif

X軸:

X軸旋轉.gif

Y軸:

Y軸旋轉.gif

七、自定義ObjectAnimator

因為ObjectAnimator是通過set來反射實現的,所以自己也可以通過這樣的操作來實現自己view的set函數,從而實現簡單的動畫效果。

1.自定義view的set函數

FallingBallImageView.java

public class FallingBallImageView extends ImageView {
    public FallingBallImageView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public void setFallingPos(Point pos){
        layout(pos.x,pos.y,pos.x+getWidth(),pos.y+getHeight());
    }

}

佈局使用

<com.lanjiabin.systemtest.anim.FallingBallImageView
                android:id="@+id/imageBall"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:layout_marginTop="30dp"
                android:background="@drawable/shape"
                android:layout_marginBottom="25dp" />

set函數的名字是setFallingPos,所以在傳遞反射函數名字的時候,應該是fallingPos或者FallingPos,必須是這兩個名字中其中一個的格式,否則就不會正確反射。參數類型是Point,所以使用函數是ofObject()

2.自定義Evaluator

 class DivEvaluator implements TypeEvaluator<Point> {
        Point point = new Point();

        @Override
        public Point evaluate(float fraction, Point startValue, Point endValue) {
            point.x = (int) (startValue.x + (endValue.x - startValue.x) * fraction);
            if (fraction * 2 <= 1) {
                point.y = (int) (startValue.y + (endValue.y - startValue.y) * fraction);
            } else {
                point.y = endValue.y;
            }
            return point;
        }
    }

3.實現最終反射調用

  public void doObjectAnimationByDiv() {
        ObjectAnimator objectAnimator=ObjectAnimator
                .ofObject(
                        ballImageView,  //自定義view的小球
                        "FallingPos",   //反射名字,FallingPos或者fallingPos都可以
                        new DivEvaluator(), //自定義轉換器
                        new Point(0,0),     //起始坐標
                        new Point(300,300)); //目標坐標
        objectAnimator.setDuration(4000);   //動畫時長
        objectAnimator.start();
    }

4.效果

自定義ObjectAnimation.gif

5.get函數

當我們在上述函數的時候,ofObject()傳的都是可變長的參數,也就是兩個參數以上,當我們只傳遞一個參數的時候,這個參數只是目標參數,沒有初始參數,系統就會預設調用系統自帶的get方法,來獲得初始值。當沒有這個get方法的時候,就會報錯,以至於崩潰。
所以想傳遞一個參數,就需要自定義get()方法,返回的,就是初始值。對應名字也和set的名字類似。
setFallingPos(Point pos)的名字就是getFallingPos(Point pos)

在自定義view中加入get方法:返回控制項的初始Point

 public Point getFallingPos() {
        int[] location = new int[2];
        this.getLocationOnScreen(location);
        return new Point(location[0], location[1]);
    }

八、AnimatorSet

1.AnimatorSet理解和使用

AnimatorSet組合動畫,對ValueAnimation和ObjectAnimation都有一樣的效果。
有兩個播放方法:只管播放的時間,不管動畫個體是如何操作的,不管動畫的執行時間,迴圈次數等。
playSequentially()
是順序播放,當前一個動畫播放完畢以後,才會執行下一個動畫。當前一個動畫是無限迴圈時,後一個動畫也就無法播放。有兩個構造方法。

playSequentially(Animator... items)
playSequentially(List<Animator> items)

playTogether()
是一起播放,同一個時間內,在列表中所有動畫同一時間啟動。

playTogether(Animator... items)
playTogether(Collection<Animator> items)

具體實例,有一個縮放動畫和位移動畫,分別實現同時播放和順序播放。

 public void doAnimationSet() {
        //縮放
        ObjectAnimator objectAnimatorScaleY = ObjectAnimator.ofFloat(ballImageView, "scaleY", 0.0f, 1.6f, 1.0f);

        //平移
        ObjectAnimator objectAnimatorTranslationX = ObjectAnimator.ofFloat(ballImageView, "translationX", 400);

        //組合動畫
        AnimatorSet animator = new AnimatorSet();

        //每個動畫的播放時間
        animator.setDuration(3000);

        //順序播放
        animator.playSequentially(objectAnimatorScaleY, objectAnimatorTranslationX);

        //一起播放
        animator.playTogether(objectAnimatorScaleY, objectAnimatorTranslationX);

        animator.start();
    }

同時播放:動畫效果同時體現出來,縮放和位移
組合動畫-同時播放.gif

順序播放:先縮放完畢再位移
組合動畫-順序播放.gif

2.AnimatorSet.Builder

  		//組合動畫
        AnimatorSet animator = new AnimatorSet();

        //目標動畫
        AnimatorSet.Builder builder=animator.play(objectAnimatorScaleY);

        //執行目標動畫後再執行該動畫
        builder.after(objectAnimatorScaleY);

        //執行該動畫後再執行目標動畫
        builder.before(objectAnimatorScaleY);

        //和目標動畫一起播放
        builder.with(objectAnimatorScaleY);

        //延遲時間執行目標動畫
        builder.after(3000);


		//串列方式
        AnimatorSet animator = new AnimatorSet();
        AnimatorSet.Builder builder=animator
        	.play(objectAnimatorScaleY)
            .after(objectAnimatorScaleY)
            .before(objectAnimatorScaleY);


		//如果AnimatorSet設置了動畫時長,迴圈次數等,都以AnimatorSet為準,單個設置不起作用。
        //每個動畫的播放時間
        animator.setDuration(3000);
  		//所有的動畫都集中於這個控制項上,其它的不起作用
        animator.setTarget(ballImageView);

九、實例-衛星菜單

1.實現原理

實現一個放射衛星的效果,點擊一下,放射出菜單,再點擊一下,收回菜單。
原理就是,將所有的菜單重疊在一起,點擊最上面的菜單,按照不同的角度,實現位移,縮放,透明度的效果,將下麵的菜單都位移出去。看看位移的計算方式,每個菜單,與主菜單都形成了直角形式,水平X軸的位移和Y軸的水平位移都可以計算出來。  就是從主菜單,位移到不同位置的X軸和Y軸。
計算公式.png

2.佈局

佈局非常簡單,全部控制項疊加在一起,而且子菜單的屬性全部一致,省略了一些重覆的空間。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="20dp">

        <!-- Shadow 代表陰影,對陰影的一些處理-->
        <Button
            android:id="@+id/mainBtn"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_gravity="center_vertical|right"
            android:layout_marginRight="40dp"
            android:background="@drawable/menu_main"
            android:outlineAmbientShadowColor="@android:color/transparent"
            android:outlineSpotShadowColor="@android:color/transparent"
            android:shadowColor="@android:color/transparent" />

        <Button
            android:id="@+id/rockBtn"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_gravity="center_vertical|right"
            android:layout_marginRight="20dp"
            android:background="@drawable/menu_rock"
            android:outlineAmbientShadowColor="@android:color/transparent"
            android:outlineSpotShadowColor="@android:color/transparent"
            android:shadowColor="@android:color/transparent"
            android:visibility="gone" />
                
            <!-- 以下省略六個子按鈕菜單 -->    
    </FrameLayout>


</LinearLayout>

3.java代碼

核心思想就是,添加要控制的子菜單,開啟動畫方法,關閉動畫方法。


public class ExampleActivity extends BaseActivity {

    private boolean mIsMenuOpen = false;
    private Button mMainBtn, mRockBtn, mAirBtn, mTrainBtn, mCarBtn, mMotorbikeBtn, mBicycleBtn, mWalkBtn;
    List<Button> mBtnArray;

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

    public void initView() {
        setContentView(R.layout.activity_example);
        mMainBtn = findViewById(R.id.mainBtn);

        mRockBtn = findViewById(R.id.rockBtn);
        mAirBtn = findViewById(R.id.airBtn);
        mTrainBtn = findViewById(R.id.trainBtn);
        mCarBtn = findViewById(R.id.carBtn);
        mMotorbikeBtn = findViewById(R.id.motorbikeBtn);
        mBicycleBtn = findViewById(R.id.bicycleBtn);
        mWalkBtn = findViewById(R.id.walkBtn);

        //添加子菜單
        mBtnArray = new ArrayList<Button>();
        mBtnArray.add(mRockBtn);
        mBtnArray.add(mAirBtn);
        mBtnArray.add(mTrainBtn);
        mBtnArray.add(mCarBtn);
        mBtnArray.add(mMotorbikeBtn);
        mBtnArray.add(mBicycleBtn);
        mBtnArray.add(mWalkBtn);
    }

    public void OnClick() {
        mMainBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                switchAnimation();
            }
        });

        mRockBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(ExampleActivity.this, "你選擇了火箭出行!", Toast.LENGTH_SHORT).show();
            }
        });
    }

    //開關
    public void switchAnimation() {
        if (!mIsMenuOpen) {
            mIsMenuOpen = true;
            for (int i = 0; i < mBtnArray.size(); i++) {
                doAnimationOpen(mBtnArray.get(i), i, mBtnArray.size(), 500);
            }
        } else {
            mIsMenuOpen = false;
            for (int i = 0; i < mBtnArray.size(); i++) {
                doAnimationClose(mBtnArray.get(i), i, mBtnArray.size(), 500);
            }
        }
    }

    /**
     * 開啟動畫/展開菜單
     * @param view   要控制的控制項/子菜單
     * @param index  要控制控制項的順序
     * @param total  子菜單的總數
     * @param radius 主菜單到子菜單的距離/半徑
     * */
    private void doAnimationOpen(View view, int index, int total, int radius) {

        //顯示菜單
        if (view.getVisibility() != View.VISIBLE) {
            view.setVisibility(View.VISIBLE);
        }

        //計算每個菜單的角度,toRadians()將度數轉換為弧度
        //七個子菜單,有六個夾角角,180/(7-1)*2  2代表第二個夾角
        double degree = Math.toRadians(180) / (total - 1) * index;

        //X軸位移
        int translationX = -(int) (radius * Math.sin(degree));

        //Y軸位移
        int translationY = -(int) (radius * Math.cos(degree));
        AnimatorSet animatorSet = new AnimatorSet();

        //動畫合集
        animatorSet.playTogether(

                //從原來控制項的位置往X軸移動多少
                ObjectAnimator.ofFloat(view, "translationX", 0, translationX),

                //從原來控制項的位置往Y軸移動多少
                ObjectAnimator.ofFloat(view, "translationY", 0, translationY),

                //X軸縮放
                ObjectAnimator.ofFloat(view, "scaleX", 0.01f, 1f),

                //Y軸縮放
                ObjectAnimator.ofFloat(view, "scaleY", 0.01f, 1.0f),

                //透明度
                ObjectAnimator.ofFloat(view, "alpha", 0.01f, 1.0f)
        );
        animatorSet.setDuration(500);
        animatorSet.start();
    }

    //關閉菜單/動畫
    private void doAnimationClose(View view, int index, int total, int radius) {
        if (view.getVisibility() != View.VISIBLE) {
            view.setVisibility(View.VISIBLE);
        }
        double degree = Math.toRadians(180) / (total - 1) * index;
        int translationX = -(int) (radius * Math.sin(degree));
        int translationY = -(int) (radius * Math.cos(degree));
        AnimatorSet animatorSet = new AnimatorSet();

        animatorSet.playTogether(
                ObjectAnimator.ofFloat(view, "translationX", translationX, 0),
                ObjectAnimator.ofFloat(view, "translationY", translationY, 0),
                ObjectAnimator.ofFloat(view, "scaleX", 1.0f, 0.01f),
                ObjectAnimator.ofFloat(view, "scaleY", 1.0f, 0.01f),
                ObjectAnimator.ofFloat(view, "alpha", 1.0f, 0.01f)
        );
        animatorSet.setDuration(500);
        animatorSet.start();
    }
}

3.效果

衛星菜單.gif

十、XML實現Animator

1.animator

在animator下建立animator.xml

image.png

xml代碼:

<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:valueFrom="0"
    android:valueTo="300"
    android:valueType="intType" />

java代碼使用

  ValueAnimator valueAnimator=(ValueAnimator)AnimatorInflater.loadAnimator(
                                ExampleActivity.this,
                                R.animator.animator);

                valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        int offset=(int)animation.getAnimatedValue();
                        mRockBtn.layout(offset,offset,mRockBtn.getWidth()+offset,mRockBtn.getHeight()+offset);
                    }
                });
                valueAnimator.start();

2.ObjectAnimator

object_animator.xml

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"  //時間
    android:interpolator="@android:anim/accelerate_interpolator"  //插值器
    android:propertyName="string"  //要映射的名字
    android:repeatCount="11"      //迴圈次數
    android:repeatMode="restart"  //迴圈模式
    android:startOffset="777"     
    android:valueFrom="99"  //開始
    android:valueTo="199"   //目標
    android:valueType="intType"  //數據類型
    />

java代碼使用

  ObjectAnimator animator=(ObjectAnimator)AnimatorInflater.loadAnimator(
                        ExampleActivity.this,
                        R.animator.object_animator);
                animator.setTarget(mAirBtn);
                animator.start();

十一、後語

包括其它的知識點,都只能說一些基礎的內容,很多方法和拓展知識都沒有說道,需要自己去探索,多閱讀SDK源碼。屬性動畫,有一些高級的內容,後續會持續拓展。

編程中我們會遇到多少挫折?表放棄,沙漠盡頭必是綠洲。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 【目錄】 一 系統資料庫 二 創建資料庫 三 資料庫相關操作 一 系統資料庫 information_schema: 虛擬庫,不占用磁碟空間,存儲的是資料庫啟動後的一些參數,如用戶表信息、列信息、許可權信息、字元信息等 performance_schema: MySQL 5.5開始新增一個資料庫,主要 ...
  • 伴隨著Redis6.0的發佈,作為最令人怦然心動的特性之一,Redis官方同時推出Redis集群的proxy了:redis-cluster-proxy,https://github.com/RedisLabs/redis-cluster-proxy 相比從前訪問Redis集群時需要制定集群中所有的I ...
  • mysql命令gruop by報錯this is incompatible with sql_mode=only_full_group_by 出現這個錯誤已導致在開發中mybatis的sql也運行不了 原因: 看一下group by的語法: select 選取分組中的列+聚合函數 from 表名稱 ...
  • 目錄:andorid jar/庫源碼解析 RxJava2: 作用: 通過提供一種,觀察者和訂閱者的模式,的架構,來優化邏輯流程。適用於複雜和需要多數據轉換和長流程。 慄子: 定義三個對象類 public class ResultInfo { public int code; public Strin ...
  • 目錄:andorid jar/庫源碼解析 Bolts: 作用: 用於鏈式執行跨線程代碼,且傳遞數據 慄子: Task.call(new Callable<Boolean>() { @Override public Boolean call() throws Exception { return tr ...
  • 快速接入訊飛語音聽寫SDK(內附空指針解決和修改對話框文字方法) ...
  • 簡單又詳細,Android Library 發佈開源庫 JCenter & JitPack 攻略~ ...
  • 前言 最近項目有一個節點進度條的小需求,完成後,想分享出來希望可以幫到有需要的同學。 真機效果圖 自定義View完整代碼 開箱即用~,註釋已經炒雞詳細了 註意點 1. 控制項的節點總個數是與傳入的節點底部標題列表中元素個數控制(相同)的,簡而言之就是傳入的標題列表中有多少個標題,節點就會繪製多少個 2 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...