/** 计算最大len的Text的宽高度 */ private void measureTextWidthHeight() { Rect rect = new Rect(); for (int i = 0; i < adapter.getItemsCount(); i++) { String s1 = getContentText(adapter.getItem(i)); paintCenterText.getTextBounds(s1, 0, s1.length(), rect); int textWidth = rect.width(); if (textWidth > maxTextWidth) { maxTextWidth = textWidth; } paintCenterText.getTextBounds("\u661F\u671F", 0, 2, rect); // 星期 int textHeight = rect.height(); if (textHeight > maxTextHeight) { maxTextHeight = textHeight; } } itemHeight = lineSpacingMultiplier * maxTextHeight; }
@Override protected void onDraw(Canvas canvas) { if (adapter == null) { return; } // 可见的item数组 Object visibles[] = new Object[itemsVisible]; // 滚动的Y值高度除去每行Item的高度,得到滚动了多少个item,即change数 change = (int) (totalScrollY / itemHeight); try { // 滚动中实际的预选中的item(即经过了中间位置的item) = 滑动前的位置 + 滑动相对位置 preCurrentIndex = initPosition + change % adapter.getItemsCount(); } catch (ArithmeticException e) { System.out.println("出错了!adapter.getItemsCount() == 0,联动数据不匹配"); } if (!isLoop) { // 不循环的情况 if (preCurrentIndex < 0) { preCurrentIndex = 0; } if (preCurrentIndex > adapter.getItemsCount() - 1) { preCurrentIndex = adapter.getItemsCount() - 1; } } else { // 循环 if (preCurrentIndex < 0) { // 举个例子:如果总数是5,preCurrentIndex = -1,那么preCurrentIndex按循环来说,其实是0的上面,也就是4的位置 preCurrentIndex = adapter.getItemsCount() + preCurrentIndex; } if (preCurrentIndex > adapter.getItemsCount() - 1) { // 同理上面,自己脑补一下 preCurrentIndex = preCurrentIndex - adapter.getItemsCount(); } } // 跟滚动流畅度有关,总滑动距离与每个item高度取余,即并不是一格格的滚动,每个item不一定滚到对应Rect里的,这个item对应格子的偏移值 int itemHeightOffset = (int) (totalScrollY % itemHeight); // 设置数组中每个元素的值 int counter = 0; while (counter < itemsVisible) { int index = preCurrentIndex - (itemsVisible / 2 - counter); // 索引值,即当前在控件中间的item看作数据源的中间,计算出相对源数据源的index值 // 判断是否循环,如果是循环数据源也使用相对循环的position获取对应的item值,如果不是循环则超出数据源范围使用""空白字符串填充,在界面上形成空白无数据的item项 if (isLoop) { index = getLoopMappingIndex(index); visibles[counter] = adapter.getItem(index); } else if (index < 0) { visibles[counter] = ""; } else if (index > adapter.getItemsCount() - 1) { visibles[counter] = ""; } else { visibles[counter] = adapter.getItem(index); } counter++; } // 中间两条横线 canvas.drawLine(0.0F, firstLineY, measuredWidth, firstLineY, paintIndicator); canvas.drawLine(0.0F, secondLineY, measuredWidth, secondLineY, paintIndicator); // 单位的Label if (label != null) { int drawRightContentStart = measuredWidth - getTextWidth(paintCenterText, label); // 靠右并留出空隙 canvas.drawText(label, drawRightContentStart - CENTERCONTENTOFFSET, centerY, paintCenterText); } counter = 0; while (counter < itemsVisible) { canvas.save(); // L(弧长)=α(弧度)* r(半径) (弧度制) // 求弧度--> (L * π ) / (π * r) (弧长X派/半圆周长) float itemHeight = maxTextHeight * lineSpacingMultiplier; double radian = ((itemHeight * counter - itemHeightOffset) * Math.PI) / halfCircumference; // 弧度转换成角度(把半圆以Y轴为轴心向右转90度,使其处于第一象限及第四象限 float angle = (float) (90D - (radian / Math.PI) * 180D); // 九十度以上的不绘制 if (angle >= 90F || angle <= -90F) { canvas.restore(); } else { String contentText = getContentText(visibles[counter]); // 计算开始绘制的位置 measuredCenterContentStart(contentText); measuredOutContentStart(contentText); float translateY = (float) (radius - Math.cos(radian) * radius - (Math.sin(radian) * maxTextHeight) / 2D); // 根据Math.sin(radian)来更改canvas坐标系原点,然后缩放画布,使得文字高度进行缩放,形成弧形3d视觉差 canvas.translate(0.0F, translateY); canvas.scale(1.0F, (float) Math.sin(radian)); if (translateY <= firstLineY && maxTextHeight + translateY >= firstLineY) { // 条目经过第一条线 canvas.save(); canvas.clipRect(0, 0, measuredWidth, firstLineY - translateY); canvas.scale(1.0F, (float) Math.sin(radian) * SCALECONTENT); canvas.drawText(contentText, drawOutContentStart, maxTextHeight, paintOuterText); canvas.restore(); canvas.save(); canvas.clipRect(0, firstLineY - translateY, measuredWidth, (int) (itemHeight)); canvas.scale(1.0F, (float) Math.sin(radian) * 1F); canvas.drawText( contentText, drawCenterContentStart, maxTextHeight - CENTERCONTENTOFFSET, paintCenterText); canvas.restore(); } else if (translateY <= secondLineY && maxTextHeight + translateY >= secondLineY) { // 条目经过第二条线 canvas.save(); canvas.clipRect(0, 0, measuredWidth, secondLineY - translateY); canvas.scale(1.0F, (float) Math.sin(radian) * 1.0F); canvas.drawText( contentText, drawCenterContentStart, maxTextHeight - CENTERCONTENTOFFSET, paintCenterText); canvas.restore(); canvas.save(); canvas.clipRect(0, secondLineY - translateY, measuredWidth, (int) (itemHeight)); canvas.scale(1.0F, (float) Math.sin(radian) * SCALECONTENT); canvas.drawText(contentText, drawOutContentStart, maxTextHeight, paintOuterText); canvas.restore(); } else if (translateY >= firstLineY && maxTextHeight + translateY <= secondLineY) { // 中间条目 canvas.clipRect(0, 0, measuredWidth, (int) (itemHeight)); canvas.drawText( contentText, drawCenterContentStart, maxTextHeight - CENTERCONTENTOFFSET, paintCenterText); int preSelectedItem = adapter.indexOf(visibles[counter]); if (preSelectedItem != -1) { selectedItem = preSelectedItem; } } else { // 其他条目 canvas.save(); canvas.clipRect(0, 0, measuredWidth, (int) (itemHeight)); canvas.scale(1.0F, (float) Math.sin(radian) * SCALECONTENT); canvas.drawText(contentText, drawOutContentStart, maxTextHeight, paintOuterText); canvas.restore(); } canvas.restore(); } counter++; } }