概念
滑动是如何产生的
滑动一个VIew,本质上是移动一个View。移动一个View需要改变他的坐标,所以滑动一个View分为两步:
- 监听用户的触摸事件,并获得事件的坐标。
- 根据事件坐标动态且不断的改变View的坐标。
坐标系
-
Android坐标系,以屏幕为坐标原点,Y轴向下,X轴向右增大可以通过
getLocationOnScreen(int location[])
来获取。触控事件中使用getRawX()
、getRawY()
来获取 -
视图坐标系,以父视图的左上角为坐标原点。在触控事件中,通过
getX()
,getY()
来获取
触控事件
触控事件MothinEvent,它封装了一些常量
//单点触摸按下动作
public static final int ACTION_DOWN = 0;
//单点触摸离开动作
public static final int ACTION_UP= 1;
//触摸点移动操作
public static final int ACTION_MOVE = 2;
//触摸动作取消
public static final int ACTION_CANCEL= 3;
//触摸动作超出边界
public static final int ACTION_OUTSIDE = 4;
//多点触控按下操作
public static final int ACTION_PIOINTER_MOVE = 5;
//多点离开动作
public static final int ACTION_PIOINTER_UP= 6;
在代码中
@Override
public boolean onTouchEvent(MotionEvent event) {
//视图坐标
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//处理按下操作
break;
case MotionEvent.ACTION_MOVE:
//处理移动事件
break;
case MotionEvent.ACTION_UP:
//处理输入离开事件
break;
}
return true;
}
获取坐标的方法:
- VIew提供的方法:getTop(),getLeft(),getRight(),getBottom.分别获取View自身到父布局上左右下的距离
- MotionEvent提供的方法:视图坐标getX(),getY();绝对坐标getRawX(),getRawY()(使用绝对坐标时,需要保存上次的坐标)
滑动的七种方式
在自定义view中处理onTouchEvent事件,通过获取到手指移动的距离.启动方式都是通过移动的距离来移动view的。
方式一:layout方法
方式二:offsetLeftAndRight(),offsetTopAndBottom()
方式三:layoutParams
方式四:scrollTo与scrollBy
scrollTo是移动到一个具体的坐标点,scrollBy是移动一段距离。
使用scrollTo与scrollBy移动的是content,所以需要getParent(),且因为坐标的参考系的变化,移动的值需要为相反数。
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
int offsetX = x - lastX;
int offsetY = y - lastY;
//方式一:layou
layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY);
//方式二:offsetLeftAndRight
offsetLeftAndRight(offsetX);
offsetTopAndBottom(offsetY);
//方式三:LayoutParams
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
layoutParams.leftMargin = getLeft() + offsetX;
layoutParams.topMargin = getTop() + offsetY;
setLayoutParams(layoutParams);
//方式四scrollBy
((View)getParent()).scrollBy(-offsetX,-offsetY);
break;
case MotionEvent.ACTION_UP:
break;
}
方式五:Scroller
Scroller是一个辅助类,只是不断的改变值。本质还是使用scrollTo与scrollBy来移动VIew,方法有:
public void startScroll(int startX,int startY,int dx, int dy,int duration)
public void startScroll(int startX,int startY,int dx, int dy)
使用步骤:
- 初始化Scroller
- 重写computeScroll(),实现模拟滑动
- startScroll开启模拟过程
computeScroll不会主动调用,只能通过invalidate()->draw()-> computeScroll()
方式六:属性动画
方式七: ViewDragHelper
public class DragViewGroup extends FrameLayout {
private ViewDragHelper mViewDragHelper;
private View mMenuView, mMainView;
private int mWidth;
public DragViewGroup(@NonNull Context context) {
super(context);
initView();
}
public DragViewGroup(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView();
}
public DragViewGroup(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mMenuView = getChildAt(0);
mMainView = getChildAt(1);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = mMenuView.getMeasuredWidth();
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mViewDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mViewDragHelper.processTouchEvent(event);
return true;
}
private void initView() {
mViewDragHelper = ViewDragHelper.create(this, callback);
}
private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(View child, int pointerId) {
return mMainView == child;
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
return left;
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
return 0;
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
if (mMainView.getLeft() < 500) {
mViewDragHelper.smoothSlideViewTo(mMainView, 0, 0);
ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
} else {
mViewDragHelper.smoothSlideViewTo(mMainView, 300, 0);
ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
}
}
};
@Override
public void computeScroll() {
super.computeScroll();
if (mViewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
}
网友评论