- 工具类实现
- 没有数据时的空白页面支持
ScrollViewCompat工具类
我们在上拉下拉动作的时候,需要通过ScrollViewCompat
工具类来判断是否达到顶端或者底端,一般可滑动的控件分为ScrollView
,ListView
,WebView
和RecyclerView
,ListView
和RecyclerView
是通过当前显示的子视图是否第一个或者最后一个以及是否有未显示的视图判断,ScrollView
是通过scrollY值判断
/**
* 该视图控件还能否向下拉动
*
* @param mTarget
* @return true-未到顶部,false-到顶部
*/
public static boolean canSmoothDown(View mTarget) {
if (android.os.Build.VERSION.SDK_INT < 14) {
if (mTarget instanceof AbsListView) {
final AbsListView absListView = (AbsListView) mTarget;
return absListView.getChildCount() > 0
&& (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
.getTop() < absListView.getPaddingTop());
} else if (mTarget instanceof RecyclerView) {
final RecyclerView recyclerView = (RecyclerView) mTarget;
LinearLayoutManager lm = (LinearLayoutManager) recyclerView.getLayoutManager();
if ((lm.findFirstVisibleItemPosition() == 0)) {
View firstView = lm.findViewByPosition(0);
return firstView.getTop() < 0;
} else {
return true;
}
} else {
return mTarget.getScrollY() > 0;
}
} else {
return ViewCompat.canScrollVertically(mTarget, -1);
}
}
/**
* 该视图控件还能否向上拉动
*
* @param mTarget
* @return true-未到底部,false-到底部
*/
public static boolean canSmoothUp(View mTarget) {
if (android.os.Build.VERSION.SDK_INT < 14) {
if (mTarget instanceof AbsListView) {
final AbsListView absListView = (AbsListView) mTarget;
View lastChild = absListView.getChildAt(absListView.getChildCount() - 1);
if (lastChild != null) {
if (absListView.getFirstVisiblePosition() == 0 && absListView.getLastVisiblePosition() == (absListView.getCount() - 1)) {
return false;
}
return (absListView.getLastVisiblePosition() < (absListView.getCount() - 1))
&& lastChild.getBottom() > absListView.getPaddingBottom();
} else {
return false;
}
} else if (mTarget instanceof RecyclerView) {
final RecyclerView recyclerView = (RecyclerView) mTarget;
LinearLayoutManager lm = (LinearLayoutManager) recyclerView.getLayoutManager();
int count = recyclerView.getAdapter().getItemCount() - 1;
if (lm.canScrollVertically()) {
return !(lm.findLastVisibleItemPosition() == count);
} else {
return false;
}
} else {
View scrollChild = ((ViewGroup) mTarget).getChildAt(0);
if (scrollChild == null) {
return false;
} else {
int childHeight = scrollChild.getMeasuredHeight();
return (mTarget.getScrollY() + mTarget.getHeight()) < childHeight;
}
}
} else {
return ViewCompat.canScrollVertically(mTarget, 1);
}
}
空白页面支持
一般在没有数据的时候我们希望显示一个缺省的空白页面,类似于ListView
的emptyView
这里除了添加上空白页面支持外,还需做一些小的改变。在显示空白页面时,我们希望只有动画可拽动而空白页面不会被拽动,也就是侵入式的下拉效果(非侵入式效果即之前的正常列表的下拉)
public DragRefreshLayout(Context context, AttributeSet attrs) {
// .......
emptyId = a.getResourceId(R.styleable.refresh_DragRefreshLayout_refresh_empty, 0);
// .......
}
private void ensureTarget() {
// .....
if (emptyId != 0) {
emptyView = findViewById(emptyId);
emptyView.setClickable(true);
}
}
VDH的tryCaptureView
中增加是否是emptyView
的判断
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child == mTarget
|| (child == emptyView && emptyView.isShown())
|| child == refreshView
|| child == loadView;
}
不要忘了clampViewPositionVertical
:
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
if (child == mTarget || (child == emptyView && emptyView.isShown())) {
status = ScrollStatus.DRAGGING;
if (contentTop + dy > DRAG_MAX_RANGE) {
return DRAG_MAX_RANGE;
} else if (contentTop + dy < -DRAG_MAX_RANGE) {
return -DRAG_MAX_RANGE;
} else {
return top;
}
} else {
status = ScrollStatus.DRAGGING;
if (contentTop + dy > DRAG_MAX_RANGE) {
return DRAG_MAX_RANGE - refreshView.getMeasuredHeight();
} else if (contentTop + dy < -DRAG_MAX_RANGE) {
return getMeasuredHeight() - getPaddingBottom() - DRAG_MAX_RANGE;
} else {
return top;
}
}
}
侵入式下拉即下拉时emptyView
的位置不变,其他视图的位置依然变化:
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
if (changedView == mTarget) {
//......
} else if (changedView == emptyView && emptyView.isShown()) {
refreshView.offsetTopAndBottom(dy);
loadView.offsetTopAndBottom(dy);
contentTop = top;
invalidate();
} else {
// .......
}
}
因为控件不维护数据内容,控件本身没有设置空白页面展示与隐藏的能力,不比
ListView
,因此只能在业务中判断数据是否为空并且显示或者隐藏空白页面
到此,整个DragRefresh
控件完成,have a happy day!