返回顶部
首页 > 资讯 > 移动开发 >Android实现简单的下拉刷新pulltorefresh
  • 239
分享到

Android实现简单的下拉刷新pulltorefresh

pulltorefreshAndroid 2022-06-06 08:06:03 239人浏览 八月长安
摘要

网上下拉刷新的DEMO很多,但是总有各种不满意的地方,有些会下拉卡住,有些回弹不流畅,有些性能太低会各种卡顿,有些emptyView无法下拉......  自己写的才

网上下拉刷新的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 {
    
    public void onRefreshStart();
    
    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>
您可能感兴趣的文章:android使用PullToRefresh框架实现ListView下拉刷新上拉加载更多android使用Ultra-PullToRefresh实现下拉刷新自定义代码android使用PullToRefresh实现下拉刷新和上拉加载Android使用PullToRefresh完成ListView下拉刷新和左滑删除功能Android开源项目PullToRefresh下拉刷新功能详解2Android开源项目PullToRefresh下拉刷新功能详解Android下拉刷新控件PullToRefresh实例解析Android使用PullToRefresh实现上拉加载和下拉刷新效果的代码Android程序开发之使用PullToRefresh实现下拉刷新和上拉加载Android PullToRefreshLayout下拉刷新控件的终结者Android带刷新时间显示的PullToRefresh上下拉刷新


--结束END--

本文标题: Android实现简单的下拉刷新pulltorefresh

本文链接: https://lsjlt.com/news/24632.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作