Android UI- PullToRrefresh自訂下拉重新整理動畫,
Android UI- PullToRrefresh自訂下拉重新整理動畫
如果覺得本文不錯,麻煩投一票,2014年部落格之星投票地址:http://vote.blog.csdn.net/blogstar2014/details?username=wwj_748#content
本篇博文要給大家分享的是如何使用修改開源項目PullToRrefresh下拉重新整理的動畫,來滿足我們開發當中特定的需求,我們比較常見的一種下拉重新整理樣式可能是以下這種:
就是下拉式清單的時候兩個箭頭上下翻轉,更改日期文本和重新整理狀態,這種是最普遍的一種模式。
另外一種是旋轉動畫,就是重新整理的時候一個圈不停的旋轉,類似南方周末閱讀器(註:是小巫公司的一個產品,各位多多支援O(∩_∩)O):
github地址:https://github.com/devilWwj/Android-PullToRefresh
下載下來之後,import到工作空間,匯入到目標項目中去,不清楚如何匯入關聯項目的童鞋請自行百度。
我這裡要實現的一種效果是下拉重新整理時播放一個幀動畫
增加動畫列表:
<?xml version="1.0" encoding="utf-8"?><!-- 根標籤為animation-list,其中oneshot代表著是否只展示一遍,設定為false會不停的迴圈播放動畫根標籤下,通過item標籤對動畫中的每一個圖片進行聲明android:duration 表示展示所用的該圖片的時間長度 --><animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false" > <item android:drawable="@drawable/loading1" android:duration="150"></item> <item android:drawable="@drawable/loading2" android:duration="150"></item> <item android:drawable="@drawable/loading3" android:duration="150"></item> <item android:drawable="@drawable/loading4" android:duration="150"></item></animation-list>
修改下拉重新整理布局:
/PullToRefresh/res/layout/pull_to_refresh_header_simple.xml
<?xml version="1.0" encoding="utf-8"?><merge xmlns:android="http://schemas.android.com/apk/res/android" > <FrameLayout android:id="@+id/fl_inner" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingBottom="@dimen/header_footer_top_bottom_padding" android:paddingLeft="@dimen/header_footer_left_right_padding" android:paddingRight="@dimen/header_footer_left_right_padding" android:paddingTop="@dimen/header_footer_top_bottom_padding" > <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" > <ImageView android:id="@+id/pull_to_refresh_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:src="@drawable/loading1" /> </FrameLayout> </FrameLayout></merge>
增加自訂的載入布局
/PullToRefresh/src/com/handmark/pulltorefresh/library/internal/TweenAnimLoadingLayout.java
package com.handmark.pulltorefresh.library.internal;import com.handmark.pulltorefresh.library.R;import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode;import com.handmark.pulltorefresh.library.PullToRefreshBase.Orientation;import android.content.Context;import android.content.res.TypedArray;import android.graphics.drawable.AnimationDrawable;import android.graphics.drawable.Drawable;import android.view.View;/** * @date 2015/1/8 * @author wuwenjie * @desc 幀動畫載入布局 */public class TweenAnimLoadingLayout extends LoadingLayout {private AnimationDrawable animationDrawable;public TweenAnimLoadingLayout(Context context, Mode mode,Orientation scrollDirection, TypedArray attrs) {super(context, mode, scrollDirection, attrs);// 初始化mHeaderImage.setImageResource(R.drawable.refresh_anim);animationDrawable = (AnimationDrawable) mHeaderImage.getDrawable();}// 預設圖片@Overrideprotected int getDefaultDrawableResId() {return R.drawable.loading1;}@Overrideprotected void onLoadingDrawableSet(Drawable imageDrawable) {// NO-OP}@Overrideprotected void onPullImpl(float scaleOfLayout) {// NO-OP}// 拖動以重新整理@Overrideprotected void pullToRefreshImpl() {// NO-OP}// 正在重新整理時回調@Overrideprotected void refreshingImpl() {// 播放幀動畫animationDrawable.start();}// 釋放以重新整理@Overrideprotected void releaseToRefreshImpl() {// NO-OP}// 重新設定@Overrideprotected void resetImpl() {mHeaderImage.setVisibility(View.VISIBLE);mHeaderImage.clearAnimation();}}
我們只要修改開源項目中的LodingLayout代碼:
/PullToRefresh/src/com/handmark/pulltorefresh/library/internal/LoadingLayout.java
/******************************************************************************* * Copyright 2011, 2012 Chris Banes. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/package com.handmark.pulltorefresh.library.internal;import android.annotation.SuppressLint;import android.content.Context;import android.content.res.ColorStateList;import android.content.res.TypedArray;import android.graphics.Typeface;import android.graphics.drawable.AnimationDrawable;import android.graphics.drawable.Drawable;import android.text.TextUtils;import android.util.TypedValue;import android.view.Gravity;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.view.animation.Interpolator;import android.view.animation.LinearInterpolator;import android.widget.FrameLayout;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.ProgressBar;import android.widget.TextView;import com.handmark.pulltorefresh.library.ILoadingLayout;import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode;import com.handmark.pulltorefresh.library.PullToRefreshBase.Orientation;import com.handmark.pulltorefresh.library.R;@SuppressLint("ViewConstructor")public abstract class LoadingLayout extends FrameLayout implements ILoadingLayout {static final String LOG_TAG = "PullToRefresh-LoadingLayout";static final Interpolator ANIMATION_INTERPOLATOR = new LinearInterpolator();private FrameLayout mInnerLayout;protected final ImageView mHeaderImage;protected final ProgressBar mHeaderProgress;private boolean mUseIntrinsicAnimation;private final TextView mHeaderText;private final TextView mSubHeaderText;protected final Mode mMode;protected final Orientation mScrollDirection;private CharSequence mPullLabel;private CharSequence mRefreshingLabel;private CharSequence mReleaseLabel;public LoadingLayout(Context context, final Mode mode, final Orientation scrollDirection, TypedArray attrs) {super(context);mMode = mode;mScrollDirection = scrollDirection;switch (scrollDirection) {case HORIZONTAL:LayoutInflater.from(context).inflate(R.layout.pull_to_refresh_header_horizontal, this);break;case VERTICAL:default://LayoutInflater.from(context).inflate(R.layout.pull_to_refresh_header_vertical, this);// 修改代碼LayoutInflater.from(context).inflate(R.layout.pull_to_refresh_header_simple, this); break;}mInnerLayout = (FrameLayout) findViewById(R.id.fl_inner);mHeaderText = (TextView) mInnerLayout.findViewById(R.id.pull_to_refresh_text);mHeaderProgress = (ProgressBar) mInnerLayout.findViewById(R.id.pull_to_refresh_progress);mSubHeaderText = (TextView) mInnerLayout.findViewById(R.id.pull_to_refresh_sub_text);mHeaderImage = (ImageView) mInnerLayout.findViewById(R.id.pull_to_refresh_image);FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mInnerLayout.getLayoutParams();switch (mode) {case PULL_FROM_END:lp.gravity = scrollDirection == Orientation.VERTICAL ? Gravity.TOP : Gravity.LEFT;// Load in labelsmPullLabel = context.getString(R.string.pull_to_refresh_from_bottom_pull_label);mRefreshingLabel = context.getString(R.string.pull_to_refresh_from_bottom_refreshing_label);mReleaseLabel = context.getString(R.string.pull_to_refresh_from_bottom_release_label);break;case PULL_FROM_START:default:lp.gravity = scrollDirection == Orientation.VERTICAL ? Gravity.BOTTOM : Gravity.RIGHT;// Load in labelsmPullLabel = context.getString(R.string.pull_to_refresh_pull_label);mRefreshingLabel = context.getString(R.string.pull_to_refresh_refreshing_label);mReleaseLabel = context.getString(R.string.pull_to_refresh_release_label);break;}if (attrs.hasValue(R.styleable.PullToRefresh_ptrHeaderBackground)) {Drawable background = attrs.getDrawable(R.styleable.PullToRefresh_ptrHeaderBackground);if (null != background) {ViewCompat.setBackground(this, background);}}//if (attrs.hasValue(R.styleable.PullToRefresh_ptrHeaderTextAppearance)) {//TypedValue styleID = new TypedValue();//attrs.getValue(R.styleable.PullToRefresh_ptrHeaderTextAppearance, styleID);//setTextAppearance(styleID.data);//}//if (attrs.hasValue(R.styleable.PullToRefresh_ptrSubHeaderTextAppearance)) {//TypedValue styleID = new TypedValue();//attrs.getValue(R.styleable.PullToRefresh_ptrSubHeaderTextAppearance, styleID);//setSubTextAppearance(styleID.data);//}////// Text Color attrs need to be set after TextAppearance attrs//if (attrs.hasValue(R.styleable.PullToRefresh_ptrHeaderTextColor)) {//ColorStateList colors = attrs.getColorStateList(R.styleable.PullToRefresh_ptrHeaderTextColor);//if (null != colors) {//setTextColor(colors);//}//}//if (attrs.hasValue(R.styleable.PullToRefresh_ptrHeaderSubTextColor)) {//ColorStateList colors = attrs.getColorStateList(R.styleable.PullToRefresh_ptrHeaderSubTextColor);//if (null != colors) {//setSubTextColor(colors);//}//}// Try and get defined drawable from AttrsDrawable imageDrawable = null;if (attrs.hasValue(R.styleable.PullToRefresh_ptrDrawable)) {imageDrawable = attrs.getDrawable(R.styleable.PullToRefresh_ptrDrawable);}// Check Specific Drawable from Attrs, these overrite the generic// drawable attr aboveswitch (mode) {case PULL_FROM_START:default:if (attrs.hasValue(R.styleable.PullToRefresh_ptrDrawableStart)) {imageDrawable = attrs.getDrawable(R.styleable.PullToRefresh_ptrDrawableStart);} else if (attrs.hasValue(R.styleable.PullToRefresh_ptrDrawableTop)) {Utils.warnDeprecation("ptrDrawableTop", "ptrDrawableStart");imageDrawable = attrs.getDrawable(R.styleable.PullToRefresh_ptrDrawableTop);}break;case PULL_FROM_END:if (attrs.hasValue(R.styleable.PullToRefresh_ptrDrawableEnd)) {imageDrawable = attrs.getDrawable(R.styleable.PullToRefresh_ptrDrawableEnd);} else if (attrs.hasValue(R.styleable.PullToRefresh_ptrDrawableBottom)) {Utils.warnDeprecation("ptrDrawableBottom", "ptrDrawableEnd");imageDrawable = attrs.getDrawable(R.styleable.PullToRefresh_ptrDrawableBottom);}break;}// If we don't have a user defined drawable, load the defaultif (null == imageDrawable) {imageDrawable = context.getResources().getDrawable(getDefaultDrawableResId());}// Set Drawable, and save width/heightsetLoadingDrawable(imageDrawable);reset();}public final void setHeight(int height) {ViewGroup.LayoutParams lp = getLayoutParams();lp.height = height;requestLayout();}public final void setWidth(int width) {ViewGroup.LayoutParams lp = getLayoutParams();lp.width = width;requestLayout();}public final int getContentSize() {switch (mScrollDirection) {case HORIZONTAL:return mInnerLayout.getWidth();case VERTICAL:default:return mInnerLayout.getHeight();}}public final void hideAllViews() {//if (View.VISIBLE == mHeaderText.getVisibility()) {//mHeaderText.setVisibility(View.INVISIBLE);//}//if (View.VISIBLE == mHeaderProgress.getVisibility()) {//mHeaderProgress.setVisibility(View.INVISIBLE);//}//if (View.VISIBLE == mHeaderImage.getVisibility()) {//mHeaderImage.setVisibility(View.INVISIBLE);//}//if (View.VISIBLE == mSubHeaderText.getVisibility()) {//mSubHeaderText.setVisibility(View.INVISIBLE);//}}public final void onPull(float scaleOfLayout) {if (!mUseIntrinsicAnimation) {onPullImpl(scaleOfLayout);}}public final void pullToRefresh() {//if (null != mHeaderText) {//mHeaderText.setText(mPullLabel);//}// Now call the callbackpullToRefreshImpl();}public final void refreshing() {if (null != mHeaderText) {mHeaderText.setText(mRefreshingLabel);}if (mUseIntrinsicAnimation) {((AnimationDrawable) mHeaderImage.getDrawable()).start();} else {// Now call the callbackrefreshingImpl();}//if (null != mSubHeaderText) {//mSubHeaderText.setVisibility(View.GONE);//}}public final void releaseToRefresh() {//if (null != mHeaderText) {//mHeaderText.setText(mReleaseLabel);//}// Now call the callbackreleaseToRefreshImpl();}public final void reset() {//if (null != mHeaderText) {//mHeaderText.setText(mPullLabel);//}mHeaderImage.setVisibility(View.VISIBLE);if (mUseIntrinsicAnimation) {((AnimationDrawable) mHeaderImage.getDrawable()).stop();} else {// Now call the callbackresetImpl();}//if (null != mSubHeaderText) {//if (TextUtils.isEmpty(mSubHeaderText.getText())) {//mSubHeaderText.setVisibility(View.GONE);//} else {//mSubHeaderText.setVisibility(View.VISIBLE);//}//}}@Overridepublic void setLastUpdatedLabel(CharSequence label) {//setSubHeaderText(label);}@Overridepublic final void setLoadingDrawable(Drawable imageDrawable) {// Set DrawablemHeaderImage.setImageDrawable(imageDrawable);mUseIntrinsicAnimation = (imageDrawable instanceof AnimationDrawable);// Now call the callbackonLoadingDrawableSet(imageDrawable);}@Overridepublic void setPullLabel(CharSequence pullLabel) {mPullLabel = pullLabel;}@Overridepublic void setRefreshingLabel(CharSequence refreshingLabel) {mRefreshingLabel = refreshingLabel;}@Overridepublic void setReleaseLabel(CharSequence releaseLabel) {mReleaseLabel = releaseLabel;}@Overridepublic void setTextTypeface(Typeface tf) {mHeaderText.setTypeface(tf);}public final void showInvisibleViews() {//if (View.INVISIBLE == mHeaderText.getVisibility()) {//mHeaderText.setVisibility(View.VISIBLE);//}//if (View.INVISIBLE == mHeaderProgress.getVisibility()) {//mHeaderProgress.setVisibility(View.VISIBLE);//}if (View.INVISIBLE == mHeaderImage.getVisibility()) {mHeaderImage.setVisibility(View.VISIBLE);}//if (View.INVISIBLE == mSubHeaderText.getVisibility()) {//mSubHeaderText.setVisibility(View.VISIBLE);//}}/** * Callbacks for derivative Layouts */protected abstract int getDefaultDrawableResId();protected abstract void onLoadingDrawableSet(Drawable imageDrawable);protected abstract void onPullImpl(float scaleOfLayout);protected abstract void pullToRefreshImpl();protected abstract void refreshingImpl();protected abstract void releaseToRefreshImpl();protected abstract void resetImpl();private void setSubHeaderText(CharSequence label) {if (null != mSubHeaderText) {if (TextUtils.isEmpty(label)) {mSubHeaderText.setVisibility(View.GONE);} else {mSubHeaderText.setText(label);// Only set it to Visible if we're GONE, otherwise VISIBLE will// be set soonif (View.GONE == mSubHeaderText.getVisibility()) {mSubHeaderText.setVisibility(View.VISIBLE);}}}}private void setSubTextAppearance(int value) {if (null != mSubHeaderText) {mSubHeaderText.setTextAppearance(getContext(), value);}}private void setSubTextColor(ColorStateList color) {if (null != mSubHeaderText) {mSubHeaderText.setTextColor(color);}}private void setTextAppearance(int value) {if (null != mHeaderText) {mHeaderText.setTextAppearance(getContext(), value);}if (null != mSubHeaderText) {mSubHeaderText.setTextAppearance(getContext(), value);}}private void setTextColor(ColorStateList color) {if (null != mHeaderText) {mHeaderText.setTextColor(color);}if (null != mSubHeaderText) {mSubHeaderText.setTextColor(color);}}}
最後就不要讓我提供源碼了,筆者這裡只是提供一個思路,把重新整理的頭布局更改為我們的自訂布局就行了。
最終效果是下拉重新整理的時候會有一個不停在閃的燈,這裡沒有錄製gif動畫,只提供一張吧: