編輯:關於Android編程
Tween動畫又稱補間動畫。通過對view的位置、大小、透明度、角度的改變來實現動畫效果。
補間動畫的基類是Animation。我們通常使用它的直接子類RotateAnimation、TranslateAnimation、ScaleAnimation、AlphaAnimation。
補間動畫可以通過xml進行定義(res/anim/xxx),然後通過AnimationUtils類進行加載;也可以通過完全代碼進行設置。
<code class="hljs xml"><!--{cke_protected}{C}%3C!%2D%2D%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%2D%2D%3E--> <set android:interpolator="@[package:]anim/interpolator_resource" android:shareinterpolator="[" xmlns:android="http://schemas.android.com/apk/res/android"> <alpha android:fromalpha="float" android:toalpha="float"> <scale android:fromxscale="float" android:fromyscale="float" android:pivotx="float" android:pivoty="float" android:toxscale="float" android:toyscale="float"> <translate android:fromxdelta="float" android:fromydelta="float" android:toxdelta="float" android:toydelta="float"> <rotate android:fromdegrees="float" android:pivotx="float" android:pivoty="float" android:todegrees="float"> <set> ... </set> </rotate></translate></scale></alpha></set></code>
Animation類定義了很多常量和變量的初始值,比如:
public static final int INFINITE = -1;
public static final int RESTART = 1;
public static final int REVERSE = 2;
主要用到它的子類以及AnimationListener :
public static interface AnimationListener {
/**
* 動畫開始的時候回調
*
* @param animation The started animation.
*/
void onAnimationStart(Animation animation);
/**
* 動畫結束的時候回調。但是當設置動畫重復次數為INFINITE的時候,該方法不會回調。
*
* @param animation The animation which reached its end.
*/
void onAnimationEnd(Animation animation);
/**
* 動畫重復播放的時候回調
*
* @param animation The animation which was repeated.
*/
void onAnimationRepeat(Animation animation);
}
添加此監聽器可以對動畫做更多的操作。
介紹動畫之前,得先說說”插值器”。插值器的意思就是在播放動畫的時候,改變播放的速率,可以使動畫越來越快,或者越來越慢等。
常用的是一下九個插值器:
一般來說,官方API給的這幾個插值器就夠實用了。不過還可以自定義Interpolator。可以簡單的對系統的插值器進行一些參數值的修改:
android:zAdjustment:允許在動畫播放期間,調整播放內容在Z軸方向的順序:
normal(0):正在播放的動畫內容保持當前的Z軸順序, top(1):在動畫播放期間,強制把當前播放的內容放到其他內容的上面; bottom(-1):在動畫播放期間,強制把當前播放的內容放到其他內容之下
然後通過AnimationUtils類裝載動畫,進行應用。
Animation scaleAnimation = AnimationUtils.loadAnimation(this, R.anim.scale_anim);
targetIv.startAnimation(scaleAnimation);
ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 0.5f, 1.0f, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(1000);
scaleAnimation.setInterpolator(new OvershootInterpolator());
scaleAnimation.setFillAfter(true);
targetIv.startAnimation(scaleAnimation);
ScaleAnimation有4個構造方法。
public ScaleAnimation(Context context, AttributeSet attrs) {}
public ScaleAnimation(float fromX, float toX, float fromY, float toY) {}
public ScaleAnimation(float fromX, float toX, float fromY, float toY, float pivotX, float pivotY) {}
public ScaleAnimation(float fromX, float toX, float fromY, float toY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue) {}
第一個構造用於從資源文件中加載資源。我們主要用後三個。後面三個構造的區別就在設置變換中軸點與否。不指定pivotXType和pivotYType的話,默認采用ABSOLUTE形式,pivotX與pivotY的值都是相對於(0,0)左上角偏移的。
pivotXType可設置的參數有三種:ABSOLUTE、RELATE_TO_SELF、RELATE_TO_PARENT。
ABSOLUTE表示當前設置的pivotX和pivotY值是絕對值,相對於左上角偏移。比如:android:pibotX=”50” RELATE_TO_SELF表示設置的pivotX和pivotY是相對值。比如:android:pivotX = “50%”表示X方向中軸點在正中間。 取值范圍是[0% ~ 100%] RELATE_TO_PARENT也是表示相對值,是相對於該視圖的父控件而言。比如:android:pivotX = “50%p”表示X方向中軸點是其父控件的中間位置。取值范圍是[0% ~ 100%]效果如下:
RotateAnimation rotateAnimation = new RotateAnimation(0.0f, 550.0f, Animation.RELATIVE_TO_SELF, 0.3f, Animation.RELATIVE_TO_SELF, 0.3f);
rotateAnimation.setDuration(1500);
rotateAnimation.setInterpolator(new OvershootInterpolator());
rotateAnimation.setFillAfter(true);
targetIv.startAnimation(rotateAnimation);
效果圖如下:
TranslateAnimation translateAnimation = new TranslateAnimation(0, 200, 0, 0);
translateAnimation.setDuration(1000);
translateAnimation.setInterpolator(new AnticipateOvershootInterpolator());
targetIv.startAnimation(translateAnimation);
AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0.2f);
alphaAnimation.setDuration(1500);
alphaAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
alphaAnimation.setRepeatMode(Animation.REVERSE);
alphaAnimation.setRepeatCount(1);
targetIv.startAnimation(alphaAnimation);
上面都是一個個的單獨的動畫,我們可以將很多個單獨的動畫組合到一起成為一個集合。
動畫集合也可以在xml中設置。需要用標簽包括其他簡單的動畫。比上述公共動畫屬性多了一個android:shareInterpolator=”boolean”,表示是否對子動畫設置相同的插值器。
我們來看一個現象:
設置了上面的set動畫之後,開始運行的時候,會發現漸變動畫開始運行的時候,會先變小,旋轉一個角度,然後才開始動畫。仔細分析xml代碼之後,發現是在動畫開始的時候,把scale和rotate中的初始狀態給應用了。這時候想起了android:fillBefore屬性。
然後在scale、rotate 動畫裡添加了android:fillBefore=”false”屬性之後,發現還是不好使。查看Animation類的源碼發現,fillBefore必須在設置fillEnable=”true”的時候才神效。並且fillBefore的默認值是true,所以才會出現上述情況。
再次修改之後,代碼如下:
效果如下:
Frame動畫就是把圖片一幀一幀的播放出來的顯示效果,類似於gif圖片。幀動畫設置很簡單,只需要把每一幀對應的圖片按照順序添加進去,然後設置每一幀的顯示時長,然後為view控件設置該動畫,播放就行了。
-
-
-
-
-
-
給ImageView設置動畫:
targetIv.setBackgroundResource(R.drawable.frame_anim);
AnimationDrawable animationDrawable = (AnimationDrawable) targetIv.getBackground();
animationDrawable.start();
AnimationDrawable animationDrawable = new AnimationDrawable();
animationDrawable.setOneShot(false);
animationDrawable.addFrame(getResources().getDrawable(R.drawable.person1), 200);
animationDrawable.addFrame(getResources().getDrawable(R.drawable.person2), 200);
animationDrawable.addFrame(getResources().getDrawable(R.drawable.person3), 200);
animationDrawable.addFrame(getResources().getDrawable(R.drawable.person4), 200);
animationDrawable.addFrame(getResources().getDrawable(R.drawable.person5), 200);
targetIv.setImageDrawable(animationDrawable);
animationDrawable.start();
Tween Animation和Frame Animation都是針對單個view操作的。而LayoutAnimationController可以針對一個ViewGroup進行動畫操作,可以讓一組view的每個view按照一定的規則展示動畫。
比如:可以針對listView、gridView或者recyclerView,定義item的出場動畫,而不是非常死板的一下子全顯示出來。
一般對ListView使用layoutAnimation動畫,對GridView使用gridLayoutAnimation動畫。對RecyclerView來說,正常情況下只能使用layoutAnimation動畫,應用gridLayoutAnimation動畫的時候會報錯。不錯可以針對RecyclerView生成一個子類做一下處理進行支持gridLayoutAnimation動畫。
public LayoutAnimationController(Animation animation) {
this(animation, 0.5f);
}
public LayoutAnimationController(Animation animation, float delay) {
mDelay = delay;
setAnimation(animation);
}
LayoutAnimationController有三個構造函數,常用的時候上面兩個。delay表示每個子view啟動動畫的延遲時間,默認是0.5f。delay以秒為單位 。
Animation animation = AnimationUtils.loadAnimation(this, R.anim.item_list_anim);
LayoutAnimationController layoutAnimationController = new LayoutAnimationController(animation);
layoutAnimationController.setInterpolator(new AccelerateInterpolator());
layoutAnimationController.setDelay(0.5f);
layoutAnimationController.setOrder(LayoutAnimationController.ORDER_RANDOM);
recyclerView.setLayoutAnimation(layoutAnimationController);
GridLayoutAnimationController是LayoutAnimationController的子類。針對GridView做動畫操作。
同樣是使用一個Animation構造出GridLayoutAnimation對象,然後設置各種參數,最後設置此動畫GridView即可。
Animation animation = AnimationUtils.loadAnimation(this, R.anim.item_anim_alpha);
GridLayoutAnimationController gridLayoutAnimationController = new GridLayoutAnimationController(animation);
gridLayoutAnimationController.setDirection(GridLayoutAnimationController.DIRECTION_BOTTOM_TO_TOP | GridLayoutAnimationController.DIRECTION_RIGHT_TO_LEFT);
gridLayoutAnimationController.setDirectionPriority(GridLayoutAnimationController.PRIORITY_ROW);
gridRecyclerView.setLayoutAnimation(gridLayoutAnimationController);
效果如下:
正常情況下,我們可以對RecyclerView使用LayoutAnimation動畫。但是如果對RecycleView使用動畫的時候出現以下錯誤:
AndroidRuntime: FATAL EXCEPTION: main
Process: com.jacksen.demo.view, PID: 30770
java.lang.ClassCastException: android.view.animation.LayoutAnimationController$AnimationParameters cannot be cast to android.view.animation.GridLayoutAnimationController$AnimationParameters
at android.view.animation.GridLayoutAnimationController.getDelayForView(GridLayoutAnimationController.java:299)
at android.view.animation.LayoutAnimationController.getAnimationForView(LayoutAnimationController.java:321)
at android.view.ViewGroup.bindLayoutAnimation(ViewGroup.java:3717)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2892)
......
意思就是GridLayoutAnimationController.AnimationParameters不能強轉成LayoutAnimationController.AnimationParameters。
RecyclerView的出現本來就是替代Listview的,但是它有可以展示出GridView的效果,但是怎麼讓RecyclerView設置GridLayoutManager的時候應用gridLayoutAnimation動畫呢?
我們先來看看Gridview怎麼實現的?
在GridView源碼裡面搜索”LayoutAnimation”關鍵字發現,只有一個attachLayoutAnimationParameters()的函數,裡面將layoutAnimationParameters強轉成GridLayoutAnimationController.AnimationParameters。
@Override
protected void attachLayoutAnimationParameters(View child,
ViewGroup.LayoutParams params, int index, int count) {
GridLayoutAnimationController.AnimationParameters animationParams =
(GridLayoutAnimationController.AnimationParameters) params.layoutAnimationParameters;
if (animationParams == null) {
animationParams = new GridLayoutAnimationController.AnimationParameters();
params.layoutAnimationParameters = animationParams;
}
animationParams.count = count;
animationParams.index = index;
animationParams.columnsCount = mNumColumns;
animationParams.rowsCount = count / mNumColumns;
if (!mStackFromBottom) {
animationParams.column = index % mNumColumns;
animationParams.row = index / mNumColumns;
} else {
final int invertedIndex = count - 1 - index;
animationParams.column = mNumColumns - 1 - (invertedIndex % mNumColumns);
animationParams.row = animationParams.rowsCount - 1 - invertedIndex / mNumColumns;
}
}
然後就想到去RecyclerView中去找attachLayoutAnimationParameters()方法,但是沒有,其父類ViewGroup裡面有此方法:
protected void attachLayoutAnimationParameters(View child,
LayoutParams params, int index, int count) {
LayoutAnimationController.AnimationParameters animationParams =
params.layoutAnimationParameters;
if (animationParams == null) {
animationParams = new LayoutAnimationController.AnimationParameters();
params.layoutAnimationParameters = animationParams;
}
animationParams.count = count;
animationParams.index = index;
}
由此可見RecyclerView默認實現了ViewGroup的LayoutAnimation。我們在RecyclerView中將此方法重寫一下。不過要將mStackFromButtom參數的判斷去掉。
public class GridRecyclerView extends RecyclerView {
public GridRecyclerView(Context context) {
super(context);
}
public GridRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public GridRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void setAdapter(Adapter adapter) {
super.setAdapter(adapter);
}
@Override
public void setLayoutManager(LayoutManager layout) {
if (layout instanceof GridLayoutManager) {
super.setLayoutManager(layout);
} else {
throw new ClassCastException("you should only use the GridLayoutManager as LayoutManager when you use this " + this.getClass().getSimpleName() + " class");
}
}
@Override
protected void attachLayoutAnimationParameters(View child, ViewGroup.LayoutParams params, int index, int count) {
if (getLayoutManager() != null && getLayoutManager() instanceof GridLayoutManager) {
GridLayoutAnimationController.AnimationParameters animationParams =
(GridLayoutAnimationController.AnimationParameters) params.layoutAnimationParameters;
if (animationParams == null) {
animationParams = new GridLayoutAnimationController.AnimationParameters();
params.layoutAnimationParameters = animationParams;
}
int mNumColumns = ((GridLayoutManager) getLayoutManager()).getSpanCount();
animationParams.count = count;
animationParams.index = index;
animationParams.columnsCount = mNumColumns;
animationParams.rowsCount = count / mNumColumns;
final int invertedIndex = count - 1 - index;
animationParams.column = mNumColumns - 1 - (invertedIndex % mNumColumns);
animationParams.row = animationParams.rowsCount - 1 - invertedIndex / mNumColumns;
} else {
super.attachLayoutAnimationParameters(child, params, index, count);
}
}
}
當我們使用GridLayoutManager的時候,不能使用此屬性。
/**
* stackFromEnd is not supported by GridLayoutManager. Consider using
* {@link #setReverseLayout(boolean)}.
*/
@Override
public void setStackFromEnd(boolean stackFromEnd) {
if (stackFromEnd) {
throw new UnsupportedOperationException(
"GridLayoutManager does not support stack from end."
+ " Consider using reverse layout");
}
super.setStackFromEnd(false);
}
一、概述最近一直關注熱修復的東西,偶爾聊天談到了增量更新,當然了兩個完全不是一個東西。借此找了一些資料,收集整理了一下,本來是不想寫博客的,因為主要都是工具的實現,但是昨
1、概述 上一篇已經基本給大家介紹了如何自定義ViewGroup,如果你還不了解,請查看:Android 手把手教您自定ViewGroup ,本篇將使用上篇
API IntroductionContent providers are one of the primary building blocks(構件) of Andro
篇幅較長遂分成上下兩篇,上一篇我們已經快要一氣呵成了,但是美中不足的是,這個界面並不能討得美工MM的歡心,美工MM曾寄希望於您,卻交出這麼作出這麼一副死型樣,我都替你汗顏