这里有新鲜出炉的精品教程,程序狗速度看过来!
Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由Google公司和开放手机联盟领导及开发。尚未有统一中文名称,中国大陆地区较多人使用“安卓”或“安致”。
这篇文章主要为大家详细介绍了Android实现简单的下拉刷新pulltorefresh的相关代码,具有一定的实用性和操作价值,感兴趣的小伙伴们可以参考一下
网上下拉刷新的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>
来源: http://www.phperz.com/article/17/0917/348509.html