自定義控件:玩轉滾輪(柱狀圖、日期滾輪、刻度尺)

一、簡介

最近產品經理總想試一些新鮮東西,於是需求中就添加了一些自定義控件。好久沒寫過自定義控件了,之前道長也寫過一些自定義控件,詳見:《屬性動畫:如何自定義View》《自定義View:自定義CircleImageView實現及圖形渲染》《自定義View:用Canvas實現轉盤View》等。這次有幾個轉輪的變形,其實這幾個自定義控件的實現方式是相似的,其他不說先上圖,如下所示:
在這裏插入圖片描述

二、實現

由於這三個控件的實現是相似的,也就不一一詳說了,就說其中道長遇到的問題。

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章