写点什么

自定义 View:如何手动实现 ViewGroup 的拖拽

作者:Changing Lin
  • 2021 年 11 月 19 日
  • 本文字数:2611 字

    阅读完需:约 9 分钟

1.知识点

  • VelocityTracker:速度跟踪器

  • View.scrollTo:把当前 View 移动到 具体的某个位置(x, y)

  • View.scrollBy:把当前 View 移动在原有位置偏移多少变化量(dx, dy)

  • View.computeScroll:当子 View 在发生滑动的时候,即 mScrollX 和 mScrollY 会发生变化的时候,父布局会调用这个方法

  • scrollTo 和 scrollBy 方法只能改变 view 内容的位置而不能改变 view 在布局中的位置。 scrollBy 是基于当前位置的相对滑动,而 scrollTo 是基于所传参数的绝对滑动。通过 View 的 getScrollX 和 getScrollY 方法可以得到滑动的距离。

2.原理

  • downScrollX 的含义:记录 我当前在 X 轴上滑动了的距离

  • 滑动偏移量的计算:

float dx = downX - event.getX() + downScrollX; // 表示当前MOVE事件滑动了多少距离 + 起始的位置,得到最终的偏移
复制代码
  • 实现父控件跟随手指滑动的方法:scrollTo(dx, 0)

3.代码

package com.besmart.components;
import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.VelocityTracker;import android.view.View;import android.view.ViewConfiguration;import android.view.ViewGroup;import android.widget.OverScroller;
public class VirtualViewPager extends ViewGroup { private static final String TAG = "SimulatorViewPager";
float downX; float downY; float downScrollX; // 我当前滑动
VelocityTracker velocityTracker = VelocityTracker.obtain(); ViewConfiguration viewConfiguration; private float maxVelocity; private float minVelocity; OverScroller overScroller;
public VirtualViewPager(Context context, AttributeSet attrs) { super(context, attrs); viewConfiguration = ViewConfiguration.get(context); minVelocity = viewConfiguration.getScaledMinimumFlingVelocity(); maxVelocity = viewConfiguration.getScaledMaximumFlingVelocity(); overScroller = new OverScroller(context); }
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { measureChildren(widthMeasureSpec, heightMeasureSpec); super.onMeasure(widthMeasureSpec, heightMeasureSpec); }
@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { int count = getChildCount(); Log.e(TAG, String.format("onLayout: 当前有几个子View %d-%d-%d-%d-%d", count, left, top, right, bottom));
int childWidth = getWidth(); for (int i = 0; i < count; i++) { View child = getChildAt(i); child.layout(left, top, right, bottom); left += childWidth; right += childWidth; } }
@Override public boolean onTouchEvent(MotionEvent event) { Log.e(TAG, "onTouchEvent: "+event.toString());
if (event.getActionMasked() == MotionEvent.ACTION_DOWN){ velocityTracker.clear(); }
velocityTracker.addMovement(event);
switch (event.getActionMasked()){ case MotionEvent.ACTION_DOWN: downX = event.getX(); downY = event.getY(); downScrollX = getScrollX(); // 初始值 break; case MotionEvent.ACTION_MOVE: float dx = downX - event.getX() + downScrollX; if (dx > getWidth()) dx = getWidth(); else if (dx<0){ dx = 0; } scrollTo((int) dx, 0); break; case MotionEvent.ACTION_UP: velocityTracker.computeCurrentVelocity(1000, maxVelocity); float vx = velocityTracker.getXVelocity(); // 横向速度
int scrollX = getScrollX(); int targetPage; if (Math.abs(vx) < minVelocity){ targetPage = scrollX> getWidth()/2? 1: 0; }else { targetPage = vx <0? 1: 0; } int scrollDistance = targetPage == 1? getWidth()-scrollX: -scrollX;
// scrollTo(targetPage*getWidth(), 0); overScroller.startScroll(scrollX, 0, scrollDistance, 0); postInvalidateOnAnimation();// getParent().requestDisallowInterceptTouchEvent(false); break; default:break; } return true; }
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.e(TAG, "onInterceptTouchEvent: "+ev.toString()); boolean result = false; switch (ev.getActionMasked()){ case MotionEvent.ACTION_DOWN: downX = ev.getX(); downY = ev.getY(); downScrollX = getScrollX(); // 初始值 break; case MotionEvent.ACTION_MOVE: if (Math.abs(ev.getX()-downX) > viewConfiguration.getScaledPagingTouchSlop()){ getParent().requestDisallowInterceptTouchEvent(true); // 请求父控件禁止拦截事件 result = true; // 开始拦截事件 } break; default:break; } return result; }
@Override public void computeScroll() { if (overScroller.computeScrollOffset()){ scrollTo(overScroller.getCurrX(), overScroller.getCurrY()); postInvalidateOnAnimation(); } }}
复制代码


发布于: 4 小时前阅读数: 9
用户头像

Changing Lin

关注

获得机遇的手段远超于固有常规之上~ 2020.04.29 加入

我能做的,就是调整好自己的精神状态,以最佳的面貌去面对那些未曾经历过得事情,对生活充满热情和希望。

评论

发布
暂无评论
自定义View:如何手动实现ViewGroup的拖拽