下拉刷新動畫研究
阿新 • • 發佈:2017-06-26
而且 thead index 技術 alt 動畫播放 view動畫 set ips
昨天公司提了一個需求。說是要有自己特色的下拉刷新上拉載入很多其它,隨後就去萬能的github上面看看自己之前存過的那些。偶然間看到這個Android-AnimatePullToRefreshListView,這玩意能夠使用gif圖片或者幀動畫去運行headview動畫載入,而且是基於chrisbanes的Android-PullToRefresh,這樣還方便與我項目無縫銜接
上一張效果圖
大體上簡單說明下:
1.gif與幀動畫播放採用的是android-gif-drawable
2.主題上是改動了RotateLoadingLayout類。看代碼
//幀動畫三張圖
private int[] mGifRes = {
R.drawable.dropdown_loading_00,
R.drawable.dropdown_loading_01,
R.drawable.dropdown_loading_02,
};
//通過下拉的scale比例,去計算應該顯示哪張圖片(下拉距離/headview高度)
protected void onPullImpl(float scaleOfLayout) {
int index = (int) (scaleOfLayout / 1f * 10);
if (index == mPrevIndex) {
return;
} else {
if (index > 10) {
index = 10;
}
int res = getResources().getIdentifier(String.format("dropdown_anim_%02d", index), "drawable", getContext().getPackageName());
mHeaderImage.setImageResource(res);
mPrevIndex = index;
}
}
//正在刷新,就播放一下動畫
@Override
protected void refreshingImpl() {
if (mGifAnimation == null) {
mGifAnimation = new GifAnimation(mHeaderImage, mGifRes);
}
mGifAnimation.start();
}
//刷新結束,就停止動畫播放
@Override
protected void resetImpl() {
mHeaderImage.clearAnimation();
if (mGifAnimation != null) {
mGifAnimation.stop();
}
}
在PullToRefreshBase中能夠看到
/**
* Actions a Pull Event
*
* @return true if the Event has been handled, false if there has been no
* change
*/
private void pullEvent() {
final int newScrollValue;
final int itemDimension;
final float initialMotionValue, lastMotionValue;
switch (getPullToRefreshScrollDirection()) {
case HORIZONTAL:
initialMotionValue = mInitialMotionX;
lastMotionValue = mLastMotionX;
break;
case VERTICAL:
default:
initialMotionValue = mInitialMotionY;
lastMotionValue = mLastMotionY;
break;
}
//得到對應的高度
switch (mCurrentMode) {
case PULL_FROM_END:
newScrollValue = Math.round(Math.max(initialMotionValue
- lastMotionValue, 0)
/ FRICTION);
itemDimension = getFooterSize();
break;
case PULL_FROM_START:
default:
newScrollValue = Math.round(Math.min(initialMotionValue
- lastMotionValue, 0)
/ FRICTION);
itemDimension = getHeaderSize();
break;
}
setHeaderScroll(newScrollValue);
if (newScrollValue != 0 && !isRefreshing()) {
//通過當前移動的比例跟view自身的高度,計算出scale
float scale = Math.abs(newScrollValue) / (float) itemDimension;
//不管你設置的是何種mode。都會有對應的回調
switch (mCurrentMode) {
case PULL_FROM_END:
mFooterLayout.onPull(scale);
break;
case PULL_FROM_START:
default:
mHeaderLayout.onPull(scale);
break;
}
//前臺接口回調
if (mState != State.PULL_TO_REFRESH
&& itemDimension >= Math.abs(newScrollValue)) {
setState(State.PULL_TO_REFRESH);
} else if (mState == State.PULL_TO_REFRESH
&& itemDimension < Math.abs(newScrollValue)) {
setState(State.RELEASE_TO_REFRESH);
}
}
}
只是這邊有個情況要考慮下,就是之前我們能夠直接使用ptrDrawable、ptrDrawableStart、ptrDrawableEnd去替換上拉下拉不同的圖片
<!-- Drawable to use as Loading Indicator. Changes both Header and Footer. -->
<attr name="ptrDrawable" format="reference" />
<!-- Drawable to use as Loading Indicator in the Header View. Overrides value set in ptrDrawable. -->
<attr name="ptrDrawableStart" format="reference" />
<!-- Drawable to use as Loading Indicator in the Footer View. Overrides value set in ptrDrawable. -->
<attr name="ptrDrawableEnd" format="reference" />
可是通過如今代碼去構建view的話。這些自己定義屬性是不具備這個能力,所以要自行替換foot和head
// We need to create now layouts now
mHeaderLayout = createLoadingLayout(context, Mode.PULL_FROM_START, a);
mFooterLayout = createLoadingLayout(context, Mode.PULL_FROM_END, a);
//創建視圖的方法
protected LoadingLayout createLoadingLayout(Context context, Mode mode, TypedArray attrs) {
LoadingLayout layout = mLoadingAnimationStyle.createLoadingLayout(
context, mode, getPullToRefreshScrollDirection(), attrs);
layout.setVisibility(View.INVISIBLE);
return layout;
}
//能夠改造這個枚舉。返回須要的layout
public static enum AnimationStyle {
/**
* This is the default for Android-PullToRefresh. Allows you to use any
* drawable, which is automatically rotated and used as a Progress Bar.
*/
ROTATE,
/**
* This is the old default, and what is commonly used on iOS. Uses an
* arrow image which flips depending on where the user has scrolled.
*/
FLIP,
GIF;
static AnimationStyle getDefault() {
return ROTATE;
}
/**
* Maps an int to a specific mode. This is needed when saving state, or
* inflating the view from XML where the mode is given through a attr
* int.
*
* @param modeInt - int to map a Mode to
* @return Mode that modeInt maps to, or ROTATE by default.
*/
static AnimationStyle mapIntToValue(int modeInt) {
switch (modeInt) {
case 0x0:
default:
return ROTATE;
case 0x1:
return FLIP;
case 0x10:
return GIF;
}
}
LoadingLayout createLoadingLayout(Context context, Mode mode,
Orientation scrollDirection, TypedArray attrs) {
switch (this) {
case ROTATE:
default:
return new RotateLoadingLayout(context, mode, scrollDirection,
attrs);
case FLIP:
return new FlipLoadingLayout(context, mode, scrollDirection,
attrs);
case GIF:
return new GifLoadingLayout(context, mode, scrollDirection,
attrs);
}
}
}
僅僅有這樣才幹創建出不同的head與foot
OK,今天就說這麽多,有疑問大家一起交流
下拉刷新動畫研究