作者:手机用户2502887521 | 来源:互联网 | 2023-10-17 13:32
涉及的知识点-ViewGroup的测量与布局-View的测量与布局-滑动冲突的处理-VelocityTracker滑动速率跟踪-Scroller实现弹性滑动-屏幕宽高的获取等实现步
涉及的知识点 - ViewGroup的测量与布局- View的测量与布局- 滑动冲突的处理- VelocityTracker滑动速率跟踪- Scroller实现弹性滑动- 屏幕宽高的获取等
实现步骤 1. 创建MyScrollView继承ViewGroup,实现构造与方法2. 在onMeasure方法中对子View进行测量,同时计算出ViewGroup的宽高,并通过setMeasuredDimension设置3. 在onLayout方法中进行布局4. 在onInterceptTouchEvent方法中进行滑动冲突的处理5. 在onTouchEvent方法中进行滑动事件的处理6. 实现弹性滑动
具体实现 继承ViewGroup public class MyScrollView extends ViewGroup {/*** 可视为点击事件的距离,视为滑动的临界值*/ private int touchSlop;private Scroller mScroller;/*** 屏幕宽度*/ private int screenHeight;/*** 滑动速度跟踪类*/ private VelocityTracker velocityTracker;/*** 滑动的起始坐标*/ private int startX, startY;/*** getScrollY的起始与结束值*/ private int startScrollY, endScrollY;public MyScrollView (Context context) {this (context, null );}public MyScrollView (Context context, AttributeSet attrs) {this (context, attrs, 0 );}public MyScrollView (Context context, AttributeSet attrs, int defStyleAttr) {super (context, attrs, defStyleAttr);touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();mScroller = new Scroller(context, new OvershootInterpolator()); screenHeight = getScreenHeight(context);}
/*** 获取屏幕高*/ private int getScreenHeight (Context context) {Display d = ((Activity) context).getWindowManager().getDefaultDisplay();Point outSize = new Point();d.getSize(outSize); return outSize.y;}
onMeasure中进行测量 @Override protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {super .onMeasure(widthMeasureSpec, heightMeasureSpec);final int measureHeight = measureHeight(heightMeasureSpec); final int measureWidth = measureWidth(widthMeasureSpec); int totalHeight = 0 ; int maxWidth = 0 ; measureChildren(widthMeasureSpec, heightMeasureSpec); int childCount = getChildCount(); for (int i = 0 ; i int height = child.getMeasuredHeight();int width = child.getMeasuredWidth();totalHeight += height;maxWidth = Math.max(maxWidth, child.getMeasuredWidth() + child.getPaddingLeft() + child.getPaddingRight());}setMeasuredDimension(Math.max(measureWidth, maxWidth), Math.max(measureHeight, totalHeight));}/*** 通过widthMeasureSpec得到的宽度** @param widthMeasureSpec* @return */ private int measureWidth (int widthMeasureSpec) {int mode = MeasureSpec.getMode(widthMeasureSpec);int specSize = MeasureSpec.getSize(widthMeasureSpec);int finalSize = 200 ; switch (mode) {case MeasureSpec.EXACTLY:finalSize = specSize;break ;case MeasureSpec.AT_MOST:finalSize = Math.min(finalSize, specSize);break ;}return finalSize;}/*** 通过heightMeasureSpec得到的高度** @param heightMeasureSpec* @return */ private int measureHeight (int heightMeasureSpec) {int mode = MeasureSpec.getMode(heightMeasureSpec);int specSize = MeasureSpec.getSize(heightMeasureSpec);int finalSize = 200 ;switch (mode) {case MeasureSpec.EXACTLY:finalSize = specSize;break ;case MeasureSpec.AT_MOST:finalSize = Math.min(finalSize, specSize);break ;}return finalSize;}
onLayout方法中进行布局 @Override protected void onLayout (boolean changed, int l, int t, int r, int b) {int childCount = getChildCount(); child.layout(l, screenHeight * i, r, screenHeight * (i + 1 ));}}
onInterceptTouchEvent滑动冲突处理 /*** 滑动冲突处理,* 当Y方向滑动大于X方向滑动距离,并且Y方向滑动距离大于touchSlop时,拦截事件* 其他情况不拦截** @param ev* @return */ @Override public boolean onInterceptTouchEvent (MotionEvent ev) {boolean result = false ;switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:startX = (int ) ev.getX();startY = (int ) ev.getY();break ;case MotionEvent.ACTION_MOVE:int dX = (int ) (ev.getX() - startX);int dY = (int ) (ev.getY() - startY);if (Math.abs(dY) > Math.abs(dX) && Math.abs(dY) > touchSlop) { result = true ;} else {result = false ;}break ;}return result;}
onTouchEvent滑动事件的处理 &#64;Override public boolean onTouchEvent (MotionEvent ev) {switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:if (velocityTracker &#61;&#61; null ) {velocityTracker &#61; VelocityTracker.obtain();} else {velocityTracker.clear(); }velocityTracker.addMovement(ev); if (!mScroller.isFinished())mScroller.abortAnimation();startX &#61; (int ) ev.getX();startY &#61; (int ) ev.getY();startScrollY &#61; getScrollY();break ;case MotionEvent.ACTION_MOVE:velocityTracker.addMovement(ev); velocityTracker.computeCurrentVelocity(50 ); int dX &#61; (int ) (ev.getX() - startX);int dY &#61; (int ) (ev.getY() - startY);if (Math.abs(getScrollY()) > screenHeight * (getChildCount() - 1 ) && dY <0 ) { return false ;}scrollBy(0 , -dY);break ;case MotionEvent.ACTION_UP:endScrollY &#61; getScrollY();int deltaScrollY &#61; endScrollY - startScrollY;int page &#61; Math.abs(endScrollY / screenHeight); if (Math.abs(velocityTracker.getYVelocity()) > 100 && page !&#61; getChildCount() - 1 ) { if (velocityTracker.getYVelocity() > 100 ) { smoothScroll(0 , getScrollY(), 0 , -getScrollY() &#43; page * screenHeight, 500 ); } else if (-velocityTracker.getYVelocity() > 100 ) { smoothScroll(0 , getScrollY(), 0 , -getScrollY() &#43; (page &#43; 1 ) * screenHeight, 500 ); }} else {if (deltaScrollY <0 ) { if (Math.abs(deltaScrollY) 3) { smoothScroll(0 , getScrollY(), 0 , -deltaScrollY, deltaScrollY * 2 );} else { smoothScroll(0 , getScrollY(), 0 , -getScrollY() &#43; page * screenHeight, deltaScrollY * 2 );}} else { if (deltaScrollY > screenHeight / 3 ) { smoothScroll(0 , getScrollY(), 0 , -getScrollY() &#43; (page &#43; 1 ) * screenHeight, deltaScrollY * 2 );} else { smoothScroll(0 , getScrollY(), 0 , -deltaScrollY, deltaScrollY * 2 );}}}break ;}startX &#61; (int ) ev.getX();startY &#61; (int ) ev.getY();return true ;}
弹性滑动的实现 /*** 弹性滑动* &#64;param startX* &#64;param startY* &#64;param dX* &#64;param dY* &#64;param duration*/ private void smoothScroll (int startX, int startY, int dX, int dY, int duration) {if (Math.abs(duration) > 800 ) duration &#61; 800 ;mScroller.startScroll(startX, startY, dX, dY, Math.abs(duration));invalidate();}&#64;Override public void computeScroll () {super .computeScroll();if (mScroller.computeScrollOffset()) {scrollTo(mScroller.getCurrX(), mScroller.getCurrY());invalidate();}}
源码&#xff1a; http://download.csdn.net/detail/qq_28261343/9600431