自定义滑动控件简例

xiaoxiao2021-02-28  69

一、Scroller的使用

为了更好的了解一下滑动控件,我们需要先了解一下Scroller的作用. Scroller可以说是View的辅助类,在使用它之前,用户需要通过startScroll的参数,即起始坐标和(x,y)轴上需要滚动的距离,可以理解为一条用点表达的有向线段,调用方法为:mScroller.startScroll(x0,y0,x1,y1)。由于Scroller封装了时间,要滚动的目标x轴和y轴,以及在每个时间内View应该滚动到的(x,y)轴坐标,用户就可以通过Scroller对象的getCurX()和getCurY()方法来获取当前时刻View应该滚动到的位置。然后通过View的scrollTo和scrollBy方法来进行滚动,那么如何判断滚动是否结束呢,我们需要重写View类的computeScroll()方法,该方法会在View绘制的时候被调用,在里面调用Scroller对象的computeScrollOffset方法判断滚动是否完成,如果返回true表示未完成,如果返回false表示完成。而上述的scrollTo和scrollBy方法就是在返回值为true时调用。并且最后还需要调用postInvalidate()或者Invalidate()方法实现View的重绘。View的重绘会导致computeScroll方法被调用,从而继续整个过程。 以上内容都是书面话语,不是我个人理解,但是本人也是靠着这些解释和定义逐渐明白怎么自己写滑动控件的,下面来说一下本人对于滑动的理解。当然这些理解是本人在写滑动控件的摸索过程中自己的经验之谈,对与不对欢迎大家指点。 首先声明,我下面的自定义的控件并未实际用到Scroller。 Scroller实现的滑动是非接触性滑动,可以理解为惯性滑动(例如:你滑动ListView控件时,当你的手离开后,控件的持续性滑动,这种滑动不是你的手带动,而是类似于惯性(背后算个暂时未研究),这是通过Scoller和View本身的scrollTo和scrollBy实现的)或者弹性滑动(下拉刷新) 而不使用Scroller实现的滑动,则是接触性滑动,也就是View的滑动只会根据你滑动的变化,在根据View本身的scrollTo和scrollBy实现滑动,如果你没有接触View,不管你向下或者向上再怎么使劲,当你手离开是,他也不会再滑动了。而我下面实现的滑动就是接触性滑动。

Demo 实例

package com.test.hudezhi.testroject.customview.scrolllayout; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.Scroller; import com.test.hudezhi.testroject.R; public class SquareScroll extends ViewGroup { private Scroller mScroller; private View footerView; private View bodyView; private View headerView; private LayoutInflater inflater; private int initHeight; private int initBottom; private int downScroll; private int mLastY; public SquareScroll(Context context) { this(context, null); } public SquareScroll(Context context, AttributeSet attrs) { this(context, attrs, 0); } public SquareScroll(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mScroller = new Scroller(context); inflater = LayoutInflater.from(context); initView(); } @Override public void computeScroll() { // 并未起到实际作用,因为mScroller.startScroll()方法没有调用 super.computeScroll(); if (mScroller.computeScrollOffset()) { this.scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); this.postInvalidate(); } } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { final int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_UP: break; case MotionEvent.ACTION_MOVE: break; } return false; } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mLastY = (int) event.getRawY(); break; case MotionEvent.ACTION_UP: break; case MotionEvent.ACTION_MOVE: int currentY = (int) event.getRawY(); Log.i("", "" + currentY); int deltaY = currentY - mLastY; if (deltaY > 0) { //向下拉 if (downScroll >= initHeight) { //上一次已经到顶部 downScroll = initHeight; } else { if (downScroll + deltaY >= initHeight) { //当前滑动滑到了顶部 //滑到顶部 scrollTo(0, 0); downScroll = initHeight; } else { //当前没有滑到底部 downScroll += deltaY; whetherScroll(deltaY); } } } else if (deltaY < 0) { //向上滑 if (downScroll <= -initBottom) { downScroll = (-initBottom); } else { if (downScroll + deltaY <= (-initBottom)) { int finalY = initBottom + initHeight; scrollTo(0, finalY); downScroll = (-initBottom); } else { downScroll += deltaY; whetherScroll(deltaY); } } } mLastY = currentY; break; } return true; //滑动事件自己消费 } private void whetherScroll(int offsetY) { scrollBy(0, -offsetY); this.invalidate(); } private void initView() { initHeaderView(); initBodyView(); initFooterView(); } private void initHeaderView() { headerView = inflater.inflate(R.layout.header, this, false); LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); headerView.setLayoutParams(lp); addView(headerView); } private void initBodyView() { bodyView = inflater.inflate(R.layout.body, this, false); LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); bodyView.setLayoutParams(lp); addView(bodyView); } private void initFooterView() { footerView = inflater.inflate(R.layout.footer, this, false); LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); footerView.setLayoutParams(lp); addView(footerView); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int tempHeight = 0; int tempWidth = 0; int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); measureChild(child, widthMeasureSpec, heightMeasureSpec); int childWidth = child.getMeasuredWidth(); tempWidth = Math.max(childWidth, tempWidth); tempHeight += child.getMeasuredHeight(); } heightSize = Math.max(tempHeight, heightSize); widthSize = Math.max(tempWidth, widthSize); setMeasuredDimension(widthSize, heightSize); } @Override protected void onLayout(boolean is, int l, int t, int r, int b) { int childCount = getChildCount(); int left = 0; int top = 0; for (int i = 0; i < childCount; i++) { View child = getChildAt(i); child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight()); top += child.getMeasuredHeight(); } initHeight = headerView.getMeasuredHeight(); initBottom = footerView.getMeasuredHeight(); scrollTo(0, initHeight); } }
转载请注明原文地址: https://www.6miu.com/read-73741.html

最新回复(0)