1.记录一下自己自定义View
2.直接子View只能是一个
public class SlideView extends ViewGroup {
private static final String TAG = "ScrollLinearLayout";
private int lastY;//记录上一个位置
private Scroller mScroller;//回弹的动画效果
private View mChildView;
public SlideView(Context context) {
this(context, null);
}
public SlideView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public SlideView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
private void initView(Context context) {
mScroller = new Scroller(context);
setClickable(true);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
int childCount = getChildCount();
if (childCount > 1) {
throw new RuntimeException("只能有一个子View");
}
mChildView = getChildAt(0);
if (mChildView == null) {
throw new RuntimeException("没有子View");
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int y = (int) event.getY();
Log.e(TAG, "onTouchEvent: y==" + y);
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
int mScrollY = lastY - y;//手指滑动的距离
Log.e(TAG, "dispatchTouchEvent: mScrollY==" + mScrollY + " getScrollY()==" + getScrollY());
/**
* 子View在中间,触摸事件交给子View
*/
if (!canPullDown() && !canPullUp()) {
lastY = y;
if (getScrollY() != 0) {//子View到了中间位置,父View还有移动的距离,父View恢复原位
int scrollY = getScrollY();
mScroller.startScroll(0, scrollY, 0, -scrollY, 0);
invalidate();
}
break;
}
if (canPullDown() && mScrollY < 0) {//顶部往下拉
mScrollY = (int) (mScrollY * scan());
} else if (canPullUp() && mScrollY > 0) {//底部往上拉
mScrollY = (int) (mScrollY * scan());
} else {
if (Math.abs(mScrollY) > Math.abs(getScrollY())) {//边界问题,移动的距离大于当前的滑动的距离
mScrollY = -getScrollY();
}
}
scrollBy(0, mScrollY);//滑动
if (getScrollY() == 0) {
break;
}
lastY = y;
return true;//事件自己消费
case MotionEvent.ACTION_UP:
int scrollY = getScrollY();
mScroller.startScroll(0, scrollY, 0, -scrollY);
invalidate();
break;
}
lastY = y;
return super.dispatchTouchEvent(event);
}
/**
* 滑动的速度
*
* @return
*/
private float scan() {
return 0.5f;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//不能用这个来测量子View的大小,不准确
// measureChildren(widthMeasureSpec, heightMeasureSpec);
measureChildWithMargins(getChildAt(0), widthMeasureSpec, 0, heightMeasureSpec, 0);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(getChildTotalWidth(), getChildTotalHeight());
} else if (widthMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(getChildTotalWidth(), heightSize);
} else if (heightMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(widthSize, getChildTotalHeight());
} else {
setMeasuredDimension(widthSize, heightSize);
}
}
/**
* 得到子View的宽度
*
* @return
*/
private int getChildTotalWidth() {
int childCount = getChildCount();
int width = 0;
for (int i = 0; i < childCount; i++) {
View childAt = getChildAt(i);
MarginLayoutParams layoutParams = (MarginLayoutParams) childAt.getLayoutParams();
width += childAt.getMeasuredWidth() + layoutParams.leftMargin;
}
return width;
}
/**
* 得到子View的高度
*
* @return
*/
private int getChildTotalHeight() {
int childCount = getChildCount();
int height = 0;
for (int i = 0; i < childCount; i++) {
View childAt = getChildAt(i);
MarginLayoutParams layoutParams = (MarginLayoutParams) childAt.getLayoutParams();
height += childAt.getMeasuredHeight() + layoutParams.topMargin;
}
return height;
}
@Override
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount = getChildCount();
Log.e(TAG, "onLayout: r==" + r + " b==" + b + " l==" + l + " t==" + t);
for (int i = 0; i < childCount; i++) {
View childAt = getChildAt(i);
MarginLayoutParams layoutParams = (MarginLayoutParams) childAt.getLayoutParams();
int left = layoutParams.leftMargin + getPaddingLeft();
int top = layoutParams.topMargin + getPaddingTop();
int right = left + childAt.getMeasuredWidth();
int bottom = top + childAt.getMeasuredHeight();
childAt.layout(left, top, right, bottom);
}
}
//到底顶部,可以下拉
private boolean canPullDown() {
if (mChildView instanceof ScrollView) {
ScrollView scrollView = (ScrollView) mChildView;
if (scrollView.getScrollY() == 0) {
return true;
}
} else if (mChildView instanceof RecyclerView) {
RecyclerView recyclerView = (RecyclerView) mChildView;
if (!recyclerView.canScrollVertically(-1)) {
return true;
}
} else if (mChildView instanceof ListView) {
ListView listView = (ListView) mChildView;
if (!listView.canScrollVertically(-1)) {
return true;
}
} else {
return true;
}
return false;
}
//到达底部,可以上拉
private boolean canPullUp() {
if (mChildView instanceof ScrollView) {
ScrollView scrollView = (ScrollView) mChildView;
boolean b = scrollView.canScrollVertically(1);
if (!b) {
return true;
}
} else if (mChildView instanceof RecyclerView) {
RecyclerView recyclerView = (RecyclerView) mChildView;
boolean b = recyclerView.canScrollVertically(1);
if (!b) {
return true;
}
} else if (mChildView instanceof ListView) {
ListView listView = (ListView) mChildView;
boolean b = listView.canScrollVertically(1);
if (!b) {
return true;
}
} else {
return true;
}
return false;
}
@Override
public void computeScroll() {
// 重写computeScroll()方法,完成回弹
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
invalidate();
}
}
}
3.使用