Pull to refresh implemention
来源:互联网 发布:dota三大后期 知乎 编辑:程序博客网 时间:2024/04/28 11:20
pull to refresh 源于IPhone,现在很多项目都有实现,在github 有个开源的Pull To Refresh 项目,看过感觉代码太重了,日常项目中要是用它有点杀鸡用牛刀大才小用了
其实网上早已有了它简易的实现,看代码:
该控件特点:
1.子控件必须是一个ScrollView或ListView;
2.支持自定义下拉布局;
3.自定义下拉布局可以不用处理下拉的各种状态(只需要实现几个接口即可),也可以自己处理各种下拉的状态。
先来看看效果图:
上代码:
首先看如何使用:
1.使用的布局:
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" >
- <com.example.pulldown.PullDownScrollView
- android:id="@+id/refresh_root"
- android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1"
- android:background="#161616"
- android:orientation="vertical" >
- <ScrollView
- android:id="@+id/scrollview"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:scrollbars="none" >
- <LinearLayout
- android:id="@+id/mainView"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:background="#1f1f1f"
- android:orientation="vertical" >
- <!-- 自已的布局 -->
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="10dip"
- android:gravity="center"
- android:text="@string/hello_world"
- android:textColor="@android:color/white"
- android:textSize="18sp" />
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="10dip"
- android:gravity="center"
- android:text="@string/hello_world"
- android:textColor="@android:color/white"
- android:textSize="18sp" />
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="10dip"
- android:gravity="center"
- android:text="@string/hello_world"
- android:textColor="@android:color/white"
- android:textSize="18sp" />
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="10dip"
- android:gravity="center"
- android:text="@string/hello_world"
- android:textColor="@android:color/white"
- android:textSize="18sp" />
- </LinearLayout>
- </ScrollView>
- </com.example.pulldown.PullDownScrollView>
- lt;/LinearLayout>
2.UI使用:
首先,Activity实现接口:
implements RefreshListener
部分代码如下:
- package com.example.pulldown;
- import com.example.pulldown.PullDownScrollView.RefreshListener;
- import android.os.Bundle;
- import android.os.Handler;
- import android.app.Activity;
- import android.view.Menu;
- public class MainActivity extends Activity implements RefreshListener{
- private PullDownScrollView mPullDownScrollView;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- mPullDownScrollView = (PullDownScrollView) findViewById(R.id.refresh_root);
- mPullDownScrollView.setRefreshListener(this);
- mPullDownScrollView.setPullDownElastic(new PullDownElasticImp(this));
- }
- @Override
- public void onRefresh(PullDownScrollView view) {
- new Handler().postDelayed(new Runnable() {
- @Override
- public void run() {
- // TODO Auto-generated method stub
- mPullDownScrollView.finishRefresh("上次刷新时间:12:23");
- }
- }, 2000);
- }
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.activity_main, menu);
- return true;
- }
- }
3.再来看看控件代码:
- import android.content.Context;
- import android.util.AttributeSet;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.animation.LinearInterpolator;
- import android.view.animation.RotateAnimation;
- import android.widget.AbsListView;
- import android.widget.LinearLayout;
- import android.widget.ScrollView;
- /**
- * @author xwangly@163.com
- * @date 2013-7-9
- *
- */
- public class PullDownScrollView extends LinearLayout {
- private static final String TAG = "PullDownScrollView";
- private int refreshTargetTop = -60;
- private int headContentHeight;
- private RefreshListener refreshListener;
- private RotateAnimation animation;
- private RotateAnimation reverseAnimation;
- private final static int RATIO = 2;
- private int preY = 0;
- private boolean isElastic = false;
- private int startY;
- private int state;
- private String note_release_to_refresh = "松开更新";
- private String note_pull_to_refresh = "下拉刷新";
- private String note_refreshing = "正在更新...";
- private IPullDownElastic mElastic;
- public PullDownScrollView(Context context) {
- super(context);
- init();
- }
- public PullDownScrollView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
- private void init() {
- animation = new RotateAnimation(0, -180,
- RotateAnimation.RELATIVE_TO_SELF, 0.5f,
- RotateAnimation.RELATIVE_TO_SELF, 0.5f);
- animation.setInterpolator(new LinearInterpolator());
- animation.setDuration(250);
- animation.setFillAfter(true);
- reverseAnimation = new RotateAnimation(-180, 0,
- RotateAnimation.RELATIVE_TO_SELF, 0.5f,
- RotateAnimation.RELATIVE_TO_SELF, 0.5f);
- reverseAnimation.setInterpolator(new LinearInterpolator());
- reverseAnimation.setDuration(200);
- reverseAnimation.setFillAfter(true);
- }
- /**
- * 刷新监听
- * @param listener
- */
- public void setRefreshListener(RefreshListener listener) {
- this.refreshListener = listener;
- }
- /**
- * 下拉布局
- * @param elastic
- */
- public void setPullDownElastic(IPullDownElastic elastic) {
- mElastic = elastic;
- headContentHeight = mElastic.getElasticHeight();
- refreshTargetTop = - headContentHeight;
- LayoutParams lp = new LinearLayout.LayoutParams(
- LayoutParams.FILL_PARENT, headContentHeight);
- lp.topMargin = refreshTargetTop;
- addView(mElastic.getElasticLayout(), 0, lp);
- }
- /**
- * 设置更新提示语
- * @param pullToRefresh 下拉刷新提示语
- * @param releaseToRefresh 松开刷新提示语
- * @param refreshing 正在刷新提示语
- */
- public void setRefreshTips(String pullToRefresh, String releaseToRefresh, String refreshing) {
- note_pull_to_refresh = pullToRefresh;
- note_release_to_refresh = releaseToRefresh;
- note_refreshing = refreshing;
- }
- /*
- * 该方法一般和ontouchEvent 一起用 (non-Javadoc)
- *
- * @see
- * android.view.ViewGroup#onInterceptTouchEvent(android.view.MotionEvent)
- */
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- Logger.d(TAG, "onInterceptTouchEvent");
- printMotionEvent(ev);
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- preY = (int) ev.getY();
- }
- if (ev.getAction() == MotionEvent.ACTION_MOVE) {
- Logger.d(TAG, "isElastic:" + isElastic + " canScroll:"+ canScroll() + " ev.getY() - preY:"+(ev.getY() - preY));
- if (!isElastic && canScroll()
- && (int) ev.getY() - preY >= headContentHeight / (3*RATIO)
- && refreshListener != null && mElastic != null) {
- isElastic = true;
- startY = (int) ev.getY();
- Logger.i(TAG, "在move时候记录下位置startY:" + startY);
- return true;
- }
- }
- return super.onInterceptTouchEvent(ev);
- }
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- Logger.d(TAG, "onTouchEvent");
- printMotionEvent(event);
- handleHeadElastic(event);
- return super.onTouchEvent(event);
- }
- private void handleHeadElastic(MotionEvent event) {
- if (refreshListener != null && mElastic != null) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- Logger.i(TAG, "down");
- break;
- case MotionEvent.ACTION_UP:
- Logger.i(TAG, "up");
- if (state != IPullDownElastic.REFRESHING && isElastic) {
- if (state == IPullDownElastic.DONE) {
- // 什么都不做
- setMargin(refreshTargetTop);
- }
- if (state == IPullDownElastic.PULL_To_REFRESH) {
- state = IPullDownElastic.DONE;
- setMargin(refreshTargetTop);
- changeHeaderViewByState(state, false);
- Logger.i(TAG, "由下拉刷新状态,到done状态");
- }
- if (state == IPullDownElastic.RELEASE_To_REFRESH) {
- state = IPullDownElastic.REFRESHING;
- setMargin(0);
- changeHeaderViewByState(state, false);
- onRefresh();
- Logger.i(TAG, "由松开刷新状态,到done状态");
- }
- }
- isElastic = false;
- break;
- case MotionEvent.ACTION_MOVE:
- Logger.i(TAG, "move");
- int tempY = (int) event.getY();
- if (state != IPullDownElastic.REFRESHING && isElastic) {
- // 可以松手去刷新了
- if (state == IPullDownElastic.RELEASE_To_REFRESH) {
- if (((tempY - startY) / RATIO < headContentHeight)
- && (tempY - startY) > 0) {
- state = IPullDownElastic.PULL_To_REFRESH;
- changeHeaderViewByState(state, true);
- Logger.i(TAG, "由松开刷新状态转变到下拉刷新状态");
- } else if (tempY - startY <= 0) {
- state = IPullDownElastic.DONE;
- changeHeaderViewByState(state, false);
- Logger.i(TAG, "由松开刷新状态转变到done状态");
- }
- }
- if (state == IPullDownElastic.DONE) {
- if (tempY - startY > 0) {
- state = IPullDownElastic.PULL_To_REFRESH;
- changeHeaderViewByState(state, false);
- }
- }
- if (state == IPullDownElastic.PULL_To_REFRESH) {
- // 下拉到可以进入RELEASE_TO_REFRESH的状态
- if ((tempY - startY) / RATIO >= headContentHeight) {
- state = IPullDownElastic.RELEASE_To_REFRESH;
- changeHeaderViewByState(state, false);
- Logger.i(TAG, "由done或者下拉刷新状态转变到松开刷新");
- } else if (tempY - startY <= 0) {
- state = IPullDownElastic.DONE;
- changeHeaderViewByState(state, false);
- Logger.i(TAG, "由DOne或者下拉刷新状态转变到done状态");
- }
- }
- if (tempY - startY > 0) {
- setMargin((tempY - startY)/2 + refreshTargetTop);
- }
- }
- break;
- }
- }
- }
- /**
- *
- */
- private void setMargin(int top) {
- LinearLayout.LayoutParams lp = (LayoutParams) mElastic.getElasticLayout()
- .getLayoutParams();
- lp.topMargin = top;
- // 修改后刷新
- mElastic.getElasticLayout().setLayoutParams(lp);
- mElastic.getElasticLayout().invalidate();
- }
- private void changeHeaderViewByState(int state, boolean isBack) {
- mElastic.changeElasticState(state, isBack);
- switch (state) {
- case IPullDownElastic.RELEASE_To_REFRESH:
- mElastic.showArrow(View.VISIBLE);
- mElastic.showProgressBar(View.GONE);
- mElastic.showLastUpdate(View.VISIBLE);
- mElastic.setTips(note_release_to_refresh);
- mElastic.clearAnimation();
- mElastic.startAnimation(animation);
- Logger.i(TAG, "当前状态,松开刷新");
- break;
- case IPullDownElastic.PULL_To_REFRESH:
- mElastic.showArrow(View.VISIBLE);
- mElastic.showProgressBar(View.GONE);
- mElastic.showLastUpdate(View.VISIBLE);
- mElastic.setTips(note_pull_to_refresh);
- mElastic.clearAnimation();
- // 是由RELEASE_To_REFRESH状态转变来的
- if (isBack) {
- mElastic.startAnimation(reverseAnimation);
- }
- Logger.i(TAG, "当前状态,下拉刷新");
- break;
- case IPullDownElastic.REFRESHING:
- mElastic.showArrow(View.GONE);
- mElastic.showProgressBar(View.VISIBLE);
- mElastic.showLastUpdate(View.GONE);
- mElastic.setTips(note_refreshing);
- mElastic.clearAnimation();
- Logger.i(TAG, "当前状态,正在刷新...");
- break;
- case IPullDownElastic.DONE:
- mElastic.showProgressBar(View.GONE);
- mElastic.clearAnimation();
- // arrowImageView.setImageResource(R.drawable.goicon);
- // tipsTextview.setText("下拉刷新");
- // lastUpdatedTextView.setVisibility(View.VISIBLE);
- Logger.i(TAG, "当前状态,done");
- break;
- }
- }
- private void onRefresh() {
- // downTextView.setVisibility(View.GONE);
- // scroller.startScroll(0, i, 0, 0 - i);
- // invalidate();
- if (refreshListener != null) {
- refreshListener.onRefresh(this);
- }
- }
- /**
- *
- */
- @Override
- public void computeScroll() {
- // if (scroller.computeScrollOffset()) {
- // int i = this.scroller.getCurrY();
- // LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) this.refreshView
- // .getLayoutParams();
- // int k = Math.max(i, refreshTargetTop);
- // lp.topMargin = k;
- // this.refreshView.setLayoutParams(lp);
- // this.refreshView.invalidate();
- // invalidate();
- // }
- }
- /**
- * 结束刷新事件,UI刷新完成后必须回调此方法
- * @param text 一般传入:“上次更新时间:12:23”
- */
- public void finishRefresh(String text) {
- if (mElastic == null) {
- Logger.d(TAG, "finishRefresh mElastic:" + mElastic);
- return;
- }
- state = IPullDownElastic.DONE;
- mElastic.setLastUpdateText(text);
- changeHeaderViewByState(state,false);
- Logger.i(TAG, "执行了=====finishRefresh");
- mElastic.showArrow(View.VISIBLE);
- mElastic.showLastUpdate(View.VISIBLE);
- setMargin(refreshTargetTop);
- // scroller.startScroll(0, i, 0, refreshTargetTop);
- // invalidate();
- }
- private boolean canScroll() {
- View childView;
- if (getChildCount() > 1) {
- childView = this.getChildAt(1);
- if (childView instanceof AbsListView) {
- int top = ((AbsListView) childView).getChildAt(0).getTop();
- int pad = ((AbsListView) childView).getListPaddingTop();
- if ((Math.abs(top - pad)) < 3
- && ((AbsListView) childView).getFirstVisiblePosition() == 0) {
- return true;
- } else {
- return false;
- }
- } else if (childView instanceof ScrollView) {
- if (((ScrollView) childView).getScrollY() == 0) {
- return true;
- } else {
- return false;
- }
- }
- }
- return canScroll(this);
- }
- /**
- * 子类重写此方法可以兼容其它的子控件,目前只兼容AbsListView和ScrollView
- * @param view
- * @return
- */
- public boolean canScroll(PullDownScrollView view) {
- return false;
- }
- private void printMotionEvent(MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- Logger.d(TAG, "down");
- break;
- case MotionEvent.ACTION_MOVE:
- Logger.d(TAG, "move");
- break;
- case MotionEvent.ACTION_UP:
- Logger.d(TAG, "up");
- default:
- break;
- }
- }
- /**
- * 刷新监听接口
- */
- public interface RefreshListener {
- public void onRefresh(PullDownScrollView view);
- }
- }
4.接口:
- import android.view.View;
- import android.view.animation.Animation;
- /**
- * @author xwangly@163.com
- * @date 2013-7-10
- * 下拉控件接口
- */
- public interface IPullDownElastic {
- public final static int RELEASE_To_REFRESH = 0;
- public final static int PULL_To_REFRESH = 1;
- public final static int REFRESHING = 2;
- public final static int DONE = 3;
- public View getElasticLayout();
- public int getElasticHeight();
- public void showArrow(int visibility);
- public void startAnimation(Animation animation);
- public void clearAnimation();
- public void showProgressBar(int visibility);
- public void setTips(String tips);
- public void showLastUpdate(int visibility);
- public void setLastUpdateText(String text);
- /**
- * 可以不用实现此方法,PullDownScrollView会处理ElasticLayout布局中的状态
- * 如果需要特殊处理,可以实现此方法进行处理
- *
- * @param state @see RELEASE_To_REFRESH
- * @param isBack 是否是松开回退
- */
- public void changeElasticState(int state, boolean isBack);
- }
5.默认实现:
- import android.content.Context;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.animation.Animation;
- import android.widget.ImageView;
- import android.widget.ProgressBar;
- import android.widget.TextView;
- /**
- * @author xwangly@163.com
- * @date 2013-7-10
- * 默认下拉控件布局实现
- */
- public class PullDownElasticImp implements IPullDownElastic {
- private View refreshView;
- private ImageView arrowImageView;
- private int headContentHeight;
- private ProgressBar progressBar;
- private TextView tipsTextview;
- private TextView lastUpdatedTextView;
- private Context mContext;
- public PullDownElasticImp(Context context) {
- mContext = context;
- init();
- }
- private void init() {
- // 刷新视图顶端的的view
- refreshView = LayoutInflater.from(mContext).inflate(
- R.layout.refresh_top_item, null);
- // 指示器view
- arrowImageView = (ImageView) refreshView
- .findViewById(R.id.head_arrowImageView);
- // 刷新bar
- progressBar = (ProgressBar) refreshView
- .findViewById(R.id.head_progressBar);
- // 下拉显示text
- tipsTextview = (TextView) refreshView.findViewById(R.id.refresh_hint);
- // 下来显示时间
- lastUpdatedTextView = (TextView) refreshView
- .findViewById(R.id.refresh_time);
- headContentHeight = Utils.dip2px(mContext, 50);
- }
- /**
- * @return
- *
- */
- @Override
- public View getElasticLayout() {
- return refreshView;
- }
- /**
- * @return
- *
- */
- @Override
- public int getElasticHeight() {
- return headContentHeight;
- }
- /**
- * @param show
- *
- */
- @Override
- public void showArrow(int visibility) {
- arrowImageView.setVisibility(visibility);
- }
- /**
- * @param animation
- *
- */
- @Override
- public void startAnimation(Animation animation) {
- arrowImageView.startAnimation(animation);
- }
- /**
- *
- *
- */
- @Override
- public void clearAnimation() {
- arrowImageView.clearAnimation();
- }
- /**
- * @param show
- *
- */
- @Override
- public void showProgressBar(int visibility) {
- progressBar.setVisibility(visibility);
- }
- /**
- * @param tips
- *
- */
- @Override
- public void setTips(String tips) {
- tipsTextview.setText(tips);
- }
- /**
- * @param show
- *
- */
- @Override
- public void showLastUpdate(int visibility) {
- lastUpdatedTextView.setVisibility(visibility);
- }
- /**
- * @param text
- *
- */
- public void setLastUpdateText(String text) {
- lastUpdatedTextView.setText(text);
- }
- /**
- * @param state
- * @param isBack
- *
- */
- @Override
- public void changeElasticState(int state, boolean isBack) {
- // TODO Auto-generated method stub
- }
- }
6.默认实现的布局:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="-50.0dip"
- android:orientation="vertical" >
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="0.0dip"
- android:layout_weight="1.0"
- android:gravity="center"
- android:orientation="horizontal" >
- <!-- 箭头图像、进度条 -->
- <FrameLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_centerVertical="true"
- android:layout_marginLeft="30dip" >
- <!-- 箭头 -->
- <ImageView
- android:id="@+id/head_arrowImageView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:src="@drawable/goicon" />
- <!-- 进度条 -->
- <ProgressBar
- android:id="@+id/head_progressBar"
- style="@android:style/Widget.ProgressBar.Small.Inverse"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:visibility="gone" />
- </FrameLayout>
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:gravity="center"
- android:orientation="vertical" >
- <!-- 提示 -->
- <TextView
- android:id="@+id/refresh_hint"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="下拉刷新"
- android:textColor="#f2f2f2"
- android:textSize="16sp" />
- <!-- 最近更新 -->
- <TextView
- android:id="@+id/refresh_time"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="上次更新"
- android:textColor="#b89766"
- android:textSize="10sp" />
- </LinearLayout>
- </LinearLayout>
- </LinearLayout>
6.图片资源:
@drawable/goicon
完结
- Pull to refresh implemention
- ListView pull to refresh
- Pull to Refresh下拉刷新
- Pull-To-Refresh使用详解
- android-Ultra-Pull-To-Refresh
- Android-Ultra-Pull-To-Refresh
- How to implement Android Pull-to-Refresh
- iscroll5 html5 pull to refresh, pull to load 完整demo
- android Pull-to-refresh 动画实现
- Android pull to Refresh 导入出错?
- android-Ultra-Pull-to-Refresh下拉刷新
- pull to refresh的使用心得
- android-Ultra-Pull-To-Refresh 源码解析
- android-Ultra-Pull-To-Refresh 源码解析
- android-Ultra-Pull-To-Refresh源码分析
- android-Ultra-Pull-To-Refresh 源码解析
- 【框架学习】【android-Ultra-Pull-To-Refresh】
- android-Ultra-Pull-To-Refresh 源码解析
- 几种经典的网络服务器架构模型的分析与比较
- [PHP解算法题]最小操作数
- Spring基础
- C与C++头文件
- MYSQL常用命令
- Pull to refresh implemention
- 随机采样系列2:0-1均匀分布
- 在控制台程序中输出彩色字符
- 递归(1)
- uva 10285 Longest Run on a Snowboard(dp+记忆化搜索)
- lustre安装
- Hibernate在删除一个游离对象的时候,是不会更新该游离对象的
- Android newIntent
- CGI 文件下载