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

一.简介

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

 

 

 

 

 

 

二.View的scrollBy和scrollTo方法

 

图解

 

 

1.scrollBy方法

public void scrollBy (int x, int y)

 

作用

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

 

参数

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

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

 

 

2.scrollTo方法

public void scrollTo (int x, int y)

 

作用

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

 

参数

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

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

 

 

 

3.scrollTo实现Demo

布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/activity_marginlayout_layout"
    android:orientation="vertical">

    <TextView
        android:id="@+id/activity_marginlayout_textview1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:background="#FF0000"
        android:gravity="center"
        android:padding="10dp"
        android:text="scrollTo方法测试"
        android:textColor="#FFFFFF" />


</RelativeLayout>

 

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);
            }
        });

    }

}

 

效果

原始

 

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

 

 

 

4.scrollBy实现Demo

布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/activity_marginlayout_layout"
    android:orientation="vertical">

    <TextView
        android:id="@+id/activity_marginlayout_textview1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:background="#FF0000"
        android:gravity="center"
        android:padding="10dp"
        android:text="scrollBy方法测试"
        android:textColor="#FFFFFF" />


</RelativeLayout>

 

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);
            }
        });

    }

}

 

效果

原始

 

点击

 

多次点击

 

 

 

 

 

三.Scroller工具类使用

 

1.Scroller使用步骤

<1> 创建Scroller的实例。

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

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

 

 

2.Demo实现仿ViewPager滑动

自定义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();
        }
    }
}

 

布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/activity_marginlayout_layout"
    android:orientation="vertical">

    <com.wjn.sqlitedemo.view.ScrollerLayout
        android:id="@+id/activity_marginlayout_scrollerlayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </com.wjn.sqlitedemo.view.ScrollerLayout>


</RelativeLayout>

 

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);
        }

    }

}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值