Android手绘手写图DrawableView



Android手绘手写图DrawableView

Android上的第三方开源DrawableView支持手写,类似于写字板。DrawableView支持改变画笔颜色,画笔线条粗细,画布的手势缩放和拖曳显示部分区域。并最终支持将手绘的图保存到本地。
在github上的项目主页:https://github.com/PaNaVTEC/DrawableView
先把布局文件中写一个DrawableView:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <Button
            android:id="@+id/strokeWidthPlusButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="画笔宽度+" />

        <Button
            android:id="@+id/strokeWidthMinusButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="画笔宽度-" />

        <Button
            android:id="@+id/changeColorButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="画笔颜色" />

        <Button
            android:id="@+id/undoButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="撤销上一步" />
        
         <Button
            android:id="@+id/saveButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="保存成图片" />
        
    </LinearLayout>

    <me.panavtec.drawableview.DrawableView
        android:id="@+id/paintView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>


Java代码:

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Random;
import me.panavtec.drawableview.DrawableView;
import me.panavtec.drawableview.DrawableViewConfig;

public class MainActivity extends Activity {

	private DrawableView drawableView;
	private DrawableViewConfig config = new DrawableViewConfig();

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		drawableView = (DrawableView) findViewById(R.id.paintView);
		

		// 画笔宽度-
		Button strokeWidthMinusButton = (Button) findViewById(R.id.strokeWidthMinusButton);

		// 画笔宽度+
		Button strokeWidthPlusButton = (Button) findViewById(R.id.strokeWidthPlusButton);

		// 改变画笔颜色
		Button changeColorButton = (Button) findViewById(R.id.changeColorButton);

		// 撤销上一步绘画操作
		Button undoButton = (Button) findViewById(R.id.undoButton);

		Button saveButton = (Button) findViewById(R.id.saveButton);

		// 画笔颜色
		config.setStrokeColor(Color.RED);

		// 画布边界
		config.setShowCanvasBounds(true);

		// 设置画笔宽度
		config.setStrokeWidth(10.0f);

		// 缩放
		config.setMinZoom(1.0f);
		config.setMaxZoom(3.0f);

		// 高和宽
		config.setCanvasHeight(500);
		config.setCanvasWidth(700);

		drawableView.setConfig(config);

		strokeWidthPlusButton.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				// 增宽则每次增加10
				config.setStrokeWidth(config.getStrokeWidth() + 10);
			}
		});

		strokeWidthMinusButton.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				// 减宽则每次减小10
				config.setStrokeWidth(config.getStrokeWidth() - 10);
			}
		});

		changeColorButton.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				// 测试期间,随机生成一些颜色
				Random random = new Random();
				config.setStrokeColor(Color.argb(255, random.nextInt(256), random.nextInt(256), random.nextInt(256)));
			}
		});

		undoButton.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				drawableView.undo();
			}
		});

		saveButton.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				try {
					saveBitmapToSDCard();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		});
	}

	// 将用户手绘的DrawableView转化为图片保存到本地系统默认的图片库中。
	private void saveBitmapToSDCard() throws IOException {

		// 从DrawableView获得Bitmap
		Bitmap bmp = drawableView.obtainBitmap();

		File parent_path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);

		File f = new File(parent_path.getAbsoluteFile(), "myDrawableView.png");
		f.createNewFile();

		Log.d("保存图片的路径", f.getAbsolutePath());

		FileOutputStream fos = new FileOutputStream(f);
		bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
		fos.flush();
		fos.close();

		Log.d("保存图片", "成功");
	}
}



运行结果如图:



默认的,在未发布的debug阶段,DrawableView会在画布上添加一些log日志输出。如果不打算在画布中显示log,可以修改DrawableView的源代码去掉DrawableView默认的log日志。关键代码有两行,在CanvasDrawer的库文件源代码中:

initLogger();

...

canvasLogger.log(canvas, canvasRect, viewRect, scaleFactor);

将这两行注释掉即可,如图:


附录参考文章:
【文章1】《Android写文件到SDCard的一般过程和代码》链接地址:http://blog.csdn.net/zhangphil/article/details/49976687
【文章2】《Android View转换成图片保存》链接地址:http://blog.csdn.net/zhangphil/article/details/44217539


package com.example.linchartdemo.view; import java.util.List; import android.R.color; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Typeface; import android.util.AttributeSet; import android.util.Log; import android.view.View; public class ZXView extends View { private List<Integer> xlist;// X坐标标签 private List<Integer> ylist;// Y坐标标签 private List<Integer> params;// 参数集合 private Paint paint; private Paint paintLines; private Paint paintArc; private Paint paintText; private int textsize = 20; private float Xoffset = 0;// X轴偏移或叫间隔 private float Yoffset = 0;// Y轴偏移或叫间隔 public float XSpac = 50; public float Xspac = 50; public float YSpac = 50; public float rightXspac = 50; public float rightYspac = 50; public float circleRadius = 10; private float lastX = -1; private float lastY = -1; public ZXView(Context context, List<Integer> xlists, List<Integer> ylists, List<Integer> paramss) { super(context); xlist = xlists; ylist = ylists; params = paramss; initWidget(); } public ZXView(Context context, AttributeSet attrs) { super(context, attrs); initWidget(); } public ZXView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initWidget(); } public void initViewData(List<Integer> xlists, List<Integer> ylists, List<Integer> paramss) { xlist = xlists; ylist = ylists; params = paramss; } @Override protected void onDraw(Canvas canvas) { drawXY(canvas); drawLine(canvas); super.onDraw(canvas); } public void updataUI() { invalidate(); } /** * 画折线 * * @param canvas */ private void drawLine(Canvas canvas) { Xoffset = ((getWidth()) - 20) / (xlist.size()); Yoffset = (getHeight()) / (ylist.size()); Log.i("texts", "X=" + Xoffset + "Y=" + Yoffset); float rulerOffset = 0; if (xlist.size() < 2) throw new IllegalArgumentException("the params argument is <2"); else rulerOffset = (xlist.get(1) - xlist.get(0)); if (params == null && params.size() <= 0) throw new IllegalArgumentException("the params is null or 0"); // Paint p = new Paint(); // p.setAntiAlias(true); // p.setTextSize(25); // p.setColor(Color.WHITE); // canvas.drawText("KW", 10 + Xoffset, 20, p); for (int i = 0; i < params.size(); i++) { int param = params.get(i); float histigramHight = param * (Yoffset / rulerOffset); float currentX = (Xoffset * i + Xspac + 5); float currentY = (getHeight() - YSpac - histigramHight); canvas.drawCircle(currentX, currentY, circleRadius, paintArc); if (lastX != -1) { canvas.drawLine(lastX, lastY, currentX, currentY, paintLines); } lastX = currentX; lastY = currentY; } // 重置lastX跟Y lastX = -1; lastY = -1; } /** * 画坐标轴 * * @param canvas */ private void drawXY(Canvas canvas) { canvas.drawLine(XSpac, 0, XSpac, getHeight() - 5 - XSpac, paint);// x canvas.drawLine(XSpac, getHeight() - XSpac, getWidth(), getHeight() - XSpac, paint);// y canvas.drawLine(getWidth(), 0, getWidth() - 1, getWidth() - YSpac, paint);// 右边Y float yoffset = getHeight() / ylist.size(); float xoffset = (getWidth() - XSpac) / xlist.size(); // 画字 for (int i = 0; i < ylist.size(); i++) { canvas.drawText(ylist.get(i) + "", 0, getHeight() - yoffset * i - YSpac, paintText); } for (int i = 0; i < xlist.size(); i++) { canvas.drawText(xlist.get(i) + "", XSpac + xoffset * i, getHeight() - YSpac + textsize, paintText); } // for (int i = 0; i < ylist.size(); i++) { // for (int j = 0; j < 50; j++) { // canvas.drawLine(XSpac + j * 303, yoffset * i - YSpac, XSpac + j // * 30 + 20, yoffset * i - YSpac, paint); // } // } } /** * 初始化画笔 */ private void initWidget() { paint = new Paint(); paint.setColor(Color.parseColor("#999999")); paint.setTypeface(Typeface.DEFAULT); paint.setAntiAlias(true); paint.setStrokeWidth(2); paintLines = new Paint(); paintLines.setColor(Color.parseColor("#00B4EA")); paintLines.setTypeface(Typeface.DEFAULT); paintLines.setAntiAlias(true); paintLines.setStrokeWidth(3); paintArc = new Paint(); paintArc.setColor(Color.parseColor("#EBEEEF")); paintArc.setTypeface(Typeface.DEFAULT); paintArc.setAntiAlias(true); paintArc.setStrokeWidth(2); paintText = new Paint(); // paintText.setColor(Color.parseColor("#ffffff")); paintText.setTypeface(Typeface.DEFAULT); paintText.setAntiAlias(true); paintText.setStrokeWidth(2); paintText.setTextSize(textsize); } }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangphil

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值