編輯:關於Android編程
市面上的大多數應用,多多少少都會通過動畫,讓應用多一些靈動性和趣味性,並且在視圖之間的切換會顯得更加自然。例如許多應用都定制了自己的下拉刷新中的動畫,讓應用增色不少。Android動畫主要有:
View 動畫 屬性動畫 幀動畫View動畫是Android裡面常用的動畫方式。View動畫直接作用於View上面。View動畫有且只有四種:平移、縮放、旋轉、透明度。平移就是左右上下位置移動,縮放就是大小的變換,旋轉就是視圖的2D旋轉,透明度就不用多說了,由於View動畫采用xml方式實現較多,所以這裡我們著重介紹下xml方式下的View動畫標簽。
...
我們可以看到這裡有一個 android:interpolator 屬性。這個在動畫中十分重要,interpolator 插值器,控制動畫是以一定的速度播放還是先快後慢等動畫播放效果。android內置了豐富的插值器,不同的插值器對整個動畫過程會產生不同的影響,默認的插值器是常量速度插值器,我們可以通過插值器讓動畫執行過程由慢到快的變換。下面是Android系統提供的部分常見插值器:
View動畫實現
View動畫有兩種實現方式,一種是硬編碼,一種是通過XML文件,建議使用XML方式。如果采用XML文件的話,那麼需要在/res文件夾下面新建anim文件夾,並且將XML動畫文件放在文件夾下面。
//加載XML動畫並且播放
public void loadAnimation(){
//加載動畫
Animation animation = AnimationUtils.loadAnimation(this,R.anim.alpha_scale);
//設定動畫播放時長
animation.setDuration(3000);
//通過View.startAnimation(Animation)執行動畫
findViewById(R.id.iv).startAnimation(animation);
}
//純硬編碼方式
public void loadAnimation2(){
//動畫效果由透明動畫與縮放動畫組合成,所以需要用AnimationSet將他們裝起來
AnimationSet animationSet = new AnimationSet(true);
//創建透明度動畫
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
//創建縮放動畫
ScaleAnimation scaleAnimation = new ScaleAnimation(0f, 1f, 0f, 1f,
Animation.RELATIVE_TO_SELF,0.5f, Animation.RELATIVE_TO_SELF,0.5f);
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(scaleAnimation);
animationSet.setDuration(3000);
//通過View.startAnimation(Animation)播放動畫
findViewById(R.id.iv).startAnimation(animationSet);
}
View動畫常用方法:
需要特別注意,View動畫的交互事件只在動畫前的位置有效。例如我向右平移了100px,並停留在該位置,但是在該位置無法觸發觸摸等事件,因為View動畫的交互事件只在原來的位置有效!
屬性動畫是Android 從API 11(Android3.0)開始支持的動畫類型。雖然官方只支持API11以上(包括),但是我們依舊可以使用NineOldAndroids在API11下面采用屬性動畫的用法(部分動畫效果實質還是View動畫)。屬性動畫十分強大,幾乎可以在任何對象上產生動畫效果。屬性動畫的原理是:在一定的動畫時長內,在不同的時間點(幀)下,不斷改變對象的屬性值,從而產生動畫效果。屬性動畫由三部分構成:動畫控制器、插值器、估值器。
屬性動畫控制器,控制著動畫的播放&停止,動畫的時間等等,並提供一系列的動畫回調。控制器是我們使用屬性動畫的入口。我們經常使用的是ObjectAnimator來實現動畫效果,如果需要更加靈活的控制動畫,那麼可以通過ValueAnimator實現。
這裡的插值器與上面View動畫的插值器是一致的,屬性動畫的原理是不停的改變屬性值,來實現動畫效果,這個屬性值的計算是由插值器與估值器共同計算出來的,而插值器是主要的影響因素。例如上面有一AccelerateInterpolator(動畫由慢到快)插值器,插值的增長速率會慢慢變快。以此才能達到由慢到快的動畫效果。下圖是AccelerateInterpolator插值器每兩個時間點的差值。
vcrLl1rXG9w==" src="/uploadfile/Collfiles/20160614/20160614093434113.png" title="\" />
可以很清晰的看到,越往下,每兩個時間點的差值越大,也就是插值隨著時間加速增長,因此,才能讓動畫由慢到快。不同的插值器,在動畫開始到結束過程中,產生的插值數值也不一樣,需要注意的是,這裡的插值數值是隨著動畫時間變化的一個比例值,不是具體應該被設置的屬性值。
上面我們提到動畫播放過程中的屬性值由插值器和估值器共同計算,由於插值器只得出了隨著時間變化而改變的一個插值比例值,所以我們還需要通過動畫估值器來計算出該時間點最終的屬性值。Android系統提供的默認估值器有:
我們比較常用ObjectAnimator實現屬性動畫,使用ObjectAnimator的時候,有一個前提條件,那就是需要目標對象提供作用屬性的Setter封裝方法。下面是Android 11(Android 3.0)之後。我們常用且View基類中提供了Setter方法的屬性。
利用ObjectAnimator實現上面View動畫從0到1透明並且逐漸放大的效果:
private void playObjectPropertyAnimation() {
final ImageView iv = (ImageView) findViewById(R.id.iv);
final AnimatorSet animatorSet = new AnimatorSet();
//作用在ImageView的alpha、scaleX、scaleY屬性上
ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(iv, "alpha", 0, 1);
ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(iv, "scaleX", 0, 1);
ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(iv, "scaleY", 0, 1);
//這裡同一時間播放上面三個動畫
animatorSet.playTogether(alphaAnimator, scaleXAnimator, scaleYAnimator);
animatorSet.setDuration(3000);
animatorSet.start();
}
如果目標對象的作用屬性沒有提供Setter方法,那麼我們需要創建包裝類,提供相應的Setter方法。我們如果要將動畫作用於寬度&高度上,但是View對象並沒有提供寬度&高度的Setter方法,那麼我們需要創建相應的包裝類。
//View寬度包裝類
public class ViewWidthWrapper {
private View v;
public ViewWidthWrapper(View v){
this.v = v;
}
//寬度Setter方法
public void setWidth(int width){
ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
layoutParams.width = width;
v.setLayoutParams(layoutParams);
v.invalidate();
}
public int getWidth(){
return v.getWidth();
}
}
//播放寬度屬性
private void playCustomPropertyAnimation() {
final ImageView iv = (ImageView) findViewById(R.id.iv);
//創建View寬度包裝類
final ViewWidthWrapper widthWrapper = new ViewWidthWrapper(iv);
iv.post(new Runnable() {
@Override
public void run() {
//播放寬度屬性動畫
final ObjectAnimator widthAnimator = ObjectAnimator.ofInt(widthWrapper,"width",widthWrapper.getWidth(),widthWrapper.getWidth()+100);
widthAnimator.setDuration(3000);
widthAnimator.start();
}
});
}
我們也可以利用ValueAnimator更加靈活的實現動畫,但是相對於ObjectAnimator會相對復雜一點。我們需要聯合ValueAnimator.AnimatorUpdateListener回調來實現屬性動畫。下面是用ValueAnimator實現上面ObjectAnimator實現的動畫效果。
public void loadValueAnimation(){
final ImageView iv = (ImageView)findViewById(R.id.iv);
//估值器
final FloatEvaluator floatEvaluator = new FloatEvaluator();
//透明度動畫
ValueAnimator alphaAnimator = ValueAnimator.ofFloat(0,1);
alphaAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
//這裡我們需要自己計算最終屬性值
float value = floatEvaluator.evaluate(valueAnimator.getAnimatedFraction(),0,1);
//自己更新作用屬性值
iv.setAlpha(value);
}
});
//X軸縮放動畫
ValueAnimator scaleXAnimator = ValueAnimator.ofFloat(0,1);
scaleXAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float value = floatEvaluator.evaluate(valueAnimator.getAnimatedFraction(),0,1);
iv.setScaleX(value);
}
});
//Y軸縮放值
ValueAnimator scaleYAnimator = ValueAnimator.ofFloat(0,1);
scaleXAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float value = floatEvaluator.evaluate(valueAnimator.getAnimatedFraction(),0,1);
iv.setScaleY(value);
}
});
final AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(alphaAnimator,scaleXAnimator,scaleYAnimator);
animatorSet.setDuration(3000);
iv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animatorSet.start();
}
});
}
通過代碼我們可以看到,ValueAnimator只是幫我們計算了插值並提供了一個插值變化的回調方法,我們需要自己手動在回調方法裡面,根據估值器計算最終屬性值,並且自己更新View的屬性值,最終才能實現動畫效果。相比較ObjectAnimator來說,實現同一個效果會相對麻煩,但是靈活性增高了。例如ValueAnimator不需要我們提供Setter方法。
屬性動畫常用方法
幀動畫是直接由一副一副圖片組成,並且按照一定的順序和間隔進行播放,這就構成了幀動畫。Android幀動畫的實現十分簡單,通過AnimationDrawable就可以很簡單的實現幀動畫:
-
-
private void playFrameAnimation(){
ImageView iv = (ImageView) findViewById(R.id.iv);
//這裡跟我們設置其他圖片資源是一樣的
iv.setImageResource(R.drawable.ani);
//將ImageView圖片資源轉換成AnimationDrawable
AnimationDrawable animationDrawable = (AnimationDrawable) iv.getDrawable();
//播放幀動畫
animationDrawable.start();
}
除了用以上幾種Android提供的方式實現動畫之外,還可以通過自定義View實現動畫效果。
我們可以在onDraw()方法裡面,不停調用invaildate()來產生動畫效果,有一些動畫效果就是通過這種方式實現的。例如下面就是通過自定義View方式粗糙的仿荔枝FM加載稍等提示框的效果。
public class LizhiLoadingView extends View {
private float lineOneStartY,lineOneEndY;
private float lineSecondStartY,lineSecondEndY;
private float lineThirdStartY,lineThirdEndY;
private boolean onePlus;
private Paint mPaint;
public LizhiLoadingView(Context context) {
super(context);
initPaint();
}
public LizhiLoadingView(Context context, AttributeSet attrs) {
super(context, attrs);
initPaint();
}
public LizhiLoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaint();
}
private void initPaint(){
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(20);
mPaint.setStyle(Paint.Style.FILL);
lineOneStartY = 0;
lineOneEndY = 100;
lineSecondStartY = 10;
lineSecondEndY = 80;
lineThirdStartY = 0;
lineThirdEndY = 100;
onePlus = true;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawLine(80,lineOneStartY,80,lineOneEndY,mPaint);
canvas.drawLine(150,lineSecondStartY,150,lineSecondEndY,mPaint);
canvas.drawLine(220,lineThirdStartY,220,lineThirdEndY,mPaint);
//下面改變繪畫參數
if(onePlus){
lineOneStartY++;
lineThirdStartY++;
lineSecondStartY --;
lineOneEndY--;
lineThirdEndY--;
lineSecondEndY++;
}else{
lineOneStartY--;
lineThirdStartY--;
lineSecondStartY ++;
lineOneEndY++;
lineThirdEndY++;
lineSecondEndY--;
}
if(lineOneStartY==25){
onePlus = false;
}else if(lineOneStartY ==0){
onePlus = true;
}
//這裡導致onDraw()被不停調用
invalidate();
}
}
小米4、紅米2、小米Note的手機用戶可能經常會遇到“請勿遮擋橙色區域”的提示,這其實是小米手機的防誤觸功能的提示,以保證手機在口袋
優點:擺脫原始的Crash界面處理缺點:無法自定義界面實現自定義Ui介紹:“Recovery”幫助你自動處理程序在運行時的Crash,它含有以下幾
在android studio 中出現找不到com.android.support:recyclerview-v7 jar包。 咋一看不對啊,明明you su
在SystemUI中有一個Activity可以顯示所有的Logo這個Activity涉及到的圖標存放在SystemUI/res/drawable-nodpi目錄下在這裡我