Android 自定义View Scroller处理滚动工具类详解

1.简介

Scroller是一个专门用于处理滚动效果的工具类,可能在大多数情况下,我们直接使用Scroller的场景并不多,但是很多大家所熟知的控件在内部都是使用Scroller来实现的,如ViewPager、ListView等。

 

 

 

2.View的scrollBy和scrollTo方法

 

2.1.图解

Android 自定义View Scroller处理滚动工具类详解_第1张图片

Android 自定义View Scroller处理滚动工具类详解_第2张图片

 

 

2.2.scrollBy方法

2.2.1.方法

public void scrollBy (int x, int y)

 

2.2.2.作用

移动你视图的滚动位置。这将导致对onScrollChanged(int, int, int, int)的调用,视图将被无效。

 

2.2.3.参数

x:X轴(水平)方向移动的距离。正值向左移动,负值向右移动,单位是像素。

y:Y轴(垂直)方向移动的距离。正值向上移动,负值向下移动,单位是像素。 

 

 

2.3.scrollTo方法

2.3.1.方法

public void scrollTo (int x, int y)

 

2.3.2.作用

设置视图的滚动位置。这将导致对onScrollChanged(int, int, int, int)的调用,视图将被无效。

 

2.3.3.参数

x:X轴(水平)方向移动到目的坐标。正值向左移动,负值向右移动,单位是像素。

y:Y轴(垂直)方向移动到目的坐标。正值向上移动,负值向下移动,单位是像素。 

 

 

 

2.3.scrollTo实现Demo

2.3.1.布局




    


 

2.3.2.Java代码

public class MarginLayoutParamsActivity extends AppCompatActivity {

    private RelativeLayout layout;
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_marginlayoutparams);

        layout= (RelativeLayout) findViewById(R.id.activity_marginlayout_layout);
        textView= (TextView) findViewById(R.id.activity_marginlayout_textview1);
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                layout.scrollTo(-100, -100);
            }
        });

    }

}

 

2.3.3.效果

 

原始:

Android 自定义View Scroller处理滚动工具类详解_第3张图片

 

点击(scrollTo到某某 所以点击一次到达指定目的地后再点击无效果)

Android 自定义View Scroller处理滚动工具类详解_第4张图片

 

 

2.4.scrollBy实现Demo

2.4.1.布局




    


 

 

2.4.2.Java代码

public class MarginLayoutParamsActivity extends AppCompatActivity {

    private RelativeLayout layout;
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_marginlayoutparams);

        layout= (RelativeLayout) findViewById(R.id.activity_marginlayout_layout);
        textView= (TextView) findViewById(R.id.activity_marginlayout_textview1);
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                layout.scrollBy(-100, -100);
            }
        });

    }

}

 

 

 

2.4.3.效果

原始:

Android 自定义View Scroller处理滚动工具类详解_第5张图片

 

点击

Android 自定义View Scroller处理滚动工具类详解_第6张图片

 

多次点击

Android 自定义View Scroller处理滚动工具类详解_第7张图片

 

 

 

3. Scroller工具类使用(参考:https://blog.csdn.net/guolin_blog/article/details/48719871)

 

3.1. Scroller使用步骤

 

 

3.1.1. 创建Scroller的实例。

3.1.2. 调用startScroll()方法来初始化滚动数据并刷新界面。

3.1.3. 重写computeScroll()方法,并在其内部完成平滑滚动的逻辑。

 

 

3.2.Demo实现仿ViewPager滑动

3.2.1.自定义View

public class ScrollerLayout extends ViewGroup {

    /**
     * 用于完成滚动操作的实例
     */
    private Scroller mScroller;

    /**
     * 判定为拖动的最小移动像素数
     */
    private int mTouchSlop;

    /**
     * 手机按下时的屏幕坐标
     */
    private float mXDown;

    /**
     * 手机当时所处的屏幕坐标
     */
    private float mXMove;

    /**
     * 上次触发ACTION_MOVE事件时的屏幕坐标
     */
    private float mXLastMove;

    /**
     * 界面可滚动的左边界
     */
    private int leftBorder;

    /**
     * 界面可滚动的右边界
     */
    private int rightBorder;

    public ScrollerLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 第一步,创建Scroller的实例
        mScroller = new Scroller(context);
        ViewConfiguration configuration = ViewConfiguration.get(context);
        // 获取TouchSlop值
        mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            View childView = getChildAt(i);
            // 为ScrollerLayout中的每一个子控件测量大小
            measureChild(childView, widthMeasureSpec, heightMeasureSpec);
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (changed) {
            int childCount = getChildCount();
            for (int i = 0; i < childCount; i++) {
                View childView = getChildAt(i);
                // 为ScrollerLayout中的每一个子控件在水平方向上进行布局
                childView.layout(i * childView.getMeasuredWidth(), 0, (i + 1) * childView.getMeasuredWidth(), childView.getMeasuredHeight());
            }
            // 初始化左右边界值
            leftBorder = getChildAt(0).getLeft();
            rightBorder = getChildAt(getChildCount() - 1).getRight();
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mXDown = ev.getRawX();
                mXLastMove = mXDown;
                break;
            case MotionEvent.ACTION_MOVE:
                mXMove = ev.getRawX();
                float diff = Math.abs(mXMove - mXDown);
                mXLastMove = mXMove;
                // 当手指拖动值大于TouchSlop值时,认为应该进行滚动,拦截子控件的事件
                if (diff > mTouchSlop) {
                    return true;
                }
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                mXMove = event.getRawX();
                int scrolledX = (int) (mXLastMove - mXMove);
                if (getScrollX() + scrolledX < leftBorder) {
                    scrollTo(leftBorder, 0);
                    return true;
                } else if (getScrollX() + getWidth() + scrolledX > rightBorder) {
                    scrollTo(rightBorder - getWidth(), 0);
                    return true;
                }
                scrollBy(scrolledX, 0);
                mXLastMove = mXMove;
                break;
            case MotionEvent.ACTION_UP:
                // 当手指抬起时,根据当前的滚动值来判定应该滚动到哪个子控件的界面
                int targetIndex = (getScrollX() + getWidth() / 2) / getWidth();
                int dx = targetIndex * getWidth() - getScrollX();
                // 第二步,调用startScroll()方法来初始化滚动数据并刷新界面
                mScroller.startScroll(getScrollX(), 0, dx, 0);
                invalidate();
                break;
        }
        return super.onTouchEvent(event);
    }

    @Override
    public void computeScroll() {
        // 第三步,重写computeScroll()方法,并在其内部完成平滑滚动的逻辑
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            invalidate();
        }
    }
}

 

3.2.2.布局

 




    

    


 

3.2.3.Java代码使用

public class MarginLayoutParamsActivity extends AppCompatActivity {

    private ScrollerLayout scrollerLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_marginlayoutparams);

        scrollerLayout= (ScrollerLayout) findViewById(R.id.activity_marginlayout_scrollerlayout);

        scrollerLayout.removeAllViewsInLayout();
        for(int i=0;i<3;i++){
            TextView textView=new TextView(this);
            textView.setBackgroundColor(Color.RED);
            textView.setTextColor(Color.WHITE);
            textView.setClickable(true);
            ViewGroup.LayoutParams layoutParams=new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,300);
            textView.setText("Scroller滑动Demo-"+"TextView-"+(i+1));
            textView.setGravity(Gravity.CENTER);
            textView.setLayoutParams(layoutParams);
            scrollerLayout.addView(textView);
        }

    }

}

 

 

 

 

你可能感兴趣的:(Android,自定义View)