我的编程空间,编程开发者的网络收藏夹
学习永远不晚

亲自动手编写Android通用刷新控件

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

亲自动手编写Android通用刷新控件

项目中我们经常有上拉、下拉刷新的需求,几乎所有的listView、RecyclerView都会伴随着上拉、下拉刷新的需求,如果我们使用一些开源控件,换了控件我们就要更新,现在我们自己撸起袖子写一个通用的刷新控件

项目地址:https://git.oschina.net/qiangshen/commentview.git

思路:

  • 写一个继承RelativeLayout的RefreshLayout
  • 添加头尾控件作为刷新控件
  • 通过事件分发来进行刷新操作
  • 通过动画来控制控件移动

目的:让他的所有子控件都可以使用,哪怕是一个TextView

public class RefreshLayout extends RelativeLayout {    private final int V_REFRESH = 2;    private boolean mIsRefreshDuring;    private boolean mCanDownPull;    private boolean mCanUpPull;    private boolean mIsFirstMove;    private int mDistanceY;    private OnRefresh mOnRefresh;    private boolean mCanIntercept;  private int mTouchSlop;  private int mDistance;  private LayoutParams mHeaderParams;  private View mHeaderView;  private View mFootView;  private int mHeaderMaxHeight;  private int mStartY;  private LayoutParams mFootParams;  private int mFootMaxHeight;  private PullCallBack mCallBack;  private View mChildView;  private ObjectAnimator mAnimator;  public RefreshLayout(Context context) {    super(context);    initData();  }  public RefreshLayout(Context context, AttributeSet attrs) {    super(context, attrs);    initData();  }  public RefreshLayout(Context context, AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);    initData();  }    public interface HeadAndFootCallBack {    //设置属性    void setAttribute();    //开始刷新    void startPull();    //停止刷新    void stopPull();  }    public interface PullCallBack {    boolean canDownPull();    boolean canUpPull();  }  private void initData() {    //不调用该方法不能进行绘制    setWillNotDraw(false);  }    public void downPullFinish() {    mAnimator.setFloatValues(mChildView.getTranslationY(), 0);    mAnimator.start();    ((HeadAndFootCallBack) mHeaderView).stopPull();  }    public void upPullFinish() {    mAnimator.setFloatValues(mChildView.getTranslationY(), 0);    mAnimator.start();    ((HeadAndFootCallBack) mFootView).stopPull();  }    public void autoDownPullForHead() {    postDelayed(new Runnable() {      @Override      public void run() {        mCanDownPull = true;        mCanUpPull = false;        mAnimator.setFloatValues(10, mHeaderMaxHeight);        mAnimator.start();        ((HeadAndFootCallBack) mHeaderView).startPull();        mOnRefresh.onDownPullRefresh();      }    }, 500);  }    public void autoUpPullForHead() {    postDelayed(new Runnable() {      @Override      public void run() {        mCanDownPull = false;        mCanUpPull = true;        mAnimator.setFloatValues(0, mFootMaxHeight);        mAnimator.start();        ((HeadAndFootCallBack) mFootView).startPull();        mOnRefresh.onUpPullRefresh();      }    }, 500);  }  @Override  public boolean onInterceptTouchEvent(MotionEvent ev) {    return mCanIntercept;  }  @Override  public boolean onTouchEvent(MotionEvent event) {    return true;  }  @Override  public boolean dispatchTouchEvent(MotionEvent event) {    Log.e("shen", "mIsRefreshDuring=" + mIsRefreshDuring);    if (mIsRefreshDuring)   {      return super.dispatchTouchEvent(event);    }    switch (event.getAction()) {      case MotionEvent.ACTION_DOWN:        mStartY = (int) event.getY();        initPull();        break;      case MotionEvent.ACTION_MOVE:        if (event.getPointerCount() == 1) {          int moveY = (int) event.getY();          mDistanceY = (moveY - mStartY) / V_REFRESH;          if (!mIsFirstMove && mDistanceY != 0 && mDistanceY < mTouchSlop) {            mCanDownPull = mDistanceY > 0;            mCanUpPull = !mCanDownPull;            mIsFirstMove = true;          }          if (mCanDownPull && mCallBack.canDownPull()) {            upDataForDownPull();//下拉刷新            mChildView.setEnabled(false);            mCanIntercept = true;          }          if (mCanUpPull && mCallBack.canUpPull()) {            upDataForUpPull();//上拉加载            mChildView.setEnabled(false);            mCanIntercept = true;          }          mStartY = moveY;        }        break;      case MotionEvent.ACTION_UP:        mIsRefreshDuring = true;        mIsFirstMove = false;        if (mHeaderParams.height >= mHeaderMaxHeight)   {          ((HeadAndFootCallBack) mHeaderView).startPull();          mOnRefresh.onDownPullRefresh();        } else if (mFootParams.height >= mFootMaxHeight)   {          ((HeadAndFootCallBack) mFootView).startPull();          mOnRefresh.onUpPullRefresh();        } else if (mHeaderParams.height > 0 && mHeaderParams.height < mHeaderMaxHeight)   {          releaseForDownFinished();        } else if (mFootParams.height > 0 && mFootParams.height < mFootMaxHeight)   {          releaseForUpFinished();        } else {          mIsRefreshDuring = false;          mCanIntercept = false;        }        break;    }    super.dispatchTouchEvent(event);    return true;  }    private void initPull() {    mCanDownPull = false;    mCanUpPull = false;  }    private void releaseForUpFinished() {    mAnimator.setFloatValues(mChildView.getTranslationY(), 0);    mAnimator.start();  }    private void releaseForDownFinished() {    mAnimator.setFloatValues(mChildView.getTranslationY(), 0);    mAnimator.start();  }    private void upDataForUpPull() {    if (mDistanceY != 0) {      mFootParams.height -= mDistanceY;      if (mFootParams.height <= 0) {        mFootParams.height = 0;      }      if (mFootParams.height >= mFootMaxHeight) {        mFootParams.height = mFootMaxHeight;      }      mChildView.setTranslationY(-mFootParams.height);      mFootView.requestLayout();    }  }    private void upDataForDownPull() {    if (mDistanceY != 0) {      mHeaderParams.height += mDistanceY;      if (mHeaderParams.height >= mHeaderMaxHeight) { //最大        mHeaderParams.height = mHeaderMaxHeight;      }      if (mHeaderParams.height <= 0) { //最小        mHeaderParams.height = 0;      }      mChildView.setTranslationY(mHeaderParams.height);      mHeaderView.requestLayout();    }  }  @Override  protected void onAttachedToWindow() {    super.onAttachedToWindow();  }  @Override  protected void onFinishInflate() {    super.onFinishInflate();    //加载头    mHeaderView = getChildAt(0);    if (!(mHeaderView instanceof HeadAndFootCallBack)) {      new IllegalStateException("HeaderView必须实现HeadAndFootCallBack接口");    }    ((HeadAndFootCallBack) mHeaderView).setAttribute();    mHeaderParams = (LayoutParams) mHeaderView.getLayoutParams();    mHeaderParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);    //加载尾    mFootView = getChildAt(2);    if (!(mFootView instanceof HeadAndFootCallBack)) {      new IllegalStateException("FootView必须实现HeadAndFootCallBack接口");    }    ((HeadAndFootCallBack) mFootView).setAttribute();    mFootParams = (LayoutParams) mFootView.getLayoutParams();    mFootParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);    mChildView = getChildAt(1);    if (!(mChildView instanceof HeadAndFootCallBack)) {      new IllegalStateException("ChildView必须实现PullCallBack接口");    }    mCallBack = (PullCallBack) getChildAt(1);    //设置动画    mAnimator = ObjectAnimator.ofFloat(mChildView, "translationY", 0);    mAnimator.setInterpolator(new DecelerateInterpolator());    mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {      @Override      public void onAnimationUpdate(ValueAnimator animation) {        int translationY = (int) mChildView.getTranslationY();        if (mCanUpPull) { //从移动到的位置往下滑          mFootParams.height = Math.abs(translationY);          mFootView.requestLayout();        } else if (mCanDownPull) {          mHeaderParams.height = Math.abs(translationY);          mHeaderView.requestLayout();        }        Log.e("shen", "translationY=" + translationY);        Log.e("shen", "mHeaderParams.height=" + mHeaderParams.height);        if (translationY == 0) {          mChildView.setEnabled(true);          mDistanceY = 0; //重置          mIsRefreshDuring = false; //重置          mCanIntercept = false;        } else {          mIsRefreshDuring = true;        }      }    });  }  @Override  protected void onSizeChanged(int w, int h, int oldw, int oldh) {    super.onSizeChanged(w, h, oldw, oldh);    mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();    mDistance = mTouchSlop * 5;    //设置下拉头初始属性    mHeaderMaxHeight = mHeaderParams.height;    mHeaderParams.height = 0;    mHeaderView.requestLayout();    //设置上拉尾初始属性    mFootMaxHeight = mFootParams.height;    mFootParams.height = 0;    mFootView.requestLayout();  }    public interface OnRefresh {        void onDownPullRefresh();        void onUpPullRefresh();  }  public void setOnRefresh(OnRefresh onRefresh) {    mOnRefresh = onRefresh;  }}

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

亲自动手编写Android通用刷新控件

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

亲自动手编写Android通用刷新控件

项目中我们经常有上拉、下拉刷新的需求,几乎所有的listView、RecyclerView都会伴随着上拉、下拉刷新的需求,如果我们使用一些开源控件,换了控件我们就要更新,现在我们自己撸起袖子写一个通用的刷新控件项目地址:https://gi
2023-05-31

Android中怎么通过自定义控件实现下拉刷新效果

本篇文章给大家分享的是有关Android中怎么通过自定义控件实现下拉刷新效果,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。@Override protected void o
2023-05-30

Android实现支持所有View的通用的下拉刷新控件

下拉刷新对于一个app来说是必不可少的一个功能,在早期大多数使用的是chrisbanes的PullToRefresh,或是修改自该框架的其他库。而到现在已经有了更多的选择,github上还是有很多体验不错的下拉刷新。 而下拉刷新主要有两种实
2022-06-06

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录