自定义RecyclerView滑动
- 拦截事件处理,自定义View自己处理滑动
- 向上滑动&&向下滑动
- 滑动偏差处理
拦截事件处理,自定义View自己处理滑动
-
坐标示例图
- onInterceptTouchEvent方法处理
/**
* 重写onInterceptTouchEvent方法,来决定滑动还是不滑动
* @param ev
* @return
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean intercept=false;
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
currentY=(int)ev.getRawY();
break;
case MotionEvent.ACTION_MOVE:
//取出手指当前移动到的Y轴值,跟之前记录的手指触摸位置y相减求差值。
float y2=Math.abs(currentY-ev.getRawY());
//分两种情况
/**
* 1、小于最小滑动距离 就不滑动
* 2、如果大于最小滑动距离 就滑动
*/
if(y2>touchSlop){
intercept=true;
}
break;
}
return intercept;
}
- 处理滑动
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_MOVE:
//先获取到当前Y轴的值
float y2=event.getRawY();
//手指触摸减去滑动到的这个Y轴的值
float diff=currentY-y2;
//不加会影响反应速度
currentY=(int)y2;
//调用滑动方法
scrollBy(0,(int)diff);
break;
}
return super.onTouchEvent(event);
}
向上滑动&&向下滑动
- 上下滑动
@Override
public void scrollBy(int x, int y) {
scrollY+=y;
//处理滑动边界问题,纠正scrollY
// scrollY=scrollBounds(scrollY);
if(scrollY>0){//向上滑
/**
* 上滑需要做两件事情
* 1、将屏幕上方的ItemView移除
* 2、给屏幕下方添加一个新的ItemView进来
*/
//1、将屏幕上方的ItemView移除
while (scrollY>heights[firstRow]){
//删除第一行,就是删除当前布局中的第0个Item
removeView(viewlist.remove(0));
//改变scrolly 要减去这一行的高度
scrollY-=heights[firstRow];
//当前显示的行标
firstRow++;
}
//2、给屏幕下方添加一个新的ItemView进来
//判断当前所显示的View的高度是不是小于RecylerView的高度,如果小于,就添加新的Item
while (getFillHeight()<height){
//首先 当前第一行的坐标,加上当前屏幕显示的ItemView的长度,其实就是要添加进去那一行的Item
int addLast=firstRow+viewlist.size();
//获取到ItemView
View view=obtainView(addLast,width,heights[addLast]);
//将新的ItemView添加进viewList
viewlist.add(view);
}
}else if(scrollY<0){//向下滑
/**
* 下滑过程中要做两件事情
* 1、创建一个心的ItemView放置在屏幕上方
* 2、把最下面移出屏幕的ItemViewy移除掉
*/
while (scrollY<0){
//当前显示的ItemView的第一行的行标减去1
int firstAndRow=firstRow-1;
//获取到显示在第一行的ItemView的上一个ItemView
View view=obtainView(firstAndRow,width,heights[firstAndRow]);
//添加到可见的Item的最上面
viewlist.add(0,view);
//更新当前显示的第一行的行标
firstRow--;
//改变scrollY,scrollY要将当前添加进去的行的行高加起来
scrollY+=heights[firstAndRow];
}
//把最下面移除了屏幕的item移除掉,判断当前显示的View的总高度是不是大于RecylerView的高度。如果大于将最下面的ItemView移除掉
while (sumArray(heights,firstRow,viewlist.size())-scrollY-heights[firstRow+viewlist.size()-1]>=height){
//移除当前显示的在最下面的ItemView
removeView(viewlist.remove(viewlist.size()-1));
}
}else{
}
//重新摆放位置
rePositionView();
}
/**
* 获取到显示在控件中View的总高度
* @return
*/
private int getFillHeight() {
return sumArray(heights,firstRow,viewlist.size())-scrollY;
}
- 重新摆放位置
/**
* 当我们上拉或者下滑的时候,重新摆放View的位置
*/
private void rePositionView() {
int top=0,right,bottom,left=0,i;
top-=scrollY;
//将当前第一行的行标赋值给i
i=firstRow;
for (View view:viewlist){
//重新摆放View
bottom=top+heights[i++];
view.layout(0,top,width,bottom);
top=bottom;
}
}
滑动偏差处理
-
运行看结果
- 纠正scrolly值
/**
* 纠正scrollY值
* @param scrollY
* @return
*/
private int scrollBounds(int scrollY) {
if(scrollY>0){
//判断上滑的极限 防止滚动的距离 大于当前所有内容的高度
scrollY=Math.min(scrollY,sumArray(heights,firstRow,heights.length-firstRow)-height);
}else{
//判断下滑的极限值,防止滚动的距离 小于第0个Item的高度
scrollY=Math.max(scrollY,-sumArray(heights,0,firstRow));
}
return scrollY;
}
-
运行效果(可以正?;?/p>
好的,我们这节课就到这里,我们下节课讲RecyclerView回收池,再见