Ucrop源码解析三

提纲

ucrop中用到的自定义控件HorizontalProgressWheelView解析

HorizontalProgressWheelView

绘制如图所有的滚轮,我们需要的参数有:滚轮中线段的宽高,最中间的小线段的色值,以及间隔,红色刻度的高以及色值。


思路:

  • 利用drawline方法,根据自定义属性提供的参数,绘制小线段
  • 监听touch事件,获取滚动的距离,调整drawline的参数,重新绘制
  • 对外提供事件监听

在该view中黑色小线段的高度是红色的一半,首先调用init获取绘制需要的参数:


 private void init() {
        mMiddleLineColor = ContextCompat.getColor(getContext(), R.color.ucrop_color_progress_wheel_line);

        mProgressLineWidth = getContext().getResources().getDimensionPixelSize(R.dimen.ucrop_width_horizontal_wheel_progress_line);
        mProgressLineHeight = getContext().getResources().getDimensionPixelSize(R.dimen.ucrop_height_horizontal_wheel_progress_line);
        mProgressLineMargin = getContext().getResources().getDimensionPixelSize(R.dimen.ucrop_margin_horizontal_wheel_progress_line);

        mProgressLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mProgressLinePaint.setStyle(Paint.Style.STROKE);
        mProgressLinePaint.setStrokeWidth(mProgressLineWidth);
        }
复制代码
接着关注ondraw方法: 首先获取绘制区域,还是通过canvas.getclipBound方法。 之后开始绘制,绘制分为两部分 一:绘制n条黑色线段

 int linesCount = mCanvasClipBounds.width() / (mProgressLineWidth + mProgressLineMargin);
        float deltaX = (mTotalScrollDistance) % (float) (mProgressLineMargin + mProgressLineWidth);

        mProgressLinePaint.setColor(getResources().getColor(R.color.ucrop_color_progress_wheel_line));
        for (int i = 0; i < linesCount; i++) {
            if (i < (linesCount / 4)) {
                mProgressLinePaint.setAlpha((int) (255 * (i / (float) (linesCount / 4))));
            } else if (i > (linesCount * 3 / 4)) {
                mProgressLinePaint.setAlpha((int) (255 * ((linesCount - i) / (float) (linesCount / 4))));
            } else {
                mProgressLinePaint.setAlpha(255);
            }
            canvas.drawLine(
                    -deltaX + mCanvasClipBounds.left + i * (mProgressLineWidth + mProgressLineMargin),
                    mCanvasClipBounds.centerY() - mProgressLineHeight / 4.0f,
                    -deltaX + mCanvasClipBounds.left + i * (mProgressLineWidth + mProgressLineMargin),
                    mCanvasClipBounds.centerY() + mProgressLineHeight / 4.0f, mProgressLinePaint);
        }

复制代码
这里的算法非常简单:
1. 根据参数计算出可以绘制多少条小线段 2. 将小线段分为4部分,中间两部分设置alpha为255,两边递减 3. 计算出小线段的位置,使用drawline绘制 这里需要关注的是deltaX的值(滚动距离除以最小单元的长度取余)每次滚会修改滚动距离,并重新绘制。
二:绘制一条红色线段

  mProgressLinePaint.setColor(mMiddleLineColor);
        canvas.drawLine(mCanvasClipBounds.centerX(), mCanvasClipBounds.centerY() - mProgressLineHeight / 2.0f, mCanvasClipBounds.centerX(), mCanvasClipBounds.centerY() + mProgressLineHeight / 2.0f, mProgressLinePaint);
复制代码

接着我们关注onTouchEvent方法,在该方法中,我们提供对外的事件监听回调。


 public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastTouchedPosition = event.getX();
                break;
            case MotionEvent.ACTION_UP:
                if (mScrollingListener != null) {
                    mScrollStarted = false;
                    mScrollingListener.onScrollEnd();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                float distance = event.getX() - mLastTouchedPosition;
                if (distance != 0) {
                    if (!mScrollStarted) {
                        mScrollStarted = true;
                        if (mScrollingListener != null) {
                            mScrollingListener.onScrollStart();
                        }
                    }
                    onScrollEvent(event, distance);
                }
                break;
        }
        return true;
    }
复制代码
需要注意这里的回调时机 * onscrollstart时机:down之后第一次move * onscroll时机:每次滚动 * onscrollEnd时机:up事件 在onScrollEvent方法中:设置滚动的距离,调用postInvalidate()重新绘制滚轮。

    private void onScrollEvent(MotionEvent event, float distance) {
        mTotalScrollDistance -= distance;
        postInvalidate();
        mLastTouchedPosition = event.getX();
        if (mScrollingListener != null) {
            mScrollingListener.onScroll(-distance, mTotalScrollDistance);
        }
    }
复制代码

该view的监听:


public interface ScrollingListener {

        void onScrollStart();

        void onScroll(float delta, float totalDistance);

        void onScrollEnd();
    }
复制代码

转载于:https://juejin.im/post/5a1fd06e6fb9a044ff313e4e

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值