网上下拉刷新的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;}@Overridepublic void setEmptyView(View emptyView) {super.setEmptyView(emptyView);// 重写emptyView的Touch事件,使显示emptyView时也可以下拉刷新emptyView.setOnTouchListener(new OnTouchListener() {@Overridepublic 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) { // 下拉距离超过20dpmPullY = 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;}});}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {if (isPull) {// 正在下拉时,阻住Touch事件向下传递,同时会向各个ChildView发送ACTION_CANLE事件,// 使之前捕捉到了ACTION_DOWN事件的ChildView回复到正常状态return true;}return super.onInterceptTouchEvent(ev);}@Overridepublic 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) { // 下拉距离超过20dpmPullY = 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() {@Overridepublic 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;}@Overridepublic 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();}}@Overridepublic 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" ><LinearLayoutandroid:id="@+id/ly_pulltorefresh_pull"android:layout_width="wrap_content"android:layout_height="48dp"android:layout_gravity="center_horizontal"android:layout_marginTop="-48dp" ><ImageViewandroid:id="@+id/iv_pulltorefresh_arrow"android:layout_width="20dp"android:layout_height="match_parent"android:scaleType="fitCenter"android:src="@drawable/pulltorefresh" /><TextViewandroid: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.PullableListViewandroid: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;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.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() {@Overridepublic 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() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {Toast.makeText(getApplicationContext(), data.get(position), Toast.LENGTH_SHORT).show();}});mPullToRefreshView.setPullToRefreshListener(new PullToRefreshListener() {@Overridepublic void onRefreshStart() {// 模拟刷新数据mHandler.postDelayed(new Runnable() {@Overridepublic void run() {data.add(String.valueOf((int) (Math.random() * 1000)));mPullToRefreshView.setRrefreshFinish();}}, 2000);}@Overridepublic 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 {@Overridepublic int getCount() {// TODO Auto-generated method stubreturn data.size();}@Overridepublic Object getItem(int position) {// TODO Auto-generated method stubreturn data.get(position);}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {// TODO Auto-generated method stubif (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.PullToRefreshViewandroid: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><LinearLayoutandroid:id="@+id/empty"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center_horizontal"android:orientation="vertical"android:padding="60dp" ><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/ic_launcher" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="NO DATA" /></LinearLayout></RelativeLayout>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。