Skip to content

Commit bc101db

Browse files
authored
Merge pull request #2 from cqf-hn/master
添加是否开启3D视图 Bigkoo#907
2 parents 166cf4a + 8ffaf4a commit bc101db

File tree

1 file changed

+160
-53
lines changed

1 file changed

+160
-53
lines changed

wheelview/src/main/java/com/contrarywind/view/WheelView.java

Lines changed: 160 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ public enum DividerType { // 分隔线类型
124124

125125
private boolean isAlphaGradient = false; //透明度渐变
126126

127+
//是否开启3D
128+
private boolean isOpen3D = true;
129+
127130
public WheelView(Context context) {
128131
this(context, null);
129132
}
@@ -215,8 +218,19 @@ private void reMeasure() {//重新测量
215218

216219
//半圆的周长 = item高度乘以item数目-1
217220
int halfCircumference = (int) (itemHeight * (itemsVisible - 1));
218-
//整个圆的周长除以PI得到直径,这个直径用作控件的总高度
219-
measuredHeight = (int) ((halfCircumference * 2) / Math.PI);
221+
if (isOpen3D) {
222+
//整个圆的周长除以PI得到直径,这个直径用作控件的总高度
223+
measuredHeight = (int) ((halfCircumference * 2) / Math.PI);
224+
if (paintCenterText.getTextScaleX() == paintOuterText.getTextScaleX()) {
225+
paintCenterText.setTextScaleX(1.1F);
226+
}
227+
} else {
228+
// itemsVisible = 5;//写死了不过可拓展
229+
if (paintCenterText.getTextScaleX() != paintOuterText.getTextScaleX()) {
230+
paintCenterText.setTextScaleX(paintOuterText.getTextScaleX());
231+
}
232+
measuredHeight = (int) (itemHeight * (itemsVisible - 2));
233+
}
220234
//求出半径
221235
radius = (int) (halfCircumference / Math.PI);
222236
//控件宽度,这里支持weight
@@ -443,39 +457,135 @@ protected void onDraw(Canvas canvas) {
443457
if (!TextUtils.isEmpty(label) && isCenterLabel) {
444458
//绘制文字,靠右并留出空隙
445459
int drawRightContentStart = measuredWidth - getTextWidth(paintCenterText, label);
446-
canvas.drawText(label, drawRightContentStart - CENTER_CONTENT_OFFSET, centerY, paintCenterText);
460+
if (isOpen3D) {
461+
canvas.drawText(label, drawRightContentStart - CENTER_CONTENT_OFFSET, centerY, paintCenterText);
462+
} else {
463+
canvas.drawText(label, drawRightContentStart, centerY, paintCenterText);
464+
}
447465
}
466+
if (isOpen3D) {
467+
// 设置数组中每个元素的值
468+
int counter = 0;
469+
while (counter < itemsVisible) {
470+
Object showText;
471+
int index = preCurrentIndex - (itemsVisible / 2 - counter);//索引值,即当前在控件中间的item看作数据源的中间,计算出相对源数据源的index值
472+
473+
//判断是否循环,如果是循环数据源也使用相对循环的position获取对应的item值,如果不是循环则超出数据源范围使用""空白字符串填充,在界面上形成空白无数据的item项
474+
if (isLoop) {
475+
index = getLoopMappingIndex(index);
476+
showText = adapter.getItem(index);
477+
} else if (index < 0) {
478+
showText = "";
479+
} else if (index > adapter.getItemsCount() - 1) {
480+
showText = "";
481+
} else {
482+
showText = adapter.getItem(index);
483+
}
448484

449-
// 设置数组中每个元素的值
450-
int counter = 0;
451-
while (counter < itemsVisible) {
452-
Object showText;
453-
int index = preCurrentIndex - (itemsVisible / 2 - counter);//索引值,即当前在控件中间的item看作数据源的中间,计算出相对源数据源的index值
485+
canvas.save();
486+
// 弧长 L = itemHeight * counter - itemHeightOffset
487+
// 求弧度 α = L / r (弧长/半径) [0,π]
488+
double radian = ((itemHeight * counter - itemHeightOffset)) / radius;
489+
// 弧度转换成角度(把半圆以Y轴为轴心向右转90度,使其处于第一象限及第四象限
490+
// angle [-90°,90°]
491+
float angle = (float) (90D - (radian / Math.PI) * 180D);//item第一项,从90度开始,逐渐递减到 -90度
454492

455-
//判断是否循环,如果是循环数据源也使用相对循环的position获取对应的item值,如果不是循环则超出数据源范围使用""空白字符串填充,在界面上形成空白无数据的item项
456-
if (isLoop) {
457-
index = getLoopMappingIndex(index);
458-
showText = adapter.getItem(index);
459-
} else if (index < 0) {
460-
showText = "";
461-
} else if (index > adapter.getItemsCount() - 1) {
462-
showText = "";
463-
} else {
464-
showText = adapter.getItem(index);
465-
}
493+
// 计算取值可能有细微偏差,保证负90°到90°以外的不绘制
494+
if (angle > 90F || angle < -90F) {
495+
canvas.restore();
496+
} else {
497+
//获取内容文字
498+
String contentText;
466499

467-
canvas.save();
468-
// 弧长 L = itemHeight * counter - itemHeightOffset
469-
// 求弧度 α = L / r (弧长/半径) [0,π]
470-
double radian = ((itemHeight * counter - itemHeightOffset)) / radius;
471-
// 弧度转换成角度(把半圆以Y轴为轴心向右转90度,使其处于第一象限及第四象限
472-
// angle [-90°,90°]
473-
float angle = (float) (90D - (radian / Math.PI) * 180D);//item第一项,从90度开始,逐渐递减到 -90度
500+
//如果是label每项都显示的模式,并且item内容不为空、label 也不为空
501+
if (!isCenterLabel && !TextUtils.isEmpty(label) && !TextUtils.isEmpty(getContentText(showText))) {
502+
contentText = getContentText(showText) + label;
503+
} else {
504+
contentText = getContentText(showText);
505+
}
506+
// 根据当前角度计算出偏差系数,用以在绘制时控制文字的 水平移动 透明度 倾斜程度.
507+
float offsetCoefficient = (float) Math.pow(Math.abs(angle) / 90f, 2.2);
508+
509+
reMeasureTextSize(contentText);
510+
//计算开始绘制的位置
511+
measuredCenterContentStart(contentText);
512+
measuredOutContentStart(contentText);
513+
float translateY = (float) (radius - Math.cos(radian) * radius - (Math.sin(radian) * maxTextHeight) / 2D);
514+
//根据Math.sin(radian)来更改canvas坐标系原点,然后缩放画布,使得文字高度进行缩放,形成弧形3d视觉差
515+
canvas.translate(0.0F, translateY);
516+
if (translateY <= firstLineY && maxTextHeight + translateY >= firstLineY) {
517+
// 条目经过第一条线
518+
canvas.save();
519+
canvas.clipRect(0, 0, measuredWidth, firstLineY - translateY);
520+
canvas.scale(1.0F, (float) Math.sin(radian) * SCALE_CONTENT);
521+
setOutPaintStyle(offsetCoefficient, angle);
522+
canvas.drawText(contentText, drawOutContentStart, maxTextHeight, paintOuterText);
523+
canvas.restore();
524+
canvas.save();
525+
canvas.clipRect(0, firstLineY - translateY, measuredWidth, (int) (itemHeight));
526+
canvas.scale(1.0F, (float) Math.sin(radian) * 1.0F);
527+
canvas.drawText(contentText, drawCenterContentStart, maxTextHeight - CENTER_CONTENT_OFFSET, paintCenterText);
528+
canvas.restore();
529+
} else if (translateY <= secondLineY && maxTextHeight + translateY >= secondLineY) {
530+
// 条目经过第二条线
531+
canvas.save();
532+
canvas.clipRect(0, 0, measuredWidth, secondLineY - translateY);
533+
canvas.scale(1.0F, (float) Math.sin(radian) * 1.0F);
534+
canvas.drawText(contentText, drawCenterContentStart, maxTextHeight - CENTER_CONTENT_OFFSET, paintCenterText);
535+
canvas.restore();
536+
canvas.save();
537+
canvas.clipRect(0, secondLineY - translateY, measuredWidth, (int) (itemHeight));
538+
canvas.scale(1.0F, (float) Math.sin(radian) * SCALE_CONTENT);
539+
setOutPaintStyle(offsetCoefficient, angle);
540+
canvas.drawText(contentText, drawOutContentStart, maxTextHeight, paintOuterText);
541+
canvas.restore();
542+
} else if (translateY >= firstLineY && maxTextHeight + translateY <= secondLineY) {
543+
// 中间条目
544+
// canvas.clipRect(0, 0, measuredWidth, maxTextHeight);
545+
//让文字居中
546+
float Y = maxTextHeight - CENTER_CONTENT_OFFSET;//因为圆弧角换算的向下取值,导致角度稍微有点偏差,加上画笔的基线会偏上,因此需要偏移量修正一下
547+
canvas.drawText(contentText, drawCenterContentStart, Y, paintCenterText);
548+
//设置选中项
549+
selectedItem = preCurrentIndex - (itemsVisible / 2 - counter);
550+
} else {
551+
// 其他条目
552+
canvas.save();
553+
canvas.clipRect(0, 0, measuredWidth, (int) (itemHeight));
554+
canvas.scale(1.0F, (float) Math.sin(radian) * SCALE_CONTENT);
555+
setOutPaintStyle(offsetCoefficient, angle);
556+
// 控制文字水平偏移距离
557+
canvas.drawText(contentText, drawOutContentStart + textXOffset * offsetCoefficient, maxTextHeight, paintOuterText);
558+
canvas.restore();
559+
}
560+
canvas.restore();
561+
paintCenterText.setTextSize(textSize);
562+
}
563+
counter++;
564+
}
565+
} else {
566+
// TODO 2020/6/12 此处未做超出范围后不再绘制的优化...
567+
int counter = 0;
568+
while (counter < itemsVisible) {
569+
Object showText;
570+
int index = preCurrentIndex - (itemsVisible / 2 - counter);//索引值,即当前在控件中间的item看作数据源的中间,计算出相对源数据源的index值
571+
572+
//判断是否循环,如果是循环数据源也使用相对循环的position获取对应的item值,如果不是循环则超出数据源范围使用""空白字符串填充,在界面上形成空白无数据的item项
573+
if (isLoop) {
574+
index = getLoopMappingIndex(index);
575+
showText = adapter.getItem(index);
576+
} else if (index < 0) {
577+
showText = "";
578+
} else if (index > adapter.getItemsCount() - 1) {
579+
showText = "";
580+
} else {
581+
showText = adapter.getItem(index);
582+
}
474583

475-
// 计算取值可能有细微偏差,保证负90°到90°以外的不绘制
476-
if (angle > 90F || angle < -90F) {
477-
canvas.restore();
478-
} else {
584+
canvas.save();
585+
//itemHeightOffset 默认为偏移原来位置的点的距离
586+
float translateY = itemHeight * (counter - 1) - itemHeightOffset;
587+
translateY = (float) (translateY + ((itemHeight - maxTextHeight) / 2D));
588+
canvas.translate(0.0F, translateY);//右下正坐标系 translateY>0 向下移动坐标系
479589
//获取内容文字
480590
String contentText;
481591

@@ -485,64 +595,47 @@ protected void onDraw(Canvas canvas) {
485595
} else {
486596
contentText = getContentText(showText);
487597
}
488-
// 根据当前角度计算出偏差系数,用以在绘制时控制文字的 水平移动 透明度 倾斜程度.
489-
float offsetCoefficient = (float) Math.pow(Math.abs(angle) / 90f, 2.2);
490598

491599
reMeasureTextSize(contentText);
492600
//计算开始绘制的位置
493601
measuredCenterContentStart(contentText);
494602
measuredOutContentStart(contentText);
495-
float translateY = (float) (radius - Math.cos(radian) * radius - (Math.sin(radian) * maxTextHeight) / 2D);
496-
//根据Math.sin(radian)来更改canvas坐标系原点,然后缩放画布,使得文字高度进行缩放,形成弧形3d视觉差
497-
canvas.translate(0.0F, translateY);
498603
if (translateY <= firstLineY && maxTextHeight + translateY >= firstLineY) {
499604
// 条目经过第一条线
500605
canvas.save();
501606
canvas.clipRect(0, 0, measuredWidth, firstLineY - translateY);
502-
canvas.scale(1.0F, (float) Math.sin(radian) * SCALE_CONTENT);
503-
setOutPaintStyle(offsetCoefficient, angle);
504607
canvas.drawText(contentText, drawOutContentStart, maxTextHeight, paintOuterText);
505608
canvas.restore();
506609
canvas.save();
507610
canvas.clipRect(0, firstLineY - translateY, measuredWidth, (int) (itemHeight));
508-
canvas.scale(1.0F, (float) Math.sin(radian) * 1.0F);
509-
canvas.drawText(contentText, drawCenterContentStart, maxTextHeight - CENTER_CONTENT_OFFSET, paintCenterText);
611+
canvas.drawText(contentText, drawCenterContentStart, maxTextHeight, paintCenterText);
510612
canvas.restore();
511613
} else if (translateY <= secondLineY && maxTextHeight + translateY >= secondLineY) {
512614
// 条目经过第二条线
513615
canvas.save();
514616
canvas.clipRect(0, 0, measuredWidth, secondLineY - translateY);
515-
canvas.scale(1.0F, (float) Math.sin(radian) * 1.0F);
516-
canvas.drawText(contentText, drawCenterContentStart, maxTextHeight - CENTER_CONTENT_OFFSET, paintCenterText);
617+
canvas.drawText(contentText, drawCenterContentStart, maxTextHeight, paintCenterText);
517618
canvas.restore();
518619
canvas.save();
519620
canvas.clipRect(0, secondLineY - translateY, measuredWidth, (int) (itemHeight));
520-
canvas.scale(1.0F, (float) Math.sin(radian) * SCALE_CONTENT);
521-
setOutPaintStyle(offsetCoefficient, angle);
522621
canvas.drawText(contentText, drawOutContentStart, maxTextHeight, paintOuterText);
523622
canvas.restore();
524623
} else if (translateY >= firstLineY && maxTextHeight + translateY <= secondLineY) {
525624
// 中间条目
526625
// canvas.clipRect(0, 0, measuredWidth, maxTextHeight);
527626
//让文字居中
528-
float Y = maxTextHeight - CENTER_CONTENT_OFFSET;//因为圆弧角换算的向下取值,导致角度稍微有点偏差,加上画笔的基线会偏上,因此需要偏移量修正一下
627+
float Y = maxTextHeight;
529628
canvas.drawText(contentText, drawCenterContentStart, Y, paintCenterText);
629+
530630
//设置选中项
531631
selectedItem = preCurrentIndex - (itemsVisible / 2 - counter);
532632
} else {
533-
// 其他条目
534-
canvas.save();
535-
canvas.clipRect(0, 0, measuredWidth, (int) (itemHeight));
536-
canvas.scale(1.0F, (float) Math.sin(radian) * SCALE_CONTENT);
537-
setOutPaintStyle(offsetCoefficient, angle);
538-
// 控制文字水平偏移距离
539-
canvas.drawText(contentText, drawOutContentStart + textXOffset * offsetCoefficient, maxTextHeight, paintOuterText);
540-
canvas.restore();
633+
canvas.drawText(contentText, drawOutContentStart, maxTextHeight, paintOuterText);
541634
}
542635
canvas.restore();
543636
paintCenterText.setTextSize(textSize);
637+
counter++;
544638
}
545-
counter++;
546639
}
547640
}
548641

@@ -813,6 +906,20 @@ public void setLineSpacingMultiplier(float lineSpacingMultiplier) {
813906
}
814907
}
815908

909+
public void setOpen3D(boolean isOpen3D) {
910+
this.isOpen3D = isOpen3D;
911+
if (!isOpen3D) {
912+
// itemsVisible = 5;//此处未做拓展
913+
if (paintCenterText.getTextScaleX() != paintOuterText.getTextScaleX()) {
914+
paintCenterText.setTextScaleX(paintOuterText.getTextScaleX());
915+
}
916+
} else {
917+
if (paintCenterText.getTextScaleX() == paintOuterText.getTextScaleX()) {
918+
paintCenterText.setTextScaleX(1.1F);
919+
}
920+
}
921+
}
922+
816923
public boolean isLoop() {
817924
return isLoop;
818925
}

0 commit comments

Comments
 (0)