效果图
实现流程
- 新建一个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());
}
- 重写onIntereptTouchEvent()方法,判断下滑时候拦截事件
@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);
}
}
布局
第二阶段——适配Scrollview
效果图
布局
实现过程
- 检测直接子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
效果图
布局
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();
}
}