Android 自定义View 点击可旋转的饼状图
2016-09-21 本文已影响917人
逸小苼
贴吧有人求助下图实现思路,看着描述效果不错,决定实现
效果图如下
这里写图片描述实现思路分析
0、中心设置在center,初始偏移为正下方,即90°位置。
1、根据传入的数组数据,按百分比绘制对应degree 的圆弧 drawArc,。
2、监听 onTouchEvent ,ACTION_DOWN 获取焦点位置的 RGB 色值,在ACTION_UP 处理逻辑判断是哪一个色块。
3、根据点击的色块,所在的目标偏移位置,即圆弧的中心线,与上次偏移角度差,计算出当前旋转所需degree。
4、执行绘制,旋转到目标偏移位置。
5、选中色块的下移。修改drawArc 区域的四面范围,增加色块的起始角度,减少色块的degree,达到突出显示的效果。
6、绘制中间文本内容,根据width - 2*r,计算出适合大小的textSize。
7、微调,添加回调接口和函数,支持多条数据
这里写图片描述
`
关键代码及算法
绘制圆弧偏移和偏移色
private void drawBackg(Canvas canvas) {
if (this.datas == null || this.dataSum == 0F) {
paintArc.setColor(Color.parseColor(defaultColor));
canvas.drawArc(rectF, 0F, 360F, false, paintArc);
return;
}
for (int i = 0; i < datas.length; i++) {
canvas.save();
paintArc.setColor(Color.parseColor(arcColors[i]));
startAngleTemp = 90F - 180F * datas[0] / dataSum;
if (i != 0) {
for (int j = 0; j < i; j++) {
startAngleTemp += 360F * datas[j] / dataSum;
}
}
if (this.ACTION_ == this.ACTION_ROTATION) {
if (curColorIndex == i && degree == degreeT && datas.length > 1) {
if (mOnItemChangedListener != null)
this.mOnItemChangedListener.onItemChanged(i, datas[i]);
try {
Thread.sleep(15);
} catch (InterruptedException e) {
e.printStackTrace();
}
gain(0.5f);
}
canvas.drawArc(rectF, startAngleTemp - 1.5f, 360F * datas[i] / dataSum + 1.5f, false, paintArc);
} else if (this.ACTION_ == this.ACTION_ENLARGE) {
if (curColorIndex == i && datas.length > 1) {
setRectFSelected();
canvas.drawArc(rectFSelected, startAngleTemp + 2f, 360F * datas[i] / dataSum - 5.5f, false, paintArc);
} else {
canvas.drawArc(rectF, startAngleTemp - 1.5f, 360F * datas[i] / dataSum + 1.5f, false, paintArc);
}
}
canvas.restore();
}
}
触摸事件监听处理
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
curtX = event.getX();
curtY = event.getY();
break;
case MotionEvent.ACTION_UP:
if (this.datas == null || this.dataSum == 0F) {
break;
}
setDrawingCacheEnabled(true);
bitmap = getDrawingCache();
if (bitmap == null) {
Log.w(TAG, "bitmap == null");
break;
}
int pixel = bitmap.getPixel((int) curtX, (int) curtY);
setDrawingCacheEnabled(false);
//获取颜色RGB
int redValue = Color.red(pixel);
int blueValue = Color.blue(pixel);
int greenValue = Color.green(pixel);
int tarIndex = 0;
String curColorHex = ColorUtil.toHex(redValue, greenValue, blueValue);
for (int i = 0; i < arcColors.length; i++) {
if (curColorHex.equals(arcColors[i])) {
tarIndex = i;
break;
}
}
if (curColorIndex == tarIndex) {
break;
}
curColorIndex = tarIndex;
curIndexdegree = 360 * datas[curColorIndex] / dataSum;
if (curColorIndex == 0) {
curIndexOffsetdegree = 90;
} else {
curIndexOffsetdegree = 90;
for (int j = 0; j < curColorIndex; j++) {
if (j == 0) {
curIndexOffsetdegree += 180 * datas[j] / dataSum;
} else {
curIndexOffsetdegree += 360 * datas[j] / dataSum;
}
}
curIndexOffsetdegree += curIndexdegree / 2;
}
degreeT += offsetDegree - curIndexOffsetdegree;
offsetDegree = curIndexOffsetdegree;
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
rotation(degreeT);
break;
}
return true;
}
布局
<com.fairytale110.mycustomviews.Widget._fa_pieChartView
android:id="@+id/piechart"
android:layout_width="250dp"
android:layout_height="250dp"
android:background="@android:color/white"
android:padding="10dp"
/>
使用
Float[] datas = {73.54F,80.01F,90.00F,103F,120F};
piechart.setDatas(datas);
piechart.setOnItemChangedListener(new _fa_pieChartView.OnItemChangedListener() {
@Override
public void onItemChanged(int index, float value) {
txtData.setText("index: " +index+ " value: "+value );
}
});
运行结果
运行结果小结
基本上达到途中效果,唯一的遗憾的突出色块与两边邻近色块的间隙不平行,有待优化,欢迎分享