2525import java .util .concurrent .TimeUnit ;
2626
2727/**
28- * 3d滚轮控件
28+ * 3d滚轮控件,
2929 */
3030public class WheelView extends View {
3131
@@ -168,13 +168,19 @@ private void remeasure() {
168168
169169 measureTextWidthHeight ();
170170
171+ //最大Text的高度乘间距倍数得到 可见文字实际的总高度,半圆的周长
171172 halfCircumference = (int ) (maxTextHeight * lineSpacingMultiplier * (itemsVisible - 1 )) ;
173+ //整个圆的周长除以PI得到直径,这个直径用作控件的总高度
172174 measuredHeight = (int ) ((halfCircumference * 2 ) / Math .PI );
175+ //求出半径
173176 radius = (int ) (halfCircumference / Math .PI );
177+ //控件宽度,这里支持weight
174178 measuredWidth = MeasureSpec .getSize (widthMeasureSpec );
179+ //计算两条横线和控件中间点的Y位置
175180 firstLineY = (int ) ((measuredHeight - lineSpacingMultiplier * maxTextHeight ) / 2.0F );
176181 secondLineY = (int ) ((measuredHeight + lineSpacingMultiplier * maxTextHeight ) / 2.0F );
177182 centerY = (int ) ((measuredHeight + maxTextHeight ) / 2.0F - CENTERCONTENTOFFSET );
183+ //初始化显示的item的position,根据是否loop
178184 if (initPosition == -1 ) {
179185 if (isLoop ) {
180186 initPosition = (adapter .getItemsCount () + 1 ) / 2 ;
@@ -186,6 +192,9 @@ private void remeasure() {
186192 preCurrentIndex = initPosition ;
187193 }
188194
195+ /**
196+ * 计算最大len的Text的宽高度
197+ */
189198 private void measureTextWidthHeight () {
190199 Rect rect = new Rect ();
191200 for (int i = 0 ; i < adapter .getItemsCount (); i ++) {
@@ -280,78 +289,92 @@ protected void onDraw(Canvas canvas) {
280289 return ;
281290 }
282291
283- Object as [] = new Object [itemsVisible ];
292+ //可见的item数组
293+ Object visibles [] = new Object [itemsVisible ];
294+ //更加滚动的Y值高度除去每行Item的高度,得到滚动了多少个item,即change数
284295 change = (int ) (totalScrollY / (lineSpacingMultiplier * maxTextHeight ));
285296 try {
297+ //滚动中实际的预选中的item(即经过了中间位置的item) = 滑动前的位置 + 滑动相对位置
286298 preCurrentIndex = initPosition + change % adapter .getItemsCount ();
287299 }catch (ArithmeticException e ){
288300 System .out .println ("出错了!adapter.getItemsCount() == 0,联动数据不匹配" );
289301 }
290- if (!isLoop ) {
302+ if (!isLoop ) {//不循环的情况
291303 if (preCurrentIndex < 0 ) {
292304 preCurrentIndex = 0 ;
293305 }
294306 if (preCurrentIndex > adapter .getItemsCount () - 1 ) {
295307 preCurrentIndex = adapter .getItemsCount () - 1 ;
296308 }
297- } else {
298- if (preCurrentIndex < 0 ) {
309+ } else {//循环
310+ if (preCurrentIndex < 0 ) {//举个例子:如果总数是5,preCurrentIndex = -1,那么preCurrentIndex按循环来说,其实是0的上面,也就是4的位置
299311 preCurrentIndex = adapter .getItemsCount () + preCurrentIndex ;
300312 }
301- if (preCurrentIndex > adapter .getItemsCount () - 1 ) {
313+ if (preCurrentIndex > adapter .getItemsCount () - 1 ) {//同理上面,自己脑补一下
302314 preCurrentIndex = preCurrentIndex - adapter .getItemsCount ();
303315 }
304316 }
305317
306- //change的另外一个变量,跟滚动流畅度有关
307- int j2 = (int ) (totalScrollY % (lineSpacingMultiplier * maxTextHeight ));
308- // 设置as数组中每个元素的值
309- int k1 = 0 ;
310- while (k1 < itemsVisible ) {
311- int l1 = preCurrentIndex - (itemsVisible / 2 - k1 );
318+ //跟滚动流畅度有关,总滑动距离与每个item高度取余,即并不是一格格的滚动,每个item不一定滚到对应Rect里的,这个item对应格子的偏移值
319+ int itemHeightOffset = (int ) (totalScrollY % (lineSpacingMultiplier * maxTextHeight ));
320+ // 设置数组中每个元素的值
321+ int counter = 0 ;
322+ while (counter < itemsVisible ) {
323+ int index = preCurrentIndex - (itemsVisible / 2 - counter );//索引值,即当前在控件中间的item看作数据源的中间,计算出相对源数据源的index值
324+ //判断是否循环,如果是循环数据源也使用相对循环的position获取对应的item值,如果不是循环则超出数据源范围使用""空白字符串填充,在界面上形成空白无数据的item项
312325 if (isLoop ) {
313- if (l1 < 0 ) {
314- l1 = l1 + adapter .getItemsCount ();
326+ if (index < 0 ) {
327+ index = index + adapter .getItemsCount ();
328+ if (index < 0 ){
329+ index = 0 ;
330+ }
315331 }
316- if (l1 > adapter .getItemsCount () - 1 ) {
317- l1 = l1 - adapter .getItemsCount ();
332+ if (index > adapter .getItemsCount () - 1 ) {
333+ index = index - adapter .getItemsCount ();
334+ if (index > adapter .getItemsCount () - 1 ){
335+ index = adapter .getItemsCount () - 1 ;
336+ }
318337 }
319- as [ k1 ] = adapter .getItem (l1 );
320- } else if (l1 < 0 ) {
321- as [ k1 ] = "" ;
322- } else if (l1 > adapter .getItemsCount () - 1 ) {
323- as [ k1 ] = "" ;
338+ visibles [ counter ] = adapter .getItem (index );
339+ } else if (index < 0 ) {
340+ visibles [ counter ] = "" ;
341+ } else if (index > adapter .getItemsCount () - 1 ) {
342+ visibles [ counter ] = "" ;
324343 } else {
325- as [ k1 ] = adapter .getItem (l1 );
344+ visibles [ counter ] = adapter .getItem (index );
326345 }
327- k1 ++;
346+ counter ++;
347+
328348 }
349+
350+ //中间两条横线
329351 canvas .drawLine (0.0F , firstLineY , measuredWidth , firstLineY , paintIndicator );
330352 canvas .drawLine (0.0F , secondLineY , measuredWidth , secondLineY , paintIndicator );
353+ //单位的Label
331354 if (label != null ) {
332355 int drawRightContentStart = measuredWidth - getTextWidth (paintCenterText ,label );
333356 //靠右并留出空隙
334357 canvas .drawText (label , drawRightContentStart - CENTERCONTENTOFFSET , centerY , paintCenterText );
335358 }
336- int j1 = 0 ;
337- while (j1 < itemsVisible ) {
359+ counter = 0 ;
360+ while (counter < itemsVisible ) {
338361 canvas .save ();
339362 // L(弧长)=α(弧度)* r(半径) (弧度制)
340363 // 求弧度--> (L * π ) / (π * r) (弧长X派/半圆周长)
341364 float itemHeight = maxTextHeight * lineSpacingMultiplier ;
342- double radian = ((itemHeight * j1 - j2 ) * Math .PI ) / halfCircumference ;
365+ double radian = ((itemHeight * counter - itemHeightOffset ) * Math .PI ) / halfCircumference ;
343366 // 弧度转换成角度(把半圆以Y轴为轴心向右转90度,使其处于第一象限及第四象限
344367 float angle = (float ) (90D - (radian / Math .PI ) * 180D );
345368 if (angle >= 90F || angle <= -90F ) {
346369 canvas .restore ();
347370 } else {
348- String contentText = getContentText (as [ j1 ]);
371+ String contentText = getContentText (visibles [ counter ]);
349372
350373 //计算开始绘制的位置
351374 measuredCenterContentStart (contentText );
352375 measuredOutContentStart (contentText );
353376 int translateY = (int ) (radius - Math .cos (radian ) * radius - (Math .sin (radian ) * maxTextHeight ) / 2D );
354- //根据Math.sin(radian)来更改文字高度拉长和缩放 ,形成弧形3d视觉差
377+ //根据Math.sin(radian)来更改canvas坐标系原点,然后缩放画布,使得文字高度进行缩放 ,形成弧形3d视觉差
355378 canvas .translate (0.0F , translateY );
356379 canvas .scale (1.0F , (float ) Math .sin (radian ));
357380 if (translateY <= firstLineY && maxTextHeight + translateY >= firstLineY ) {
@@ -382,10 +405,10 @@ protected void onDraw(Canvas canvas) {
382405 // 中间条目
383406 canvas .clipRect (0 , 0 , measuredWidth , (int ) (itemHeight ));
384407 canvas .drawText (contentText , drawCenterContentStart , maxTextHeight - CENTERCONTENTOFFSET , paintCenterText );
385- //根据滚动多少个item和初始显示的item位置,计算出中间的item是第几个
386- int middleCount = ( int ) Math . round (( change + initPosition ) % ( adapter . getItemsCount () * 1.0 ));
387- selectedItem = middleCount >= 0 ? middleCount : adapter . getItemsCount () + middleCount ;
388- selectedItem = adapter . indexOf ( as [ j1 ]);
408+ int preSelectedItem = adapter . indexOf ( visibles [ counter ]);
409+ if ( preSelectedItem != - 1 ){
410+ selectedItem = preSelectedItem ;
411+ }
389412 } else {
390413 // 其他条目
391414 canvas .save ();
@@ -396,7 +419,7 @@ protected void onDraw(Canvas canvas) {
396419 }
397420 canvas .restore ();
398421 }
399- j1 ++;
422+ counter ++;
400423 }
401424 }
402425
0 commit comments