Android實現簡單的下拉重新整理pulltorefresh_Android

來源:互聯網
上載者:User

網上下拉重新整理的DEMO很多,但是總有各種不滿意的地方,有些會下拉卡住,有些回彈不流暢,有些效能太低會各種卡頓,有些emptyView無法下拉...... 

自己寫的才是最合適自己的,代碼很簡單,也很容易修改,稍微閱讀下代碼就能改出自己需要的各種效果。

首先,重寫ListView,自訂Touch事件,為了使emptyView也可下拉,emptyView也加上Touch事件。 如果要實現GridView,把這裡的ListView改成GridView即可。

PullableListView :

public class PullableListView extends ListView {  private boolean inited;  private float density;  private int mDownY, mMoveY;  private int mPullY;  private boolean isPull;  private PullListener mPullListener;  private VelocityTracker mVelocityTracker;  public interface PullListener {    public boolean onPullDownStart();    public void onPullDown(int moveY);    public void onPullDownDrop();  }  public PullableListView(Context context, AttributeSet attrs, int defStyle) {    super(context, attrs, defStyle);    init();  }  public PullableListView(Context context, AttributeSet attrs) {    super(context, attrs);    init();  }  public PullableListView(Context context) {    super(context);    init();  }  private void init() {    if (!inited) {      density = getResources().getDisplayMetrics().density;    }  }  public void setPullListener(PullListener mPullListener) {    this.mPullListener = mPullListener;  }  public boolean isPulling() {    return isPull;  }  @Override  public void setEmptyView(View emptyView) {    super.setEmptyView(emptyView);    // 重寫emptyView的Touch事件,使顯示emptyView時也可以下拉重新整理    emptyView.setOnTouchListener(new OnTouchListener() {      @Override      public boolean onTouch(View v, MotionEvent ev) {        if (mVelocityTracker == null) {          mVelocityTracker = VelocityTracker.obtain();        }        mVelocityTracker.addMovement(ev);        switch (ev.getAction()) {          case MotionEvent.ACTION_DOWN:            mDownY = (int) ev.getY();            break;          case MotionEvent.ACTION_MOVE:            mMoveY = (int) ev.getY();            if (!isPull) {              mVelocityTracker.computeCurrentVelocity(1000, 8000f);              if (mVelocityTracker.getYVelocity() > 500 // 下拉速度大於500                  && Math.abs(mMoveY - mDownY) > 20 * density) { // 下拉距離超過20dp                mPullY = mMoveY;                if (mPullListener.onPullDownStart()) {                  isPull = true;                }              }            } else {              // 阻尼下拉(隨著下拉距離增加,阻力增加)              mPullListener.onPullDown(mMoveY - mPullY + v.getScrollY());              // 等阻力下拉(阻力恒定,不隨下拉距離增加而增加)              // mPullListener.onPullDown(mMoveY - mPullY);              if (mMoveY < mPullY) {                isPull = false;              }              return true;            }            break;          case MotionEvent.ACTION_UP:            if (mVelocityTracker != null) {              mVelocityTracker.clear();              mVelocityTracker.recycle();              mVelocityTracker = null;            }            if (isPull) {              mPullY = 0;              isPull = false;              mPullListener.onPullDownDrop();              return true;            }            break;        }        return true;      }    });  }  @Override  public boolean onInterceptTouchEvent(MotionEvent ev) {    if (isPull) {      // 正在下拉時,阻住Touch事件向下傳遞,同時會向各個ChildView發送ACTION_CANLE事件,      // 使之前捕捉到了ACTION_DOWN事件的ChildView回複到正常狀態      return true;    }    return super.onInterceptTouchEvent(ev);  }  @Override  public boolean onTouchEvent(MotionEvent ev) {    if (mVelocityTracker == null) {      mVelocityTracker = VelocityTracker.obtain();    }    mVelocityTracker.addMovement(ev);    switch (ev.getAction()) {      case MotionEvent.ACTION_DOWN:        mDownY = (int) ev.getY();        break;      case MotionEvent.ACTION_MOVE:        mMoveY = (int) ev.getY();        if (!isPull) {          if (getFirstVisiblePosition() == 0) {            View view = getChildAt(0);            mVelocityTracker.computeCurrentVelocity(1000, 8000f);            if (mVelocityTracker.getYVelocity() > 500// 下拉速度大於500                && (view == null || view.getTop() == getPaddingTop()) // 已拉動到頂部                && Math.abs(mMoveY - mDownY) > 15 * density) { // 下拉距離超過20dp              mPullY = mMoveY;              if (mPullListener.onPullDownStart()) {                // 根據傳回值確認是否進入下拉狀態                isPull = true;              }            }          }        } else {          // 阻尼下拉(隨著下拉距離增加,阻力增加)          mPullListener.onPullDown(mMoveY - mPullY);          // 等阻力下拉(阻力恒定,不隨下拉距離增加而增加)          // mPullListener.onPullDown(mMoveY - mPullY - getScrollY());          if (mMoveY < mPullY) {            isPull = false;          }          return true;        }        break;      case MotionEvent.ACTION_UP:        if (mVelocityTracker != null) {          mVelocityTracker.clear();          mVelocityTracker.recycle();          mVelocityTracker = null;        }        if (isPull) {          mPullY = 0;          isPull = false;          mPullListener.onPullDownDrop();          return true;        }        break;      case MotionEvent.ACTION_CANCEL:        break;    }    return super.onTouchEvent(ev);  }}

然後是外層的LinearyLayer,監聽PullableListView的下拉回調,實現下拉效果。同時提供ListView(GridView)的外部介面,如 setEmptyView(View view),setAdapter(ListAdapter adapter)...等等,這裡只提供部分我需要使用的,可以根據自身需求去提供外部介面。 
代碼中R.drawable.pulltorefresh 和 R.drawable.loading 分別是下拉式箭頭 和 重新整理捲軸 的圖片,這裡不提供了,自己隨意找兩張圖片貼上就行了。 

PullToRefreshView: 

public class PullToRefreshView extends LinearLayout {  protected static final String TAG = "PullToRefreshView";  /**   * 下拉阻力係數   */  private static final float SCALL_PULL_DOWW = 2.0f;  private View mView;  private PullableListView mListView;  private TextView mPullTv;  private ImageView mProgressBar;  private View mPullV;  private View mEmptyView;  private boolean isInited;  private boolean canRefresh;  private boolean isRefreshing;  private boolean isPullable = true;  private int mOrMargin;  private ObjectAnimator mArrowRotateAnimator;  private Animation mProAnimation;  private PullToRefreshListener mPullToRefreshListener;  public PullToRefreshView(Context context, AttributeSet attrs, int defStyle) {    super(context, attrs, defStyle);    initView(context);  }  public PullToRefreshView(Context context, AttributeSet attrs) {    super(context, attrs);    initView(context);  }  public PullToRefreshView(Context context) {    super(context);    initView(context);  }  public interface PullToRefreshListener {    /**     * do data refresh here     */    public void onRefreshStart();    /**     * do view update here     */    public void onRefreshFinished();  }  private void initView(Context context) {    if (!isInited) {      isInited = true;      mView = LayoutInflater.from(context).inflate(R.layout.view_pulltorefresh, null);      mProgressBar = (ImageView) mView.findViewById(R.id.iv_pulltorefresh_arrow);      mProgressBar.setImageResource(R.drawable.pulltorefresh);      mPullTv = (TextView) mView.findViewById(R.id.tv_pulltorefresh);      mPullV = mView.findViewById(R.id.ly_pulltorefresh_pull);      mListView = (PullableListView) mView.findViewById(R.id.gv_smarturc_urcs);      mListView.setPullListener(mPullListener);      LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,          LayoutParams.MATCH_PARENT);      addView(mView, lp);      LayoutParams lParams = (LayoutParams) mPullV.getLayoutParams();      mOrMargin = lParams.topMargin;      mProAnimation = AnimationUtils.loadAnimation(getContext(),          R.anim.anim_progressbar);    }  }  private PullListener mPullListener = new PullListener() {    @Override    public boolean onPullDownStart() {      if (isRefreshing || !isPullable) {        return false;      }      mPullTv.setText("下拉重新整理");      mProgressBar.setRotation(0f);      mProgressBar.setImageResource(R.drawable.pulltorefresh);      if (mProgressBar.getAnimation() != null) {        mProgressBar.clearAnimation();      }      return true;    }    @Override    public void onPullDown(int moveY) {      if (isRefreshing || !isPullable) {        return;      }      moveY = (int) Math.max(0, moveY / SCALL_PULL_DOWW);      mView.scrollTo(0, -moveY);      mEmptyView.scrollTo(0, -moveY);      if (!canRefresh          && Math.abs(mView.getScrollY()) > Math.abs(mOrMargin)) {        mPullTv.setText("鬆開重新整理");        canRefresh = true;        if (mArrowRotateAnimator != null) {          mArrowRotateAnimator.cancel();        }        float rotation = mProgressBar.getRotation();        mArrowRotateAnimator = ObjectAnimator.ofFloat(mProgressBar, "rotation",            rotation, 180f);        mArrowRotateAnimator.setDuration(100).start();      } else if (canRefresh          && Math.abs(mView.getScrollY()) <= Math.abs(mOrMargin)) {        mPullTv.setText("下拉重新整理");        canRefresh = false;        if (mArrowRotateAnimator != null) {          mArrowRotateAnimator.cancel();        }        float rotation = mProgressBar.getRotation();        mArrowRotateAnimator = ObjectAnimator.ofFloat(mProgressBar, "rotation",            rotation, 0f);        mArrowRotateAnimator.setDuration(100).start();      }    }    @Override    public void onPullDownDrop() {      if (canRefresh) {        setRefreshing();      } else {        isRefreshing = false;        backTo(mView.getScrollY(), 0);      }    }  };  private void backTo(final int from, final int to) {    ObjectAnimator.ofInt(mView, "scrollY", from, to).setDuration(300)        .start();    ObjectAnimator.ofInt(mEmptyView, "scrollY", from, to).setDuration(300)        .start();  }  /**   * 設定為正在重新整理狀態   */  public void setRefreshing() {    isRefreshing = true;    mProgressBar.setImageResource(R.drawable.loading);    mProgressBar.startAnimation(mProAnimation);    mPullTv.setText("正在重新整理");    backTo(mView.getScrollY(), mOrMargin);    if (mPullToRefreshListener != null) {      mPullToRefreshListener.onRefreshStart();    }  }  /**   * 重新整理完成   */  public void setRrefreshFinish() {    if (isRefreshing) {      isRefreshing = false;      backTo(mView.getScrollY(), 0);    }    if (mPullToRefreshListener != null) {      mPullToRefreshListener.onRefreshFinished();    }  }  public void setPullable(boolean pullable) {    isPullable = pullable;  }  public void setPullToRefreshListener(      PullToRefreshListener mPullToRefreshListener) {    this.mPullToRefreshListener = mPullToRefreshListener;  }  public void setAdapter(ListAdapter adapter) {    mListView.setAdapter(adapter);  }  public void setEmptyView(View emptyView) {    mListView.setEmptyView(emptyView);    this.mEmptyView = emptyView;  }  public void setOnItemClickListener(OnItemClickListener itemClickListener) {    mListView.setOnItemClickListener(itemClickListener);  }  public void setOnItemLongClickListener(OnItemLongClickListener itemLongClickListener) {    mListView.setOnItemLongClickListener(itemLongClickListener);  }}

layout-view_pulltorefresh: 

<?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="match_parent"  android:background="#cccccc"  android:orientation="vertical" >  <LinearLayout    android:id="@+id/ly_pulltorefresh_pull"    android:layout_width="wrap_content"    android:layout_height="48dp"    android:layout_gravity="center_horizontal"    android:layout_marginTop="-48dp" >    <ImageView      android:id="@+id/iv_pulltorefresh_arrow"      android:layout_width="20dp"      android:layout_height="match_parent"      android:scaleType="fitCenter"      android:src="@drawable/pulltorefresh" />    <TextView      android:id="@+id/tv_pulltorefresh"      android:layout_width="wrap_content"      android:layout_height="match_parent"      android:layout_marginBottom="4dp"      android:layout_marginLeft="8dp"      android:gravity="center"      android:textColor="@android:color/white"      android:textSize="16sp" />  </LinearLayout>  <com.example.pulltorefresh.PullableListView    android:id="@+id/gv_smarturc_urcs"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="@android:color/transparent"    android:overScrollMode="never"    android:scrollingCache="false" >  </com.example.pulltorefresh.PullableListView></LinearLayout>

anim-anim_progressbar: 

<?xml version="1.0" encoding="utf-8"?><rotate xmlns:android="http://schemas.android.com/apk/res/android"  android:fromDegrees="0"  android:toDegrees="360"  android:pivotX="50%"  android:pivotY="50%"  android:repeatCount="infinite"  android:repeatMode="restart"  android:duration="800"  android:interpolator="@android:anim/linear_interpolator"/>

最後是DEMO ACTIVITY: 

public class PullToRefreshActivity extends Activity {  private PullToRefreshView mPullToRefreshView;  private List<String> data = new ArrayList<String>();  private MyAdapter mAdapter;  private Handler mHandler;  @Override  protected void onCreate(Bundle savedInstanceState) {    // TODO Auto-generated method stub    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_pulltorefresh);    mHandler = new Handler();    mPullToRefreshView = (PullToRefreshView) findViewById(R.id.pullToRefreshView1);    mAdapter = new MyAdapter();    mPullToRefreshView.setAdapter(mAdapter);    mPullToRefreshView.setEmptyView(findViewById(R.id.empty));    mPullToRefreshView.setOnItemLongClickListener(new OnItemLongClickListener() {      @Override      public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {        Toast.makeText(getApplicationContext(), "Long click : " + data.get(position),            Toast.LENGTH_SHORT).show();        return true;      }    });    mPullToRefreshView.setOnItemClickListener(new OnItemClickListener() {      @Override      public void onItemClick(AdapterView<?> parent, View view, int position, long id) {        Toast.makeText(getApplicationContext(), data.get(position), Toast.LENGTH_SHORT)            .show();      }    });    mPullToRefreshView.setPullToRefreshListener(new PullToRefreshListener() {      @Override      public void onRefreshStart() {        // 類比重新整理資料        mHandler.postDelayed(new Runnable() {          @Override          public void run() {            data.add(String.valueOf((int) (Math.random() * 1000)));            mPullToRefreshView.setRrefreshFinish();          }        }, 2000);      }      @Override      public void onRefreshFinished() {        // 更新視圖        mAdapter.notifyDataSetChanged();      }    });//    mHandler.postDelayed(new Runnable() {//      @Override//      public void run() {//        // TODO Auto-generated method stub//        mPullToRefreshView.setRefreshing();//      }//    }, 500);  }  public class MyAdapter extends BaseAdapter {    @Override    public int getCount() {      // TODO Auto-generated method stub      return data.size();    }    @Override    public Object getItem(int position) {      // TODO Auto-generated method stub      return data.get(position);    }    @Override    public long getItemId(int position) {      // TODO Auto-generated method stub      return position;    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {      // TODO Auto-generated method stub      if (convertView == null) {        convertView = new TextView(PullToRefreshActivity.this);      }      TextView textView = (TextView) convertView;      textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 40f);      textView.setPadding(30, 30, 30, 30);      textView.setText(data.get(position));      return convertView;    }  }}

layout-activity_pulltorefresh: 

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  xmlns:tools="http://schemas.android.com/tools"  android:id="@+id/container"  android:layout_width="match_parent"  android:layout_height="match_parent" >  <com.example.pulltorefresh.PullToRefreshView    android:id="@+id/pullToRefreshView1"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:layout_alignParentLeft="true"    android:layout_alignParentTop="true" >  </com.example.pulltorefresh.PullToRefreshView>  <LinearLayout    android:id="@+id/empty"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:gravity="center_horizontal"    android:orientation="vertical"    android:padding="60dp" >    <ImageView      android:layout_width="wrap_content"      android:layout_height="wrap_content"      android:src="@drawable/ic_launcher" />    <TextView      android:layout_width="wrap_content"      android:layout_height="wrap_content"      android:text="NO DATA" />  </LinearLayout></RelativeLayout>

以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援雲棲社區。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.