Android 自定义 上拉加载容器
2020-03-13 本文已影响0人
小白彡
App中下拉刷新和上拉加载是很常见的功能,网上也有很多第三方库可以用,为了尽快完成项目,一般都是集成别人的库快速完成功能, 但有时候产品脑洞比较大 ,用别人的库又没那么灵活改起来也麻烦, 就只能自己来了。。。。。
下面看一下效果:
WeChat_20200313173628.gif
自定义还是挺麻烦的,不过也比较有意思,完成这个需要先了解几个知识点:
1.自定义ViewGroup
2.Scroller
3.事件分发体系。
下面开始简单的实现一下:
1.自定义ReboundLinearLayout 继承自 RelativeLayout 这个ViewGroup内部放需要上拉加载的Recyclerview
public class ReboundLinearLayout extends RelativeLayout {
2.由于事件传递的时候RecyclerView会把事件全部消耗完,所以要在ReboundLinearLayout的onInterceptTouchEvent中判断需要拦截的事件, 这里的思路是:如果RecyclerView已经滑动到最底部,就可以进行上拉加载了,这时候就可以拦截手指的向上滑动事件:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if(isSlideToBottom(reboundRecyclerView)){
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
startY = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
endY = ev.getY();
if(endY - startY >= 0){
return false;
}else if(endY - startY < 0){
return true;
}
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
}else{
return false;
}
return false;
}
3.在拦截完事件后,我们在onTouchEvent中进行事件的处理,当然就是使用scroller来将RecyclerView进行移动了:
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
scrollEndY = event.getY();
if(startY - scrollEndY <= SizeUtils.dp2px(scrollHeight)){
scrollTo(0, (int) (startY - scrollEndY));
}
break;
case MotionEvent.ACTION_UP:
mScroller.startScroll(0, getScrollY(),0, -getScrollY(),300);
invalidate();
if(onRefreshListenner != null){
onRefreshListenner.onRefresh();
}
break;
default:
break;
}
return true;
}
这样就可以实现简单的上拉加载了,加个刷新监听 ,在刷新的时候请求数据,就完成啦。。。
下面贴一下代码
public class ReboundLinearLayout extends RelativeLayout {
private RecyclerView reboundRecyclerView;
//判断滑动方向
private float startY;
private float endY;
private float scrollEndY;
private Scroller mScroller;
//最大拉动距离
private int scrollHeight = 80;
private OnRefreshListenner onRefreshListenner;
public ReboundLinearLayout(Context context) {
super(context);
}
public ReboundLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);
}
public ReboundLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if(isSlideToBottom(reboundRecyclerView)){
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
startY = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
endY = ev.getY();
if(endY - startY >= 0){
return false;
}else if(endY - startY < 0){
return true;
}
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
}else{
return false;
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
scrollEndY = event.getY();
if(startY - scrollEndY <= SizeUtils.dp2px(scrollHeight)){
scrollTo(0, (int) (startY - scrollEndY));
}
break;
case MotionEvent.ACTION_UP:
mScroller.startScroll(0, getScrollY(),0, -getScrollY(),300);
invalidate();
if(onRefreshListenner != null){
onRefreshListenner.onRefresh();
}
break;
default:
break;
}
return true;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
reboundRecyclerView = (RecyclerView) getChildAt(0);
}
public static boolean isSlideToBottom(RecyclerView recyclerView) {
if (recyclerView == null) return false;
if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset()
>= recyclerView.computeVerticalScrollRange())
return true;
return false;
}
@Override
public void computeScroll() {
super.computeScroll();
//第二步
if(mScroller.computeScrollOffset()){
//第三步
scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
invalidate();
}
}
public void setOnRefreshListenner(OnRefreshListenner onRefreshListenner) {
this.onRefreshListenner = onRefreshListenner;
}
public interface OnRefreshListenner{
void onRefresh();
}
}
结束。