一、簡介
最近產品經理總想試一些新鮮東西,於是需求中就添加了一些自定義控件。好久沒寫過自定義控件了,之前道長也寫過一些自定義控件,詳見:《屬性動畫:如何自定義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);
}
}
關於滾輪繪製,道長暫時說道這裏,由於時間緊迫,難免會有問題,希望小夥伴可以指出。如果需要參考一下的小夥伴,可以點擊下面的傳送門: