自定义控件:玩转滚轮(柱状图、日期滚轮、刻度尺)

目录

  • 一、简介
  • 二、实现
    • 2.1 每个单元的滑动计算以及重绘

一、简介

最近产品经理总想试一些新鲜东西,于是需求中就添加了一些自定义控件。好久没写过自定义控件了,之前道长也写过一些自定义控件,详见:《属性动画:如何自定义View》、《自定义View:自定义CircleImageView实现及图形渲染》、《自定义View:用Canvas实现转盘View》等。这次有几个转轮的变形,其实这几个自定义控件的实现方式是相似的,其他不说先上图,如下所示:
自定义控件:玩转滚轮(柱状图、日期滚轮、刻度尺)_第1张图片

二、实现

由于这三个控件的实现是相似的,也就不一一详说了,就说其中道长遇到的问题。

2.1 每个单元的滑动计算以及重绘

  • 首先定义柱状图的初始位置
    这三个控件的初始位置都是屏幕中间,所以需要把初始位置定义为屏幕的二分之一,这里贴的FoodCalView的代码,如下所示:
        if (!setStart) {
            setStart = false;
            startOriganalX = measureWidth / 2;
        }

又因为这三个空间的左滑右滑不一致,所以对第一个单元的位置矫正也不同,如下所示:

        if (startOriganalX == 0) {
            startOriganalX = measureWidth / 2;
        }
        int startX = (int) (paddingLeft + startOriganalX - barWidth / 2);

注意:在滚轮滑动期间,界面会随着滑动而更新界面,如果处理不好就会一直在初始位置鬼畜。

  • 把每个柱状图的bar和间隔定义为一个单元,滑动时计算出当前单元、滑动方式等
if ((currX - lastX) < 0) {
	Log.e("yushan", "向左滑动");
	if (startOriganalX < measureWidth / 2) {
		startOriganalX = measureWidth / 2;
		isBoundary = true;
	}
	moveTo = "Left";
	centerPosition = (int) (startOriganalX - measureWidth / 2 + barInterval) / (barWidth + barInterval);
	nextDis = (startOriganalX - measureWidth / 2) % (barWidth + barInterval);
} else {
	if (startOriganalX > measureWidth / 2 + (barWidth + barInterval) * (innerData.size() - 1)) {
	startOriganalX = measureWidth / 2 + (barWidth + barInterval) * (innerData.size() - 1);
	isBoundary = true;
	}
	Log.e("yushan", "向右滑动");
	moveTo = "Right";
	centerPosition = (int) (startOriganalX - measureWidth / 2 + barWidth) / (barWidth + barInterval);

	nextDis = (startOriganalX - measureWidth / 2) % (barWidth + barInterval);
}

注意:如果计算不正确,用户体验非常差

  • 在手指抬起时,计算滑动速度和处理
    在手指抬起时,要计算手指抬起时移动的速度。当手指移动速度在100~1000之间,并且填充的数据大于屏幕宽度时,逐渐停止移动。
    当移动完毕时,如果柱状图bar不在屏幕中间,则根据nextDis让邻近的柱状图移动到屏幕中间。代码如下所示:
case MotionEvent.ACTION_UP:
	long endTime = System.currentTimeMillis();

	//计算猛滑动的速度,如果是大于某个值,并且数据的长度大于整个屏幕的长度,那么就允许有flIng后逐渐停止的效果
	float speed = tempLength / (endTime - startTime) * 1000;
	if (Math.abs(speed) > 100 && Math.abs(speed) < 1000 && !isFling && measureWidth < innerData.size() * (barWidth + barInterval)) {
		this.post(horizontalScrollRunnable = new HorizontalScrollRunnable(speed));
	} else if (nextDis > 0) {
		this.post(scroll2CenterRunnable = new Scroll2CenterRunnable(nextDis));
	}
	isMove = false;
	break;
  • WeightWheelView的绘制要求在手指移动时刻度尺和拳头的移动填充要实时更新,由于拳头是不规则形状,道长绘制的时候废了不少心思,效果也不错,绘制拳头的代码如下:
    private Bitmap drawFistImage() {
        Paint paint = new Paint();
        paint.setAntiAlias(true);

        Bitmap finalBmp = Bitmap.createBitmap(middleBitmap.getWidth(), middleBitmap.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(finalBmp);
        canvas.drawBitmap(backgroundBitmap, 0, 0, paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
        canvas.drawBitmap(middleBitmap, 0, 0, paint);

        return finalBmp;
    }
  • 在最后说一下,在手指移动时屏幕重绘,重绘的画布会越来越长,然后控件会越来越卡,由于任务时间紧急,这里道长只是简单处理了一下,如下所示:
                if (centerPosition % 15 == 0 && centerPosition != 0) {
                    refreshList.clear();
                    if (innerData.size() > 20) {
                        refreshList.addAll(innerData.subList(0, centerPosition + 20));
                    } else {
                        refreshList.addAll(innerData);
                    }
                }

关于滚轮绘制,道长暂时说道这里,由于时间紧迫,难免会有问题,希望小伙伴可以指出。如果需要参考一下的小伙伴,可以点击下面的传送门:

WheelDemo

你可能感兴趣的:(android-自定义控件)