一、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 = https://www.cnblogs.com/lanjiabin/p/curValueFloat.intValue();
//改變控制元件的位置,layout對應的是控制元件的位置
valueTV.layout(curValue, curValue, curValue + imageView.getWidth(), curValue + imageView.getHeight());
}
});
valueAnimator.start();
}
監聽器三個

//監聽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()
效果:

二、自定義插值器
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=https://www.cnblogs.com/lanjiabin/p/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=https://www.cnblogs.com/lanjiabin/p/(int)animation.getAnimatedValue();
valueTV.setBackgroundColor(curValue);
}
});
valueAnimator.start();
}
效果:

顏色必須包含ARGB四個值,

五、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;
}
}
效果:

六、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軸:

X軸:

Y軸:

七、自定義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.效果

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();
}
同時播放:影片效果同時體現出來,縮放和位移

順序播放:先縮放完畢再位移

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軸,

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.效果

十、XML實作Animator
1.animator
在animator下建立animator.xml

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原始碼,屬性影片,有一些高級的內容,后續會持續拓展,
編程中我們會遇到多少挫折?表放棄,沙漠盡頭必是綠洲,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/5570.html
標籤:Android
