相信很多童鞋对于控件的下拉刷新都比较熟悉吧,常用的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);
}
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来满足多分布需求.
}
}