网上开源的有些有BUG,这里已经修正了一些小问题。贴出代码和大家共享。
PullToRefreshLayout.java
vw_update_bar.xml
demens文件
PullToRefreshLayout.java
import android.content.Context; import android.text.Html; import android.util.AttributeSet; import android.view.GestureDetector; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.animation.LinearInterpolator; import android.view.animation.RotateAnimation; import android.widget.AdapterView; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.Scroller; import android.widget.TextView; public class PullToRefreshLayout extends FrameLayout implements GestureDetector.OnGestureListener { public static final int STATE_CLOSE = 1; public static final int STATE_OPEN = 2; public static final int STATE_OPEN_MAX = 4; public static final int STATE_OPEN_MAX_RELEASE = 5; public static final int STATE_OPEN_RELEASE = 3; public static final int STATE_UPDATE = 6; public static final int STATE_UPDATE_SCROLL = 7; private static int MAXHEIGHT = 80; private ImageView mArrow; private String mDate; private GestureDetector mDetector; private Flinger mFlinger; private boolean mIsAutoScroller; private int mPading; private ProgressBar mProgressBar; private int mState; private TextView mTitle; private FrameLayout mUpdateContent; private UpdateHandle mUpdateHandle; private RotateAnimation mFlipAnimation; private RotateAnimation mReverseFlipAnimation; private String tag = "<font color="#666666"><b><big>"; private String end_tag = "</font></b></big><br/>"; private String relese; private String pulldown; private String loadding; private String last_time; private boolean mIsOpen = true; public PullToRefreshLayout(Context context, AttributeSet attrs) { super(context, attrs); relese = genString("释放立即刷新"); pulldown = genString("下拉刷新"); loadding = genString("正在刷新,请稍后..."); last_time = "上次刷新时间:"; addUpdateBar(); init(); } private String genString(String text) { StringBuffer buffer = new StringBuffer(tag); buffer.append(text); buffer.append(end_tag); return buffer.toString(); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { boolean isAuto = mIsAutoScroller; mDetector.onTouchEvent(ev); switch (ev.getAction()) { case MotionEvent.ACTION_MOVE: int y = getChildAt(1).getTop(); if (y != 0) { updateView(); } break; case MotionEvent.ACTION_UP: if (mState == STATE_OPEN) { mState = STATE_OPEN_RELEASE; } if (mState == STATE_OPEN_MAX) { mState = STATE_OPEN_MAX_RELEASE; } release(); break; } if (mState != STATE_UPDATE) { isAuto = super.dispatchTouchEvent(ev); } else { return super.dispatchTouchEvent(ev); } int y = getChildAt(1).getTop(); if (y != 0) { ev.setAction(MotionEvent.ACTION_CANCEL); super.dispatchTouchEvent(ev); updateView(); } return isAuto; } private void init() { mDetector = new GestureDetector(this); mFlinger = new Flinger(getContext()); mState = STATE_CLOSE; setDrawingCacheEnabled(true); setClipChildren(true); mDetector.setIsLongpressEnabled(false); MAXHEIGHT = (int) getContext().getResources().getDimension( R.dimen.size_updatebar_content_height); } private void updateView() { View view1 = getChildAt(0); View view2 = getChildAt(1); if (mDate == null) mDate = ""; switch (mState) { case STATE_CLOSE: if (view1.getVisibility() != View.INVISIBLE) view1.setVisibility(View.INVISIBLE); case STATE_OPEN: case STATE_OPEN_RELEASE: { // STATE_OPEN int offset = -mPading - view2.getTop(); view2.offsetTopAndBottom(offset); if (view1.getVisibility() != View.VISIBLE) view1.setVisibility(View.VISIBLE); int y1 = view1.getTop();// 相对于父窗口的顶部大小 offset = -MAXHEIGHT - mPading - y1; view1.offsetTopAndBottom(offset); StringBuilder builder = new StringBuilder(pulldown); builder.append(last_time); builder.append(mDate); mTitle.setText(Html.fromHtml(builder.toString())); mProgressBar.setVisibility(View.INVISIBLE); mArrow.setVisibility(View.VISIBLE); if (!mIsOpen) { mIsOpen = true; mArrow.setAnimation(mReverseFlipAnimation); mReverseFlipAnimation.start(); } break; } case STATE_OPEN_MAX_RELEASE: case STATE_OPEN_MAX: { int offset = -mPading - view2.getTop(); view2.offsetTopAndBottom(offset); if (view1.getVisibility() != View.VISIBLE) view1.setVisibility(View.VISIBLE); offset = -MAXHEIGHT - mPading - view1.getTop(); view1.offsetTopAndBottom(offset); StringBuilder builder = new StringBuilder(relese); builder.append(last_time); builder.append(mDate); mTitle.setText(Html.fromHtml(builder.toString())); mProgressBar.setVisibility(View.INVISIBLE); mArrow.setVisibility(View.VISIBLE); if (mIsOpen) { mIsOpen = false; mArrow.setAnimation(mFlipAnimation); mFlipAnimation.start(); } break; } case STATE_UPDATE: // STATE_UPDATE { int offset = -mPading - view2.getTop(); view2.offsetTopAndBottom(offset); if (mProgressBar.getVisibility() != View.VISIBLE) mProgressBar.setVisibility(View.VISIBLE); if (mArrow.getVisibility() != View.INVISIBLE) mArrow.setVisibility(View.INVISIBLE); StringBuffer builder = new StringBuffer(loadding); builder.append(last_time); builder.append(mDate); mTitle.setText(Html.fromHtml(builder.toString())); offset = -MAXHEIGHT - mPading - view1.getTop(); view1.offsetTopAndBottom(offset); if (view1.getVisibility() != View.VISIBLE) view1.setVisibility(View.VISIBLE); mProgressBar.setVisibility(View.VISIBLE); mArrow.setVisibility(View.GONE); mArrow.clearAnimation(); break; } } invalidate(); } private void addUpdateBar() { Context context = getContext(); mFlipAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); mFlipAnimation.setInterpolator(new LinearInterpolator()); mFlipAnimation.setDuration(200); mFlipAnimation.setFillAfter(true); mReverseFlipAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); mReverseFlipAnimation.setInterpolator(new LinearInterpolator()); mReverseFlipAnimation.setDuration(200); mReverseFlipAnimation.setFillAfter(true); View view = LayoutInflater.from(context).inflate( R.layout.vw_update_bar, null); view.setVisibility(View.INVISIBLE); addView(view); mArrow = new ImageView(context); FrameLayout.LayoutParams mArrowParams = new FrameLayout.LayoutParams( FrameLayout.LayoutParams.FILL_PARENT, FrameLayout.LayoutParams.FILL_PARENT); ImageView.ScaleType localScaleType = ImageView.ScaleType.FIT_CENTER; mArrow.setScaleType(localScaleType); mArrow.setLayoutParams(mArrowParams); mArrow.setImageResource(R.drawable.arrow_down); mUpdateContent = (FrameLayout) getChildAt(0).findViewById( R.id.iv_content); mUpdateContent.addView(mArrow); FrameLayout.LayoutParams mProgressBarParams = new FrameLayout.LayoutParams( FrameLayout.LayoutParams.FILL_PARENT, FrameLayout.LayoutParams.FILL_PARENT); mProgressBarParams.gravity = Gravity.CENTER_VERTICAL; mProgressBar = new ProgressBar(context); int padding = getResources().getDimensionPixelSize( R.dimen.size_updatebar_padding); mProgressBar.setPadding(padding, padding, padding, padding); mProgressBar.setLayoutParams(mProgressBarParams); mUpdateContent.addView(mProgressBar); mTitle = (TextView) findViewById(R.id.tv_title); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { // TODO Auto-generated method stub int mtop = -MAXHEIGHT - mPading; getChildAt(0).layout(0, mtop, getMeasuredWidth(), -mPading); int mbottom = getMeasuredHeight() - mPading; getChildAt(1).layout(0, -mPading, getMeasuredWidth(), mbottom); } public void endUpdate(String timeFomat) { mDate = timeFomat; if (mPading != 0) { mState = STATE_CLOSE; scrollToClose(); } } @Override public void onShowPress(MotionEvent e) { // TODO Auto-generated method stub } @Override public void onLongPress(MotionEvent e) { // TODO Auto-generated method stub } @Override public boolean onDown(MotionEvent e) { return false; } @Override public boolean onSingleTapUp(MotionEvent e) { return false; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { AdapterView<?> adapterView = (AdapterView<?>) getChildAt(1); int k = adapterView.getCount(); if (k == 0) return false; k = adapterView.getFirstVisiblePosition();// 获取第一个显示项目的position if (k == 0) { int t = adapterView.getChildAt(0).getTop(); if (t != 0) { return false; } else { mPading = (int) (mPading + distanceY / 2); if (mPading > 0) mPading = 0; if (Math.abs(mPading) <= MAXHEIGHT) { mState = STATE_OPEN; } else { mState = STATE_OPEN_MAX; } updateView(); } } return false; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return false; } private boolean release() { int tempStatus = STATE_OPEN_MAX_RELEASE; if (mPading >= 0) { return true; } switch (mState) { case STATE_OPEN_RELEASE: if (Math.abs(mPading) < MAXHEIGHT) { tempStatus = STATE_OPEN_MAX_RELEASE; mState = tempStatus; } scrollToClose(); break; case STATE_OPEN_MAX_RELEASE: mState = tempStatus; scrollToUpdate(); break; } return false; } private void scrollToClose() { mFlinger.startUsingDistance(-mPading, 2000); } private void scrollToUpdate() { mFlinger.startUsingDistance(-mPading - MAXHEIGHT, 1000); } class Flinger implements Runnable { private int mLastFlingX; private Scroller mScroller; public Flinger(Context context) { mScroller = new Scroller(context); } private void startCommon() { removeCallbacks(this); } public void run() { boolean auto = Math.abs(mPading) != MAXHEIGHT; boolean compute = mScroller.computeScrollOffset(); move(mLastFlingX - mScroller.getCurrX(), auto); updateView(); if (compute) { mLastFlingX = mScroller.getCurrX(); post(this); } else { mIsAutoScroller = auto; removeCallbacks(this); } } public void startUsingDistance(int padding, int duration) { int i = 0; if (padding == 0) padding = -1; startCommon(); mLastFlingX = i; mScroller.startScroll(i, 0, -padding, 0, duration); mIsAutoScroller = true; post(this); } } /** * 释放的时候使用 */ public void move(float f, boolean bool) { if (mState != STATE_CLOSE) { if (!bool) { // 刷新 if (mState == STATE_OPEN_MAX_RELEASE) { mState = STATE_UPDATE; if (mUpdateHandle != null) { mUpdateHandle.onUpdate(); } } } if (mState == STATE_OPEN_MAX_RELEASE || mState == STATE_OPEN_RELEASE) { mPading += f; } } else { if (mIsAutoScroller) { mPading += f; } } } public abstract interface UpdateHandle { public abstract void onUpdate(); } public void setUpdateDate(String timeFomat) { mDate = timeFomat; } public void setUpdateHandle(UpdateHandle paramUpdateHandle) { mUpdateHandle = paramUpdateHandle; } public void updateWithoutOffset() { mState = STATE_UPDATE_SCROLL; invalidate(); } }
vw_update_bar.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="@dimen/size_updatebar_padding" android:background="#FFF4F4F4" android:orientation="vertical" > <FrameLayout android:layout_width="match_parent" android:layout_height="@dimen/size_updatebar_content_height" android:background="#FFF4F4F4" > <TextView android:id="@+id/tv_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:background="#FFF4F4F4" android:gravity="center" android:textSize="12sp" > </TextView> <FrameLayout android:id="@+id/iv_content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="15.0dip" > </FrameLayout> </FrameLayout> <ImageView android:layout_width="fill_parent" android:layout_height="1.0dip" android:contentDescription="@string/app_name" android:scaleType="fitXY" android:src="@drawable/divider_horizontal_timeline" > </ImageView> </LinearLayout>
demens文件
<dimen name="size_updatebar_content_height">48dp</dimen> <dimen name="size_updatebar_padding">12dp</dimen>使用方法:
refreshLayout = (PullToRefreshLayout) findViewById(R.id.pull_refresh); refreshLayout.setUpdateHandle(new UpdateHandle() { @Override public void onUpdate() { // TODO Auto-generated method stub new TaskThread() { @Override public void process() throws Exception { // TODO Auto-generated method stub sleep(3000); refreshLayout.endUpdate(Tools.newDateTime()); } }.start(); } });布局代码:
<com.PullToRefreshLayout android:id="@+id/pull_refresh" android:layout_width="match_parent" android:layout_height="wrap_content" > <ExpandableListView android:id="@+id/expand_list" android:layout_width="match_parent" android:layout_height="match_parent" android:cacheColorHint="@null" android:groupIndicator="@null" android:listSelector="@drawable/default_selector" android:scrollbars="none" > </ExpandableListView> </com.PullToRefreshLayout>效果图:
收藏的用户(0) X
正在加载信息~
推荐阅读
最新回复 (1)
- 今天再用到这个控件的时候,出现类型转换异常,找了下原因.之前我用的是ExpandListView,而这次用的是相对布局,所以出错了.这里只需要把代码简单改下.
@Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { ViewGroup layout = (ViewGroup) getChildAt(1); int k = layout.getChildCount(); if (k == 0) return false; k = layout.getChildAt(0).getTop();// 获取第一个显示项目的position if (k == 0) { int t = layout.getChildAt(0).getTop(); if (t != 0) { return false; } else { mPading = (int) (mPading + distanceY / 2); if (mPading > 0) mPading = 0; if (Math.abs(mPading) <= MAXHEIGHT) { mState = STATE_OPEN; } else { mState = STATE_OPEN_MAX; } updateView(); } } return false; }
站点信息
- 文章2295
- 用户1336
- 访客10465927
每日一句
Wisdom begins in wonder.
智慧始于好奇。
智慧始于好奇。
新会员