1. 程式人生 > >android 鎖定ScrollView 使其滑到一定程度不能滑動

android 鎖定ScrollView 使其滑到一定程度不能滑動

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 方法;