新手自定义控件,创建属于自己的下拉刷新(一)---Android,ListView实现IOS的弹性效果

前言

相信很多童鞋对于控件的下拉刷新都比较熟悉吧,常用的PullToRefresh开源库和Google自带的SwipeRefreshLayout大家肯定也很熟悉吧,但作为一个Android开发新手,对于自定义控件和自定义View来实现一些效果肯定还是比较恐惧,无从下手,笔者也是如此.但万事开头难,只要理清楚想要实现的效果,按照步骤来分布来具体代码实施就OK了.
其实下拉刷新,感觉万变不离其宗,对普通的下拉刷新有很多可以延伸的地方,比如:带帧动画的下拉刷新.美团,大众点评,汽车之家.从listview延伸到所有控件的下拉刷新.笔者近期想要实现的就是ViewPager左右滑动刷新加载带弹性的效果.笔者打算通过几篇日志来记录整个实现过程,供各位参考.

效果

本文想要实现的效果是,Android中的ListView下拉的时候有弹性的效果,类似IOS的ListView,但与IOS不一样,android想要实现这一的效果需要重写Listview.我们先来看看效果图,如下:

实现思路

我们想要的目的清楚了,然后就是具体实现思路.
核心:在ListView的顶部增加一个headView.并且在下拉的过程中动态改变HeadView的高度.并且在用户手松开的时候,将ListView回滚到顶部,headView隐藏.
具体实现步骤:
1.在ListView的顶部增加一个headView,将headView的初始位置隐藏在ListView的上方.(即:在ListView里面addHeaderView);
注:这一步的实现,需要在ListView里面测绘headView的高宽,方可显示出来.有点类似继承View里面的onmeasure()方法,不过因为是重写ListView,这里也要去measure,HeadView的高宽;具体代码如下:

private void measureView(View headview) {
        //设定LayoutParams来设定width和height;
        ViewGroup.LayoutParams p = headview.getLayoutParams();
        if (p == null){
            p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        }
        //这边宽度就是p的宽度,也就是父容器的width,listView是限制宽度的,所以需要getChildMeasureSpec这个方法
        int childWidthSpec = ViewGroup.getChildMeasureSpec(0,0,p.width);
        //接下来是高度
        int lpheight = p.height;
        int childHeightSpec;
        if (lpheight > 0){
            //通过makeMeasureSpec方法来获取高度
            childHeightSpec = MeasureSpec.makeMeasureSpec(lpheight,MeasureSpec.EXACTLY);//精确模式
        }else{
            childHeightSpec = MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);//不指定大小
        }
        //宽高赋值给headview
        headview.measure(childWidthSpec, childHeightSpec);
    }

2.添加进去之后,那就是最初的显示,把headview隐藏到listview上,视图不可见;

    addHeaderView(headview);//添加到父布局的headView
        headviewHeight = headview.getMeasuredHeight();//获取到测量的高度
        headview.setPadding(0,-headviewHeight,0,0);//隐藏到上面

3.在listview处于顶部的时候,监听用户滑动的过程监听用户手势进行下拉,否则,就不能下拉,那么就会用到AbsListView.OnScrollListener这个监听,当当前可见item的postion=0的时候,才下拉:

 @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {

    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        //在移动的过程中,把可见的第一项赋值给全局变量,方便后面下拉刷新
        mFirstVisibleItem = firstVisibleItem;
    }

4.就是我们的下拉回滚,主要是重写当前listview的ontouch事件来具体实现.ACTION_MOVE的代码主要是来实现listview随手势下拉,headview高度增加;ACTION_UP的代码主要是listview回滚的弹性特效,其实也监简单就一句代码就搞定,主要用了这个smoothScrollBy()方法,代码:

//重写onTouch方法,实现listview下拉回滚特效
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                //如果当前listview处于初始状态,也就是第一个可见item的postion为0的时候,记录手指滑动的Y轴坐标
                if (mFirstVisibleItem == 0){
                    startY = ev.getY();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                float tempY = ev.getY();
                //在顶部时,给偏移量赋值
                if (mFirstVisibleItem == 0){
// startY = tempY;
                    offsetY = tempY - startY;
                    float currentHeight = (-headviewHeight+offsetY/3);
                    headview.setPadding(0, (int) currentHeight, 0, 0);//这一步就是实现listView随手势下拉,headview高度增加
                }
                break;
            case MotionEvent.ACTION_UP:
// this.smoothScrollBy((int)(-headviewHeight+offsetY/3)+headviewHeight, 500);
                //恢复到headView隐藏的高度
                this.smoothScrollBy(-headviewHeight, 500);
                headview.setPadding(0,-headviewHeight,0,0);//headview隐藏到上面
                break;
        }
        return super.onTouchEvent(ev);
    }

demo下载

http://download.csdn.net/detail/qq_28690547/9398483
注:demo是android-studio项目,如果还在用eclipse的同学,直接把res和java目录文件拷过去就能跑了哈,不过建议大家还是多用android-studio,真的很方便.

结语

整个过程就完整实现了,是不是很简单了.其实自定义View我总结的,就跟咱们以前美术课拿笔在纸上作画一样,首先要明确想要画什么,其次你就会思考为了实现这个目标,我们第一步第二步第三步要做些什么.最后就是具体实现这些步骤,与画画不一样,咱们就是用代码来实现它而已.不过你这样理解了,以后就对自定义控件不那么恐惧了.

补充

其实一个很简单的方法,也可以实现ListView的弹性效果,重写ListView里面的overScrollBy的方法,设定maxOverScrollY的值也可以简单实现效果,(不过下拉刷新涉及不同状态改变其中的值,还是得用headview),代码:

/** * 重写overScrollBy方法里面的maxOverScrollY实现ListView的弹性效果 * Created by max on 2016/1/10. */
public class DouListView extends ListView{

    public DouListView(Context context) {
        super(context);
    }

    public DouListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
        return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, 300, isTouchEvent);//这个300可以根据屏幕density来满足多分布需求.
    }
}

你可能感兴趣的:(android,自定义view,listview弹性)