赞
踩
重写View中的OnDraw()方法,进行统计图的绘制。
在 Android 里,每个 View 都有一个自己的坐标系,彼此之间是不影响的。这个坐标系的原点是 View 左上角的那个点;水平方向是 x 轴,右正左负;竖直方向是 y 轴,下正上负。
获取屏幕中心点坐标:
centerX = getResources().getDisplayMetrics().widthPixels/2;
centerY = getResources().getDisplayMetrics().heightPixels/2;
在这个方法拿到canvas对象,可以进行绘制。
Paint paint = new Paint();
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 绘制一个圆
canvas.drawCircle(300, 300, 200, paint);
}
首先,我们需要计算各个数据在饼状图中占的角度,以及我们为各个数据设置的颜色。然后根据角度去绘制相应的扇形,并根据颜色设置绘制的paint。
drawArc() 中left, top, right, bottom 描述的是这个弧形所在的椭圆(圆);startAngle 是弧形的起始角度(x 轴的正向,即正右的方向,是 0 度的位置;顺时针为正角度,逆时针为负角度),sweepAngle 是弧形划过的角度;useCenter 表示是否连接到圆心,如果不连接到圆心,就是弧形,如果连接到圆心,就是扇形。
useCenter 这里需要true
显然我们需要每绘制完一个扇形就要重新计算起始角度。其他的没什么逻辑了。
本人写了一个简单的view,包括饼状图和图例部分。
private HashMap<String , Float> DataDegree(){
HashMap<String , Float> data = new HashMap<>();
data.put("苹果", 30f);
data.put("西瓜", 41f);
data.put("香蕉", 59f);
data.put("脐橙", 80f);
data.put("菠萝",140f);
return data;
}
@RequiresApi(api = Build.VERSION_CODES.O)
private HashMap<String , String> DataColor(){
HashMap<String , String> data = new HashMap<>();
data.put("苹果", "#6600ff");
data.put("西瓜", "#cc00ff");
data.put("香蕉","#9933ff");
data.put("脐橙", "#ff9900");
data.put("菠萝","#9999ff");
return data;
}
@RequiresApi(api = Build.VERSION_CODES.O) private void drawPieChartAnno() { HashMap<String , Float> dataDegree = DataDegree(); HashMap<String , String> dataColor = DataColor(); int left = 30; int right = 150; int top = 30; int rectHeight = 80; int bottom = top+rectHeight; int blank = 30; mPaint.setStyle(Paint.Style.FILL); mPaint.setTextSize(50); for(String key : dataDegree.keySet()){ mPaint.setColor(Color.parseColor(dataColor.get(key))); mCanvas.drawRect(left,top,right,bottom,mPaint); mPaint.setColor(Color.DKGRAY); mCanvas.drawText(key+":"+ new DecimalFormat("#.00").format((dataDegree.get(key)+2)/360*100)+"%",right+blank, bottom ,mPaint); //更新边界位置 top = bottom + blank; bottom = top + rectHeight; } }
@RequiresApi(api = Build.VERSION_CODES.O) private void darwPieChart() { HashMap<String , Float> dataDegree = DataDegree(); HashMap<String , String> dataColor = DataColor(); int left = centerX - 400; int right = centerX + 400; int top = centerY +100-400 ; int bottom = centerY +100 +400; //根据颜色和度数绘制饼状图 float startAngle = 2f; mPaint.setStyle(Paint.Style.FILL); for(String key : dataDegree.keySet()){ mPaint.setColor(Color.parseColor(dataColor.get(key))); mCanvas.drawArc(left,top,right,bottom, startAngle,dataDegree.get(key),true,mPaint); startAngle += dataDegree.get(key)+ 2f; } }
import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.os.Build; import android.support.annotation.RequiresApi; import android.view.View; import java.text.DecimalFormat; import java.util.HashMap; public class MyDataView extends View { private Paint mPaint = new Paint(); private Canvas mCanvas; private int centerX,centerY; public MyDataView(Context context) { super(context); } @RequiresApi(api = Build.VERSION_CODES.O) @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.WHITE); mCanvas = canvas; centerX = getResources().getDisplayMetrics().widthPixels/2; centerY = getResources().getDisplayMetrics().heightPixels/3; //绘制 饼图 darwPieChart(); //绘制图例 drawPieChartAnno(); } @RequiresApi(api = Build.VERSION_CODES.O) private void drawPieChartAnno() { HashMap<String , Float> dataDegree = DataDegree(); HashMap<String , String> dataColor = DataColor(); int left = 30; int right = 150; int top = 30; int rectHeight = 80; int bottom = top+rectHeight; int blank = 30; mPaint.setStyle(Paint.Style.FILL); mPaint.setTextSize(50); for(String key : dataDegree.keySet()){ mPaint.setColor(Color.parseColor(dataColor.get(key))); mCanvas.drawRect(left,top,right,bottom,mPaint); mPaint.setColor(Color.DKGRAY); mCanvas.drawText(key+":"+ new DecimalFormat("#.00").format((dataDegree.get(key)+2)/360*100)+"%",right+blank, bottom ,mPaint); //更新边界位置 top = bottom + blank; bottom = top + rectHeight; } } @RequiresApi(api = Build.VERSION_CODES.O) private void darwPieChart() { HashMap<String , Float> dataDegree = DataDegree(); HashMap<String , String> dataColor = DataColor(); int left = centerX - 400; int right = centerX + 400; int top = centerY +100-400 ; int bottom = centerY +100 +400; //根据颜色和度数绘制饼状图 float startAngle = 2f; mPaint.setStyle(Paint.Style.FILL); for(String key : dataDegree.keySet()){ mPaint.setColor(Color.parseColor(dataColor.get(key))); mCanvas.drawArc(left,top,right,bottom, startAngle,dataDegree.get(key),true,mPaint); startAngle += dataDegree.get(key)+ 2f; } } private HashMap<String , Float> DataDegree(){ HashMap<String , Float> data = new HashMap<>(); data.put("苹果", 30f); data.put("西瓜", 41f); data.put("香蕉", 59f); data.put("脐橙", 80f); data.put("菠萝",140f); return data; } @RequiresApi(api = Build.VERSION_CODES.O) private HashMap<String , String> DataColor(){ HashMap<String , String> data = new HashMap<>(); data.put("苹果", "#6600ff"); data.put("西瓜", "#cc00ff"); data.put("香蕉","#9933ff"); data.put("脐橙", "#ff9900"); data.put("菠萝","#9999ff"); return data; } }
public class CanvasActivity extends AppCompatActivity {
private MyDataView myDataView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myDataView = new MyDataView(this);
setContentView(myDataView);
}
}
上面的View是一个写死的数据源和数据颜色,用户交互性较差。
那么,我们来优化一下我们的View,使得我们可以将数据和View分离,达到给View传递数据,可以控制生成view及样式。
那么,如何给我们的View传递数据呢?
那就是在我们的构造方法中添加我们的数据和颜色。
来看一下代码:
/** * constructor * @param context * @param dataDegree * @param dataColor */ public MyDataView(Context context, HashMap<String , Float> dataDegree, HashMap<String , String> dataColor) { super(context); this.dataDegree = dataDegree; this.dataColor = dataColor; } /** * constructor * @param context * @param dataDegree * @param dataColor * @param attrs */ public MyDataView(Context context, HashMap<String , Float> dataDegree, HashMap<String , String> dataColor, @Nullable AttributeSet attrs ) { super(context, attrs); this.dataDegree = dataDegree; this.dataColor = dataColor; } /** * constructor * @param context * @param dataDegree * @param dataColor * @param attrs * @param defStyleAttr */ public MyDataView(Context context, HashMap<String , Float> dataDegree, HashMap<String , String> dataColor, @Nullable AttributeSet attrs, int defStyleAttr ) { super(context, attrs, defStyleAttr); this.dataDegree = dataDegree; this.dataColor = dataColor; } /** * constructor * @param context * @param dataDegree * @param dataColor * @param attrs * @param defStyleAttr * @param defStyleRes */ public MyDataView(Context context, HashMap<String , Float> dataDegree, HashMap<String , String> dataColor, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes ) { super(context, attrs, defStyleAttr, defStyleRes); this.dataDegree = dataDegree; this.dataColor = dataColor; }
同时,为了让我们的统计图适应不同的大小,我们不把其中的数据写死,而是根据其大小进行设置。
另外,我们的数据可以灵活的加入。
@RequiresApi(api = Build.VERSION_CODES.O) @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.WHITE); mCanvas = canvas; mWidth = canvas.getWidth(); mHeight = canvas.getHeight(); //定义一个我们的尺寸单位 mPx = Math.max(mWidth/100, 10); //绘制 饼图 darwPieChart(); //绘制图例 drawPieChartAnno(); } /** * 绘制图例 */ @RequiresApi(api = Build.VERSION_CODES.O) private void drawPieChartAnno() { //设置绘图参数 int left = mPx; int right = mPx * 6; int top = mPx; int rectHeight = mPx * 3; int bottom = top+rectHeight; int blank = mPx; mPaint.setStyle(Paint.Style.FILL); mPaint.setTextSize(mPx * 2); for(String key : dataDegree.keySet()){ mPaint.setColor(Color.parseColor(dataColor.get(key))); mCanvas.drawRect(left,top,right,bottom,mPaint); mPaint.setColor(Color.DKGRAY); mCanvas.drawText(key+":"+ new DecimalFormat("#.00").format((dataDegree.get(key))/360*100)+"%",right+blank, bottom ,mPaint); //更新边界位置 top = bottom + blank; bottom = top + rectHeight; } } /** * 绘制统计图 */ @RequiresApi(api = Build.VERSION_CODES.O) private void darwPieChart() { int centerX = mWidth/2; int centerY = mHeight/2; int radius = mPx * 20; int left = centerX - radius; int right = centerX + radius; int top = centerY - radius ; int bottom = centerY + radius; //根据颜色和度数绘制饼状图 float startAngle = 0f; mPaint.setStyle(Paint.Style.FILL); for(String key : dataDegree.keySet()){ //绘制饼状图 mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(Color.parseColor(dataColor.get(key))); mCanvas.drawArc(left,top,right,bottom, startAngle,dataDegree.get(key),true,mPaint); //给饼状图添加一个修饰,白边 mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(Color.WHITE); mCanvas.drawArc(left,top,right,bottom, startAngle,dataDegree.get(key),true,mPaint); startAngle += dataDegree.get(key); } }
然后,使用的时候,我们需要在代码中动态添加这个视图,通过new MyDataView(this, DataDegree(), DataColor())初始化,然后addView(myDataView, params)的方式添加。
@RequiresApi(api = Build.VERSION_CODES.O) @Override protected void onResume() { super.onResume(); myDataView = new MyDataView(this, DataDegree(), DataColor()); params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); mLny.addView(myDataView, params); } private HashMap<String , Float> DataDegree(){ dataDegee.put("餐饮消费", 32f); dataDegee.put("文教娱乐", 42f); dataDegee.put("服饰美容", 52f); dataDegee.put("出行交通", 92f); dataDegee.put("其它",142f); return dataDegee; } @RequiresApi(api = Build.VERSION_CODES.O) private HashMap<String , String> DataColor(){ dataColor.put("餐饮消费", "#6600ff"); dataColor.put("文教娱乐", "#cc00ff"); dataColor.put("服饰美容","#9933ff"); dataColor.put("出行交通", "#ff9900"); dataColor.put("其它","#9999ff"); return dataColor; }
完整代码git地址:https://github.com/DuckGrandfather/GeneratePieChart.git
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。