效果图

ScreenGif1.gif
实现流程
- 新建一个RefreshLayout继承自Linearlayout。
public class RefreshLayout extends LinearLayout -
添加一个progressbar到RefreshLayout中,作为第一个View。
public RefreshLayout(Context context) { super(context); init(); } public RefreshLayout(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } public RefreshLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { addHeadRefresh(); } private void addHeadRefresh() { setOrientation(LinearLayout.VERTICAL); ProgressBar progressBar = new ProgressBar(getContext()); addView(progressBar, 0); } - 通过scroll隐藏progerssbar。
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); scrollTo(0, getChildAt(0).getHeight()); } - 重写onInterfuptTouchEvent()方法,判断下滑时候拦截事件
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { y = (int) ev.getRawY(); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: interrupt = false; break; case MotionEvent.ACTION_MOVE: if (y - yLast > 2) { interrupt = true; } else { interrupt = false; } break; case MotionEvent.ACTION_UP: interrupt = false; break; } yLast = y; return interrupt; } - 重写onTouchEvent()方法,处理滑动以及弹性滑动
@Override public boolean onTouchEvent(MotionEvent event) { //动画还没结束的时候,直接消耗掉事件,不处理。 if (!scroller.isFinished()||isRefresh) { return true; } y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_MOVE: yMove = y - yLast; if (yMove >= 0) { scrollBy(0, -yMove / 3); // /3为了让下拉有感觉 i += yMove / 3; } break; case MotionEvent.ACTION_UP: if(i>=getChildAt(0).getHeight()){ smoothToScroll(i-getChildAt(0).getHeight()); i = getChildAt(0).getHeight(); isRefresh = true; Toast.makeText(getContext(),"正在刷新中",Toast.LENGTH_SHORT).show(); }else { endRefresh(); } break; } yLast = y; return true; } -
实现弹性滑动典型固定代码
private void smoothToScroll(int destaY) { scroller.startScroll(0, getScrollY(), 0, destaY, 500); invalidate(); } @Override public void computeScroll() { super.computeScroll(); if (scroller.computeScrollOffset()) { scrollTo(0, scroller.getCurrY()); postInvalidate(); } } -
增加结束滑动方法
public void endRefresh() { isRefresh = false; smoothToScroll(i); i = 0; }第一阶段全部代码如下
public class RefreshLayout extends LinearLayout { private boolean interrupt = false; private int yMove; private int yLast; private int y; private int i; private boolean isRefresh = false; private Scroller scroller = new Scroller(getContext()); public RefreshLayout(Context context) { super(context); init(); } public RefreshLayout(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } public RefreshLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { addHeadRefresh(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); scrollTo(0, getChildAt(0).getHeight()); } private void smoothToScroll(int destaY) { scroller.startScroll(0, getScrollY(), 0, destaY, 500); invalidate(); } @Override public void computeScroll() { super.computeScroll(); if (scroller.computeScrollOffset()) { scrollTo(0, scroller.getCurrY()); postInvalidate(); } } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { y = (int) ev.getRawY(); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: interrupt = false; break; case MotionEvent.ACTION_MOVE: if (y - yLast > 0) { interrupt = true; } else { interrupt = false; } break; case MotionEvent.ACTION_UP: interrupt = false; break; } yLast = y; return interrupt; } @Override public boolean onTouchEvent(MotionEvent event) { //动画还没结束的时候,直接消耗掉事件,不处理。 if (!scroller.isFinished()||isRefresh) { return true; } y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_MOVE: yMove = y - yLast; if (yMove >= 0) { scrollBy(0, -yMove / 3); // /3为了让下拉有感觉 i += yMove / 3; } break; case MotionEvent.ACTION_UP: if(i>=getChildAt(0).getHeight()){ smoothToScroll(i-getChildAt(0).getHeight()); i = getChildAt(0).getHeight(); isRefresh = true; Toast.makeText(getContext(),"正在刷新中",Toast.LENGTH_SHORT).show(); }else { endRefresh(); } break; } yLast = y; return true; } public void endRefresh(){ isRefresh = false; smoothToScroll(i); i = 0; } private void addHeadRefresh() { setOrientation(LinearLayout.VERTICAL); ProgressBar progressBar = new ProgressBar(getContext()); addView(progressBar, 0); } }布局

image.png
第二阶段——适配Scrollview
效果图

ScreenGif2.gif
布局

image.png
实现过程
- 检测直接子view中是否包含Scrollview
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); scrollTo(0, getChildAt(0).getHeight()); checkScrollView(); } private void checkScrollView() { //检测是否有scrollview for (int j = 0; j < getChildCount(); j++) { Object v = getChildAt(j); if (v instanceof ScrollView) { scrollView = (ScrollView) v; } } } -
为move增加scrollview的判断
case MotionEvent.ACTION_MOVE: if (y - yLast > 0) { //检测下拉操作 if(isMoveScrollView(ev)){ //如果是在滑动scrollview 不拦截 interrupt = false; }else { //否则拦截 interrupt = true; } } else { //上拉不拦截 interrupt = false; } break; private boolean isMoveScrollView(MotionEvent ev) { if(scrollView==null){ return false; } View head = getChildAt(0); //检测点击区域是不是在scrollview if(ev.getY()>(scrollView.getTop()-head.getHeight())&&ev.getY()<= (scrollView.getBottom()-head.getHeight())&&scrollView.getScrollY()!=0){ return true; } return false; }第三阶段适配Recyclerview
效果图

ScreenGif3.gif
布局

image.png
1 检测直接子view中是否包含Recyclerview,记录recyclerview的滑动距离
private void checkScrollView() {
//检测是否有scrollview
for (int j = 0; j < getChildCount(); j++) {
Object v = getChildAt(j);
if (v instanceof ScrollView) {
scrollView = (ScrollView) v;
} else if (v instanceof RecyclerView) {
recyclerView = (RecyclerView) v;
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
rvScrolled += dy;
}
});
}
}
}
2 为move增加滑动判断,原理和scrollview差不多
case MotionEvent.ACTION_MOVE:
if (y - yLast > 0) {
//检测下拉操作
if (isMoveScrollView(ev) || isMoveRecyclerView(ev)) {
//如果是在滑动scrollview 不拦截
interrupt = false;
} else {
//否则拦截
interrupt = true;
}
} else {
//上拉不拦截
interrupt = false;
}
break;
private boolean isMoveRecyclerView(MotionEvent ev) {
if (recyclerView == null) {
return false;
}
View head = getChildAt(0);
//检测点击区域是不是在scrollview
if (ev.getY() > (recyclerView.getTop() - head.getHeight()) && ev.getY() <=
(recyclerView.getBottom() - head.getHeight()) && rvScrolled != 0) {
return true;
}
return false;
}
3 增加OnRefreshListener()
private interface OnRefreshListener{
void onRefresh();
}
第二阶段代码如下
package com.administrator.customviewtest.view.scrollview;
import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.ScrollView;
import android.widget.Scroller;
/**
* Created by lsp on 2017/6/6.
*/
public class RefreshLayout extends LinearLayout {
private boolean interrupt = false;
private int yMove;
private int yLast;
private int y;
private int i;
private boolean isRefresh = false;
private Scroller scroller = new Scroller(getContext());
private ScrollView scrollView;
private RecyclerView recyclerView;
private int rvScrolled = 0;
private OnRefreshListener onRefreshListener;
public RefreshLayout(Context context) {
super(context);
init();
}
public RefreshLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public RefreshLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
addHeadRefresh();
}
public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
this.onRefreshListener = onRefreshListener;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
scrollTo(0, getChildAt(0).getHeight());
checkScrollView();
}
private void checkScrollView() {
//检测是否有scrollview
for (int j = 0; j < getChildCount(); j++) {
Object v = getChildAt(j);
if (v instanceof ScrollView) {
scrollView = (ScrollView) v;
} else if (v instanceof RecyclerView) {
recyclerView = (RecyclerView) v;
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
rvScrolled += dy;
}
});
recyclerView.getAdapter().registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
super.onItemRangeInserted(positionStart, itemCount);
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
super.onItemRangeRemoved(positionStart, itemCount);
}
});
}
}
}
private void smoothToScroll(int destaY) {
scroller.startScroll(0, getScrollY(), 0, destaY, 500);
invalidate();
}
@Override
public void computeScroll() {
super.computeScroll();
if (scroller.computeScrollOffset()) {
scrollTo(0, scroller.getCurrY());
postInvalidate();
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
y = (int) ev.getRawY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
interrupt = false;
break;
case MotionEvent.ACTION_MOVE:
if (y - yLast > 0) {
//检测下拉操作
if (isMoveScrollView(ev) || isMoveRecyclerView(ev)) {
//如果是在滑动scrollview 不拦截
interrupt = false;
} else {
//否则拦截
interrupt = true;
}
} else {
//上拉不拦截
interrupt = false;
}
break;
case MotionEvent.ACTION_UP:
interrupt = false;
break;
}
yLast = y;
return interrupt;
}
private boolean isMoveRecyclerView(MotionEvent ev) {
if (recyclerView == null) {
return false;
}
View head = getChildAt(0);
//检测点击区域是不是在scrollview
if (ev.getY() > (recyclerView.getTop() - head.getHeight()) && ev.getY() <=
(recyclerView.getBottom() - head.getHeight()) && rvScrolled != 0) {
return true;
}
return false;
}
private boolean isMoveScrollView(MotionEvent ev) {
if (scrollView == null) {
return false;
}
View head = getChildAt(0);
//检测点击区域是不是在scrollview
if (ev.getY() > (scrollView.getTop() - head.getHeight()) && ev.getY() <=
(scrollView.getBottom() - head.getHeight()) && scrollView.getScrollY() != 0) {
return true;
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//动画还没结束的时候,直接消耗掉事件,不处理。
if (!scroller.isFinished() || isRefresh) {
return true;
}
y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
yMove = y - yLast;
if (yMove >= 0) {
scrollBy(0, -yMove / 3); // /3为了让下拉有感觉
i += yMove / 3;
}
break;
case MotionEvent.ACTION_UP:
if (i >= getChildAt(0).getHeight()) {
smoothToScroll(i - getChildAt(0).getHeight());
i = getChildAt(0).getHeight();
isRefresh = true;
if (onRefreshListener != null) {
onRefreshListener.onRefresh();
}
} else {
endRefresh();
}
break;
}
yLast = y;
return true;
}
public void endRefresh() {
isRefresh = false;
smoothToScroll(i);
i = 0;
}
private void addHeadRefresh() {
setOrientation(LinearLayout.VERTICAL);
ProgressBar progressBar = new ProgressBar(getContext());
addView(progressBar, 0);
}
private interface OnRefreshListener{
void onRefresh();
}
}