自定义滑动控件简例

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

猜你喜欢

转载自blog.csdn.net/qq_35920289/article/details/77771308