Android打造通用的下拉刷新组件

还记得上一篇 blog 的内容吗?如果不记得建议先去了解一下,Android 事件处理全面剖析 ,因为下拉刷新需要用到手势的处理,而上一篇文章中,对事件处理做了很详细的说明,了解了事件的处理机制,对理解本篇文章有很大的帮助。好了,这里就当大家都已经对事件处理有了一定的了解,开始我们的下拉刷新征程。

还是老规矩,先上效果图,再根据效果图来分析实现的原理;
这里写图片描述

一 、分析原理
我们都知道,listView 控件为我们提供了 addHeaderView、和 addFootView 的方法,我们通过此方法可以很方便的实现下拉刷新效果;但不是所有的控件都有 addHeaderView 方法,比如,scrollView、TextView 等都没有addHeaderView 方法,所以这些控件就需要我们自己通过其他方式实现下拉刷新的效果,一个项目中,为了通用性和复用性,往往也不会把 listView 控件单独分离出来实现下拉刷新的效果,这时,就需要一个能对所有的控件达到通用的下拉刷新效果。
这里很容易想到用自定义 ViewGroup 来实现,让自定义的 ViewGroup 包含两个控件,一个是下拉刷新的headerView、 另一个是需要展示数据的控件contentView,contentView可以是任何控件;headerView 和 contentView 垂直布局,并且初始状态让 headerView 滚动到看不到的位置。基本的思路就是这样,接下来就是对事件处理。

二、代码实现
代码实现可以分为四个小点:
1、自定义 ViewGroup 的实现
在前面我的 blog 中有一篇写的是关于自定义 View 的内容,Android自定义View,你必须知道的几点 如果对这篇 blog 了解的同学相信对你来说,自定义 ViewGroup 也没什么难度,自定义 ViewGroup 相对自定义 View 还是较容易的。
自定义 ViewGroup 需要重写的两个方法是

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
protected void onLayout(boolean changed, int l, int t, int r, int b)

onMeasure方法相对较简单,只需要对子 View 进行测量即可,这里贴出onMeasure的代码,注解也比较详细。

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        /*获取 ViewGroup 的宽度*/
        int width = MeasureSpec.getSize(widthMeasureSpec) ;
        /*获取 ViewGroup 的高度*/
        int height = MeasureSpec.getSize(heightMeasureSpec) ;
        /*这里不懂的同学可以去参考我前面写的一篇blog 自定义View*/
        /*测量 refreshView 的宽高,这里把高度设为固定值*/
        measureChild(mHeaderView,widthMeasureSpec,MeasureSpec.makeMeasureSpec(mHeaderHeight ,MeasureSpec.EXACTLY));
        Log.v("zgy","==========mHeaderView============"+mHeaderView.getMeasuredHeight()) ;
        /*测量 mContentView 的宽高,高度为最大值只能为ViewGroup 的高度*/
        measureChild(mContentView, widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
        mRefreshHeight = mTextView.getMeasuredHeight() ;
        /*千万别忘记调用测量方法*/
        setMeasuredDimension(width,height);
    }

onLayout方法就是根据我们测量子 View 的宽高,来布局子 View,前面我们分析原理的时候说到了,这里需要用到垂直布局,也就是先布局 headerVeiw,再在 headerView 下面布局 contentView,这里 headerView 的隐藏操作也放在 onLayout 方法中,所以就得判断是否是第一次,防止重复隐藏。具体实现代码如下

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        /*布局刷新的头部 headerView*/
mHeaderView.layout(0,0,mHeaderView.getMeasuredWidth(),mHeaderView.getMeasuredHeight());
        /*布局内容区域 contentView*/   mContentView.layout(0,mHeaderView.getMeasuredHeight(),mContentView.getMeasuredWidth(),             mHeaderView.getMeasuredHeight()+mContentView.getMeasuredHeight());
        if (isFirst){ 
            /*第一次把 headerView隐藏*/
            scrollTo(0,mHeaderView.getMeasuredHeight());
        }
        isFirst = false ;
    }

上面讲到了两个 View,一个是 headerView ,另一个是 contentView,讲了这么久,相信大家都会问,这两个 View 从何而来?先来分析 headerView, headerView 它是一个固定的、不会变的。所以这里我们可以直接通过 xml 来定义,然后再代码中通过 addView 方法把 headerView 添加进去。
headerView xml 中的代码

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="130dp"
                android:background="@mipmap/refresh_bg">

    <TextView
        android:id="@+id/id_txt_header"
        android:gravity="center"
        android:text="下拉可以刷新"
        android:layout_width="match_parent"
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值