android 锁定ScrollView 使其滑到一定程度不能滑动

叶卓君
2023-12-01

Scroller学习

1) scrollTo 和 scrollBy

View自带的两个方法

左加右减,上加下减

2) 平滑效果,使用Scroller

  1. 创建Scroller的实例
  2. 调用startScroll()方法来初始化滚动数据并刷新界面
  3. 重写computeScroll()方法,并在其内部完成平滑滚动的逻辑

3) 案例:ScrollView滑到一定位置不能锁定不能滑动了

package com.abilix.learn.dashpinyinisland1.view;

import android.content.Context;
import android.support.v4.view.ViewConfigurationCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.widget.ScrollView;
import android.widget.Scroller;

/**
 * Created by yanghd on 2017/6/9.
 */

public class SlowScrollView extends ScrollView {

    private Scroller mScroller;

    public SlowScrollView(Context context) {
        this(context,null);
    }

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

    public SlowScrollView(Context context, AttributeSet attrs, int defStyle) {
        this(context, attrs);

    }

    //调用此方法滚动到目标位置  duration滚动时间
    public void smoothScrollToSlow(int fx, int fy, int duration) {
        int dx = fx - getScrollX();//mScroller.getFinalX();  普通view使用这种方法
        int dy = fy - getScrollY();  //mScroller.getFinalY();
        smoothScrollBySlow(dx, dy, duration);
    }

    //调用此方法设置滚动的相对偏移
    public void smoothScrollBySlow(int dx, int dy, int duration) {

        //设置mScroller的滚动偏移量
        mScroller.startScroll(getScrollX(), getScrollY(), dx, dy, duration);//scrollView使用的方法(因为可以触摸拖动)
//        mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy, duration);  //普通view使用的方法
        invalidate();//这里必须调用invalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果
    }

    @Override
    public void computeScroll() {

        //先判断mScroller滚动是否完成
        if (mScroller.computeScrollOffset()) {

            //这里调用View的scrollTo()完成实际的滚动
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());

            //必须调用该方法,否则不一定能看到滚动效果
            postInvalidate();
        }
        super.computeScroll();
    }

    /**
     * 滑动事件,这是控制手指滑动的惯性速度
     */
    @Override
    public void fling(int velocityY) {
        super.fling(velocityY / 400);
    }


    // -------------------  新增方法  ------------------
    /**
     * 手机当时所处的屏幕坐标
     */
    private float mYMove;

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

    /**
     * 界面可滚动的上边界
     */
    private int upBorder;

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

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

/*    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {

            case MotionEvent.ACTION_DOWN:
                mYDown = ev.getRawY();
                mYLastMove = mYDown;
                Log.d("SlowScrollView", "拦截Down");
                break;

            case MotionEvent.ACTION_MOVE:
                mYMove = ev.getRawY();
                float diff = Math.abs(mYMove - mYDown);
                mYLastMove = mYMove;
                // 当手指拖动值大于TouchSlop值时,认为应该进行滚动,拦截子控件的事件
                if (diff > mTouchSlop) {
                    Log.d("SlowScrollView", "diff:" + diff);
                    Log.d("SlowScrollView", "mTouchSlop:" + mTouchSlop);
                    Log.d("SlowScrollView", "拦截Move");
                    return true;
                }
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }*/

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {

            case MotionEvent.ACTION_MOVE:
                Log.d("SlowScrollView", "执行Move");
                mYMove = event.getRawY();
                int scrolledY = (int) (mYLastMove - mYMove);
                if (getScrollY() + scrolledY < upBorder) {
                    scrollTo(0, upBorder);
                    return true;
                }
                scrollBy(scrolledY, 0);
                mYLastMove = mYMove;
                break;

            case MotionEvent.ACTION_UP:
                Log.d("SlowScrollView", "执行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);
    }

    public void setUpBorder(int upBorder) {
        this.upBorder = upBorder;
    }

}

其实可以直接不重写 onInterceptTouchEvent 方法;

 类似资料: