网上开源的有些有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; }
站点信息
- 文章2314
- 用户1336
- 访客11813325
每日一句
Let's seek joy in the simple, quiet moments.
让我们在简单宁静的时刻中寻找快乐。
让我们在简单宁静的时刻中寻找快乐。