Android中绘图的方式有多种,在一些App中与可能会用到,小弟利用闲暇时间在网上找了一点资料进行研究,谨在此汇总一下,希望对用需要的同仁有所帮助。说到自定义控件相信大家都不陌生,这边文章主要介绍的就是利用自定义控件进行绘制。其中主要在onDraw()方法中进行操作。主要用到的有控件Paint(画笔)和Path这两种。下面直接多行代码了,代码中都有注释,不再多做解释:
1.主函数中不用做任何操作,只要在主函数的布局中调用即可:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.wls.pathdraw.MainActivity">
<view.MyView2
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<view.MyView
android:id="@+id/view_line"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
2.下面是自定义MyView中的代码。展示的是一种折线图:
public class MyView extends View {
//原点位置的坐标
private int xPoint = 260;
private int yPoint = 760;
//刻度长度
private int xScal = 8;//8个单位构成一个刻度
private int yScal = 40;
//x轴与y轴坐标轴的长度
private int xLength = 380;
private int yLength = 240;
//横坐标最多可绘制的点
private int MaxDataSize = xLength/xScal;
//存放纵坐标所绘制的点
private List<Integer> yList = new ArrayList<>();
//y轴刻度上显示字的集合
private String [] yLable = new String[yLength/yScal];
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what == 0){
MyView.this.invalidate();//刷新view
}
}
};
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
for(int i = 0; i < yLable.length; i++){
yLable[i] = (i+1) + "M/s";
}
new Thread(new Runnable() {
@Override
public void run() {
while (true){//在线程中不断往集合中添加数据
try {
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
//判断集合长度是否大于最大绘制长度
if(yList.size() > MaxDataSize){
yList.remove(0);
}
//生成1-6的随机数
yList.add(new Random().nextInt(5) + 1);
mHandler.sendEmptyMessage(0);//发送空消息通知刷新
}
}
}).start();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
//画y轴
canvas.drawLine(xPoint,yPoint - yLength,xPoint,yPoint,mPaint);
//y轴箭头
canvas.drawLine(xPoint,yPoint - yLength,xPoint - 3,yPoint - yLength + 6,mPaint);
canvas.drawLine(xPoint,yPoint - yLength,xPoint + 3,yPoint - yLength + 6,mPaint);
//绘制刻度和文字
for(int i = 0; i * yScal < yLength; i++){
canvas.drawLine(xPoint,yPoint - i * yScal,xPoint + 5,yPoint - i * yScal,mPaint);
canvas.drawText(yLable[i],xPoint - 50, yPoint - i * yScal,mPaint);
}
//画X轴
canvas.drawLine(xPoint,yPoint,xPoint + xLength,yPoint,mPaint);
//如果集合中有数据,依次取出进行绘制
/* if(yList.size() > 1){
for(int i = 1; i < yList.size(); i ++){
canvas.drawLine(xPoint + (i - 1) * xScal,yPoint - yList.get(i - 1) * yScal,xPoint + i * xScal,yPoint - yList.get(i) * yScal,mPaint);
}
}*/
//这里也可以使用canvas.drawPath()绘制(无填充)
/* if(yList.size() > 1){
Path mPath = new Path();
mPath.moveTo(xPoint,yPoint - yList.get(0) * yScal);//起点
for(int i = 1; i < yList.size(); i ++){
mPath.lineTo(xPoint + i * xScal,yPoint - yList.get(i) * yScal);
}
canvas.drawPath(mPath,mPaint);
}*/
/*//这里实现填充(无边界)
mPaint.setStyle(Paint.Style.FILL);//实现填充
if(yList.size() > 1){
Path mPath = new Path();
mPath.moveTo(xPoint,yPoint - yList.get(0) * yScal);//起点
for(int i = 1; i < yList.size(); i ++){
mPath.lineTo(xPoint + i * xScal,yPoint - yList.get(i) * yScal);
}
mPath.lineTo(xPoint + (yList.size() - 1) * xScal,yPoint);
canvas.drawPath(mPath,mPaint);
}*/
mPaint.setStrokeWidth(5f);//红色边界的填充
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
if(yList.size() > 1){
Path mPath = new Path();
Path path = new Path();
mPath.moveTo(xPoint,yPoint - yList.get(0) * yScal);//起点
path.moveTo(xPoint,yPoint);
for(int i = 0; i < yList.size(); i ++){
mPath.lineTo(xPoint + i * xScal,yPoint - yList.get(i) * yScal);
path.lineTo(xPoint + i * xScal,yPoint - yList.get(i) * yScal);
}
path.lineTo(xPoint + (yList.size() - 1) * xScal,yPoint);
canvas.drawPath(mPath,mPaint);
canvas.drawPath(path,paint);
}
}
}
这里介绍了绘制折线时的两种方法:canvas.drawLine()和canvas.drawPath()。里面对图形的展示有三种形式,无填充色的,有填充色的和有红色边线的三种展现形式,均可以实现。下面的效果图中,只会展示有边界线的。
2.自定义MyView2的代码,这里绘制了空心,实心,渐变色和字体四中样式。绘制的图形分别是圆形,正方形,长方形,椭圆,三角形和梯形,分为四列展示即四中样式。
public class MyView2 extends View {
public MyView2(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
/**
* 第一列,空心
*/
Paint mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);//空心
mPaint.setAntiAlias(true);//抗锯齿
mPaint.setStrokeWidth(3f);
canvas.drawCircle(40,40,30,mPaint);//圆形
canvas.drawRect(10,90,70,150,mPaint);//正方形
canvas.drawRect(10,170,70,200,mPaint);//长方形
canvas.drawOval(new RectF(10,220,70,250),mPaint);//椭圆形
Path path = new Path();//运用path绘制三角形
path.moveTo(10,330);
path.lineTo(70,330);
path.lineTo(40,270);
path.close();//封闭的图形
canvas.drawPath(path,mPaint);
Path mPath = new Path();//绘制梯形
mPath.moveTo(10,410);
mPath.lineTo(70,410);
mPath.lineTo(55,350);
mPath.lineTo(25,350);
mPath.close();
canvas.drawPath(mPath,mPaint);
/**
* 第二列,实心
*/
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.FILL);//实心
mPaint.setAntiAlias(true);//抗锯齿
mPaint.setStrokeWidth(3f);
canvas.drawCircle(120,40,30,mPaint);//圆形
canvas.drawRect(90,90,150,150,mPaint);//正方形
canvas.drawRect(90,170,150,200,mPaint);//长方形
canvas.drawOval(new RectF(90,220,150,250),mPaint);//椭圆形
Path path2 = new Path();//运用path绘制三角形
path2.moveTo(90,330);
path2.lineTo(150,330);
path2.lineTo(120,270);
path2.close();//封闭的图形
canvas.drawPath(path2,mPaint);
Path mPath2 = new Path();//绘制梯形
mPath2.moveTo(90,410);
mPath2.lineTo(150,410);
mPath2.lineTo(135,350);
mPath2.lineTo(105,350);
mPath2.close();
canvas.drawPath(mPath2,mPaint);
/**
* 第三列,渐变色
* LinearGradient shader = new LinearGradient(0, 0, endX, endY, new
* int[]{startColor, midleColor, endColor},new float[]{0 , 0.5f,
* 1.0f}, TileMode.MIRROR);
* 参数一为渐变起初点坐标x位置,参数二为y轴位置,参数三和四分辨对应渐变终点
* 其中参数new int[]{startColor, midleColor,endColor}是参与渐变效果的颜色集合,
* 其中参数new float[]{0 , 0.5f, 1.0f}是定义每个颜色处于的渐变相对位置,
* 这个参数可以为null,如果为null表示所有的颜色按顺序均匀的分布
*/
Shader shader = new LinearGradient(0,0,100,100,
new int[]{Color.RED,Color.GREEN,Color.BLUE,Color.YELLOW},null, Shader.TileMode.REPEAT);
// Shader.TileMode三种模式
// REPEAT:沿着渐变方向循环重复
// CLAMP:如果在预先定义的范围外画的话,就重复边界的颜色
// MIRROR:与REPEAT一样都是循环重复,但这个会对称重复
mPaint.setShader(shader);//用shader中定义的颜色来画
canvas.drawCircle(200,40,30,mPaint);
canvas.drawRect(170,90,230,150,mPaint);//正方形
canvas.drawRect(170,170,230,200,mPaint);//长方形
canvas.drawOval(new RectF(170,220,230,250),mPaint);//椭圆形
Path path3 = new Path();//运用path绘制三角形
path3.moveTo(170,330);
path3.lineTo(230,330);
path3.lineTo(200,270);
path3.close();//封闭的图形
canvas.drawPath(path3,mPaint);
Path mPath3 = new Path();//绘制梯形
mPath3.moveTo(170,410);
mPath3.lineTo(230,410);
mPath3.lineTo(215,350);
mPath3.lineTo(185,350);
mPath3.close();
canvas.drawPath(mPath3,mPaint);
/**
* 第四列,绘制字体
*/
mPaint.setTextSize(24);
canvas.drawText("圆形", 240, 50, mPaint);
canvas.drawText("正方形", 240, 120, mPaint);
canvas.drawText("长方形", 240, 190, mPaint);
canvas.drawText("椭圆形", 240, 250, mPaint);
canvas.drawText("三角形", 240, 320, mPaint);
canvas.drawText("梯形", 240, 390, mPaint);
}
}
下面是绘制的效果图