自定义横向日期选择器,可滑动,可点击

自定义横向日期选择器,可滑动,可点击_第1张图片
布局文件比较简单,直接上代码:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >

    <LinearLayout
        android:id="@+id/ll"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/btn_left"
            android:layout_width="24dp"
            android:layout_height="match_parent" />

        <com.wscq.dataindicator.DataIndicatorView
            android:id="@+id/data_indicator"
            android:layout_width="0dp"
            android:layout_height="135dp"
            android:layout_weight="1" >
        com.wscq.dataindicator.DataIndicatorView>

        <Button
            android:id="@+id/btn_right"
            android:layout_width="24dp"
            android:layout_height="match_parent" />
    LinearLayout>

    <TextView
        android:id="@+id/tv_context"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/ll"
        android:gravity="center"
        android:textSize="30sp" />

RelativeLayout>

其中主要的难度就是自定义了一个横向的LinearLayout,其中因为只是拦截横向滚动,所以需要有如下的事件分发代码:


    /** 事件分发,只拦截横向滑动,不拦截其他事件 */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean intercepted = false;
        int x = (int) ev.getX();
        int y = (int) ev.getY();

        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            intercepted = false;
            if (!mScroller.isFinished()) {
                mScroller.abortAnimation();
                intercepted = true;
            }
            break;
        }
        case MotionEvent.ACTION_MOVE: {
            int deltaX = x - mLastXIntercept;
            int deltaY = y - mLastYIntercept;
            // 判断是不是横向滑动
            if (Math.abs(deltaX) > Math.abs(deltaY)) {
                intercepted = true;
            } else {
                intercepted = false;
            }
            // 判断是否是有效的滑动
            if (Math.abs(deltaX) < ViewConfiguration.get(getContext()).getScaledTouchSlop()) {
                intercepted = false;
            }
            break;
        }
        case MotionEvent.ACTION_UP: {
            intercepted = false;
            break;
        }
        default:
            break;
        }
        mLastX = x;
        mLastY = y;
        mLastXIntercept = x;
        mLastYIntercept = y;
        return intercepted;
    }

    /** 横向滑动时候的相关处理操作 */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mVelocityTracker.addMovement(event);
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            if (!mScroller.isFinished()) {
                mScroller.abortAnimation();
            }
            break;
        }
        case MotionEvent.ACTION_MOVE: {
            // 获取水平方向的移动距离
            int deltaX = x - mLastX;
            // 因为是水平移动,所以这个变量并没有使用
            int deltaY = y - mLastY;
            // 移动到对应的地方
            scrollBy(-deltaX, 0);
            break;
        }
        case MotionEvent.ACTION_UP: {
            // 设置滚动时间
            mVelocityTracker.computeCurrentVelocity(1000);
            // 当水平距离大于某个值时候,移动到下一页,否则停留在当前页
            float xVelocity = mVelocityTracker.getXVelocity();
            int page = mChoosePage;
            if (Math.abs(xVelocity) >= mLayoutWidth / 3) {
                // 更新当前屏幕的页数
                page = xVelocity > 0 ? page - 1 : page + 1;
            }
            scrollPage(page);
            mVelocityTracker.clear();
            break;
        }
        default:
            break;
        }
        // 更新最后触摸点的坐标
        mLastX = x;
        mLastY = y;
        return true;
    }

这里的横向滑动是弹性滑动,实现弹性滑动需要有如下代码:

/**
 * 页数改变时的滚动方法
 * 
 * @param page
 */
public void scrollPage(int page) {
    // 取到正确的page值
    mChoosePage = Math.max(0, Math.min(page, mPageSum));
    // 如果显示的不是当前页,重置所有文字颜色,防止view复用引发的字体颜色显示异常
    if (mChooseIndex / 7 == mChoosePage) {
        highLightTextView(mChooseIndex);
    } else {
        resetTextViewColor();
    }

    // 滚动到对应的位置
    int scrollX = getScrollX();
    int delta = mChoosePage * mLayoutWidth - scrollX;
    mScroller.startScroll(scrollX, 0, delta, 0, 1000);
    invalidate();

    // 回调页面改变监听
    if (null != listener) {
        listener.onPageChangedListener(mChoosePage);
    }
}

/** 覆写方法,用来实现弹性滑动 */
@Override
public void computeScroll() {
    super.computeScroll();
    if (mScroller.computeScrollOffset()) {
        scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
        postInvalidate();
    }
}

“`

具体的代码可以参考如下地址:
https://github.com/h55l55/DateIndicator

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