From cdac521fdacf54e41c092df56b35819e536498aa Mon Sep 17 00:00:00 2001 From: cqf-hn Date: Fri, 12 Jun 2020 11:53:50 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E5=BC=80=E5=90=AF3D=E8=A7=86=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/contrarywind/view/WheelView.java | 213 +++++++++++++----- 1 file changed, 160 insertions(+), 53 deletions(-) diff --git a/wheelview/src/main/java/com/contrarywind/view/WheelView.java b/wheelview/src/main/java/com/contrarywind/view/WheelView.java index ea7327c7..059e5560 100644 --- a/wheelview/src/main/java/com/contrarywind/view/WheelView.java +++ b/wheelview/src/main/java/com/contrarywind/view/WheelView.java @@ -124,6 +124,9 @@ public enum DividerType { // 分隔线类型 private boolean isAlphaGradient = false; //透明度渐变 + //是否开启3D + private boolean isOpen3D = false; + public WheelView(Context context) { this(context, null); } @@ -215,8 +218,19 @@ private void reMeasure() {//重新测量 //半圆的周长 = item高度乘以item数目-1 int halfCircumference = (int) (itemHeight * (itemsVisible - 1)); - //整个圆的周长除以PI得到直径,这个直径用作控件的总高度 - measuredHeight = (int) ((halfCircumference * 2) / Math.PI); + if (isOpen3D) { + //整个圆的周长除以PI得到直径,这个直径用作控件的总高度 + measuredHeight = (int) ((halfCircumference * 2) / Math.PI); + if (paintCenterText.getTextScaleX() == paintOuterText.getTextScaleX()) { + paintCenterText.setTextScaleX(1.1F); + } + } else { +// itemsVisible = 5;//写死了不过可拓展 + if (paintCenterText.getTextScaleX() != paintOuterText.getTextScaleX()) { + paintCenterText.setTextScaleX(paintOuterText.getTextScaleX()); + } + measuredHeight = (int) (itemHeight * (itemsVisible - 2)); + } //求出半径 radius = (int) (halfCircumference / Math.PI); //控件宽度,这里支持weight @@ -443,39 +457,135 @@ protected void onDraw(Canvas canvas) { if (!TextUtils.isEmpty(label) && isCenterLabel) { //绘制文字,靠右并留出空隙 int drawRightContentStart = measuredWidth - getTextWidth(paintCenterText, label); - canvas.drawText(label, drawRightContentStart - CENTER_CONTENT_OFFSET, centerY, paintCenterText); + if (isOpen3D) { + canvas.drawText(label, drawRightContentStart - CENTER_CONTENT_OFFSET, centerY, paintCenterText); + } else { + canvas.drawText(label, drawRightContentStart, centerY, paintCenterText); + } } + if (isOpen3D) { + // 设置数组中每个元素的值 + int counter = 0; + while (counter < itemsVisible) { + Object showText; + int index = preCurrentIndex - (itemsVisible / 2 - counter);//索引值,即当前在控件中间的item看作数据源的中间,计算出相对源数据源的index值 + + //判断是否循环,如果是循环数据源也使用相对循环的position获取对应的item值,如果不是循环则超出数据源范围使用""空白字符串填充,在界面上形成空白无数据的item项 + if (isLoop) { + index = getLoopMappingIndex(index); + showText = adapter.getItem(index); + } else if (index < 0) { + showText = ""; + } else if (index > adapter.getItemsCount() - 1) { + showText = ""; + } else { + showText = adapter.getItem(index); + } - // 设置数组中每个元素的值 - int counter = 0; - while (counter < itemsVisible) { - Object showText; - int index = preCurrentIndex - (itemsVisible / 2 - counter);//索引值,即当前在控件中间的item看作数据源的中间,计算出相对源数据源的index值 + canvas.save(); + // 弧长 L = itemHeight * counter - itemHeightOffset + // 求弧度 α = L / r (弧长/半径) [0,π] + double radian = ((itemHeight * counter - itemHeightOffset)) / radius; + // 弧度转换成角度(把半圆以Y轴为轴心向右转90度,使其处于第一象限及第四象限 + // angle [-90°,90°] + float angle = (float) (90D - (radian / Math.PI) * 180D);//item第一项,从90度开始,逐渐递减到 -90度 - //判断是否循环,如果是循环数据源也使用相对循环的position获取对应的item值,如果不是循环则超出数据源范围使用""空白字符串填充,在界面上形成空白无数据的item项 - if (isLoop) { - index = getLoopMappingIndex(index); - showText = adapter.getItem(index); - } else if (index < 0) { - showText = ""; - } else if (index > adapter.getItemsCount() - 1) { - showText = ""; - } else { - showText = adapter.getItem(index); - } + // 计算取值可能有细微偏差,保证负90°到90°以外的不绘制 + if (angle > 90F || angle < -90F) { + canvas.restore(); + } else { + //获取内容文字 + String contentText; - canvas.save(); - // 弧长 L = itemHeight * counter - itemHeightOffset - // 求弧度 α = L / r (弧长/半径) [0,π] - double radian = ((itemHeight * counter - itemHeightOffset)) / radius; - // 弧度转换成角度(把半圆以Y轴为轴心向右转90度,使其处于第一象限及第四象限 - // angle [-90°,90°] - float angle = (float) (90D - (radian / Math.PI) * 180D);//item第一项,从90度开始,逐渐递减到 -90度 + //如果是label每项都显示的模式,并且item内容不为空、label 也不为空 + if (!isCenterLabel && !TextUtils.isEmpty(label) && !TextUtils.isEmpty(getContentText(showText))) { + contentText = getContentText(showText) + label; + } else { + contentText = getContentText(showText); + } + // 根据当前角度计算出偏差系数,用以在绘制时控制文字的 水平移动 透明度 倾斜程度. + float offsetCoefficient = (float) Math.pow(Math.abs(angle) / 90f, 2.2); + + reMeasureTextSize(contentText); + //计算开始绘制的位置 + 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); + if (translateY <= firstLineY && maxTextHeight + translateY >= firstLineY) { + // 条目经过第一条线 + canvas.save(); + canvas.clipRect(0, 0, measuredWidth, firstLineY - translateY); + canvas.scale(1.0F, (float) Math.sin(radian) * SCALE_CONTENT); + setOutPaintStyle(offsetCoefficient, angle); + 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) * 1.0F); + canvas.drawText(contentText, drawCenterContentStart, maxTextHeight - CENTER_CONTENT_OFFSET, 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 - CENTER_CONTENT_OFFSET, paintCenterText); + canvas.restore(); + canvas.save(); + canvas.clipRect(0, secondLineY - translateY, measuredWidth, (int) (itemHeight)); + canvas.scale(1.0F, (float) Math.sin(radian) * SCALE_CONTENT); + setOutPaintStyle(offsetCoefficient, angle); + canvas.drawText(contentText, drawOutContentStart, maxTextHeight, paintOuterText); + canvas.restore(); + } else if (translateY >= firstLineY && maxTextHeight + translateY <= secondLineY) { + // 中间条目 + // canvas.clipRect(0, 0, measuredWidth, maxTextHeight); + //让文字居中 + float Y = maxTextHeight - CENTER_CONTENT_OFFSET;//因为圆弧角换算的向下取值,导致角度稍微有点偏差,加上画笔的基线会偏上,因此需要偏移量修正一下 + canvas.drawText(contentText, drawCenterContentStart, Y, paintCenterText); + //设置选中项 + selectedItem = preCurrentIndex - (itemsVisible / 2 - counter); + } else { + // 其他条目 + canvas.save(); + canvas.clipRect(0, 0, measuredWidth, (int) (itemHeight)); + canvas.scale(1.0F, (float) Math.sin(radian) * SCALE_CONTENT); + setOutPaintStyle(offsetCoefficient, angle); + // 控制文字水平偏移距离 + canvas.drawText(contentText, drawOutContentStart + textXOffset * offsetCoefficient, maxTextHeight, paintOuterText); + canvas.restore(); + } + canvas.restore(); + paintCenterText.setTextSize(textSize); + } + counter++; + } + } else { + // TODO 2020/6/12 此处未做超出范围后不再绘制的优化... + int counter = 0; + while (counter < itemsVisible) { + Object showText; + int index = preCurrentIndex - (itemsVisible / 2 - counter);//索引值,即当前在控件中间的item看作数据源的中间,计算出相对源数据源的index值 + + //判断是否循环,如果是循环数据源也使用相对循环的position获取对应的item值,如果不是循环则超出数据源范围使用""空白字符串填充,在界面上形成空白无数据的item项 + if (isLoop) { + index = getLoopMappingIndex(index); + showText = adapter.getItem(index); + } else if (index < 0) { + showText = ""; + } else if (index > adapter.getItemsCount() - 1) { + showText = ""; + } else { + showText = adapter.getItem(index); + } - // 计算取值可能有细微偏差,保证负90°到90°以外的不绘制 - if (angle > 90F || angle < -90F) { - canvas.restore(); - } else { + canvas.save(); + //itemHeightOffset 默认为偏移原来位置的点的距离 + float translateY = itemHeight * (counter - 1) - itemHeightOffset; + translateY = (float) (translateY + ((itemHeight - maxTextHeight) / 2D)); + canvas.translate(0.0F, translateY);//右下正坐标系 translateY>0 向下移动坐标系 //获取内容文字 String contentText; @@ -485,64 +595,47 @@ protected void onDraw(Canvas canvas) { } else { contentText = getContentText(showText); } - // 根据当前角度计算出偏差系数,用以在绘制时控制文字的 水平移动 透明度 倾斜程度. - float offsetCoefficient = (float) Math.pow(Math.abs(angle) / 90f, 2.2); reMeasureTextSize(contentText); //计算开始绘制的位置 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); if (translateY <= firstLineY && maxTextHeight + translateY >= firstLineY) { // 条目经过第一条线 canvas.save(); canvas.clipRect(0, 0, measuredWidth, firstLineY - translateY); - canvas.scale(1.0F, (float) Math.sin(radian) * SCALE_CONTENT); - setOutPaintStyle(offsetCoefficient, angle); 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) * 1.0F); - canvas.drawText(contentText, drawCenterContentStart, maxTextHeight - CENTER_CONTENT_OFFSET, paintCenterText); + canvas.drawText(contentText, drawCenterContentStart, maxTextHeight, 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 - CENTER_CONTENT_OFFSET, paintCenterText); + canvas.drawText(contentText, drawCenterContentStart, maxTextHeight, paintCenterText); canvas.restore(); canvas.save(); canvas.clipRect(0, secondLineY - translateY, measuredWidth, (int) (itemHeight)); - canvas.scale(1.0F, (float) Math.sin(radian) * SCALE_CONTENT); - setOutPaintStyle(offsetCoefficient, angle); canvas.drawText(contentText, drawOutContentStart, maxTextHeight, paintOuterText); canvas.restore(); } else if (translateY >= firstLineY && maxTextHeight + translateY <= secondLineY) { // 中间条目 // canvas.clipRect(0, 0, measuredWidth, maxTextHeight); //让文字居中 - float Y = maxTextHeight - CENTER_CONTENT_OFFSET;//因为圆弧角换算的向下取值,导致角度稍微有点偏差,加上画笔的基线会偏上,因此需要偏移量修正一下 + float Y = maxTextHeight; canvas.drawText(contentText, drawCenterContentStart, Y, paintCenterText); + //设置选中项 selectedItem = preCurrentIndex - (itemsVisible / 2 - counter); } else { - // 其他条目 - canvas.save(); - canvas.clipRect(0, 0, measuredWidth, (int) (itemHeight)); - canvas.scale(1.0F, (float) Math.sin(radian) * SCALE_CONTENT); - setOutPaintStyle(offsetCoefficient, angle); - // 控制文字水平偏移距离 - canvas.drawText(contentText, drawOutContentStart + textXOffset * offsetCoefficient, maxTextHeight, paintOuterText); - canvas.restore(); + canvas.drawText(contentText, drawOutContentStart, maxTextHeight, paintOuterText); } canvas.restore(); paintCenterText.setTextSize(textSize); + counter++; } - counter++; } } @@ -813,6 +906,20 @@ public void setLineSpacingMultiplier(float lineSpacingMultiplier) { } } + public void setOpen3D(boolean isOpen3D) { + this.isOpen3D = isOpen3D; + if (!isOpen3D) { +// itemsVisible = 5;//此处未做拓展 + if (paintCenterText.getTextScaleX() != paintOuterText.getTextScaleX()) { + paintCenterText.setTextScaleX(paintOuterText.getTextScaleX()); + } + } else { + if (paintCenterText.getTextScaleX() == paintOuterText.getTextScaleX()) { + paintCenterText.setTextScaleX(1.1F); + } + } + } + public boolean isLoop() { return isLoop; } From 8ffaf4a30e1ef64deff1947db80e1f7a99db16d4 Mon Sep 17 00:00:00 2001 From: cqf-hn Date: Fri, 12 Jun 2020 11:55:46 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E9=BB=98=E8=AE=A4=E5=BC=80=E5=90=AF3D?= =?UTF-8?q?=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wheelview/src/main/java/com/contrarywind/view/WheelView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wheelview/src/main/java/com/contrarywind/view/WheelView.java b/wheelview/src/main/java/com/contrarywind/view/WheelView.java index 059e5560..d7860627 100644 --- a/wheelview/src/main/java/com/contrarywind/view/WheelView.java +++ b/wheelview/src/main/java/com/contrarywind/view/WheelView.java @@ -125,7 +125,7 @@ public enum DividerType { // 分隔线类型 private boolean isAlphaGradient = false; //透明度渐变 //是否开启3D - private boolean isOpen3D = false; + private boolean isOpen3D = true; public WheelView(Context context) { this(context, null);