写这篇文章是因为代码中刚实现过这些功能,害怕自己之后会忘记,所以把整个方法写出来,方便自己日后复习用。

还是老样子,先上图:

1.首页

2.点击手绘板图片后跳出的窗口

3.用手指进行绘制

4.点击保存按钮

原理什么的就不说了,直接上代码:

1.MainActivity

import androidx.appcompat.app.AppCompatActivity;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Base64;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;

import java.io.ByteArrayOutputStream;

public class MainActivity extends AppCompatActivity {
    private ImageView iv_wacom_may;//显示图片用的控件
    private MakeWacomDialog makeWacomDialog;//用来显示手绘板的对话框
    private String savedphoto = "";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();//代码初始化
        setClick();//设置点击方法
    }

    /**
     * 设置点击方法
     */
    private void setClick() {
        iv_wacom_may.setOnClickListener(new MainAcitivytClick());
    }

    /**
     * 代码初始化
     */
    private void initView() {
        iv_wacom_may = findViewById(R.id.iv_wacom_may);
    }

    /**
     * 设置MainActivity的点击方法
     */
    private class MainAcitivytClick implements View.OnClickListener {

        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.iv_wacom_may://点击了手绘板图片
                    BitmapFactory.Options options = new BitmapFactory.Options();
                    if (TextUtils.isEmpty(savedphoto)) {//修改后图片的数据,首次进入数据会是空的,这里用默认图片代替
                        savedphoto = changeBitmapToString(BitmapFactory.decodeResource(getResources(),
                                R.mipmap.wacom, options));
                    }
                    String defaultimg = changeBitmapToString(BitmapFactory.decodeResource(getResources(),
                            R.mipmap.wacom, options));//默认图片的数据
                    makeWacomDialog = new MakeWacomDialog(MainActivity.this, new saveResult(), savedphoto, defaultimg);
                    makeWacomDialog.setCancelable(false);//失去焦点后不会自动关闭对话框
                    makeWacomDialog.show();//展示对话框
                    break;
                default:
                    break;
            }
        }
    }

    /**
     * 将图片转换成String形式
     *
     * @param bitmap
     */
    private String changeBitmapToString(Bitmap bitmap) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
        byte[] byteArray = byteArrayOutputStream.toByteArray();
        return Base64.encodeToString(byteArray, Base64.DEFAULT);
    }

    /**
     * 手绘板界面点击保存按钮后执行的监听
     */
    private class saveResult implements MakeWacomDialog.GetSignature {

        @Override
        public void getSignature(MakeWacomView makeWacomView, Bitmap bitmap) {
            savedphoto = changeBitmapToString(bitmap);
            byte[] imageBytes = Base64.decode(savedphoto, Base64.DEFAULT);
            Bitmap photobitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
            iv_wacom_may.setImageBitmap(photobitmap);
            makeWacomDialog.dismiss();//关闭手绘板
        }
    }
}

2.activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:text="首页"
        android:textSize="20sp"
        android:gravity="center"
       />
    <ImageView
        android:id="@+id/iv_wacom_may"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_gravity="center_horizontal"
        android:src="@mipmap/wacom"
        android:layout_centerInParent="true"
        />
</RelativeLayout>

3.MakeWacomDialog

import android.app.Dialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;

import androidx.annotation.NonNull;

/**
 * @author Jay
 * @date 2021/3/9
 * File description.
 * 手绘板提示框
 */
public class MakeWacomDialog extends Dialog {
    private Button btn_save_dmm, btn_cancel_dmm, btn_clear_dmm, btn_reset_dmm;
    private LinearLayout ll_wacom_dmm;
    private Context context;
    private MakeWacomView makeWacomView;
    private GetSignature mGetSignature;
    private String localphoto = "";
    private String defaultimg;
    private Boolean isdefaultimg = false;

    protected MakeWacomDialog(@NonNull Context context, GetSignature getSignature, String localphoto, String defaultimg) {
        super(context);
        this.context = context;
        makeWacomView = new MakeWacomView(context);

        this.mGetSignature = getSignature;
        this.localphoto = localphoto;
        this.defaultimg = defaultimg;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.dialog_makewacom);
        initWeightandHeight();//设置对话框的宽高
        initView();//代码初始化
        setClick();//设置点击方法
        ll_wacom_dmm.addView(makeWacomView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        setBakcground(localphoto);//设置背景图
    }

    /**
     * 设置背景图
     *
     * @param localphoto
     */
    private void setBakcground(String localphoto) {
        try {
            if (TextUtils.isEmpty(localphoto)) {
                return;
            }
            byte[] imageBytes = Base64.decode(localphoto, Base64.DEFAULT);
            Bitmap decodedImage = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
            Drawable d = new BitmapDrawable(getContext().getResources(), decodedImage);
//            mSignContent.setBackground(d);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                makeWacomView.clear();//赋值前先清空之前的图
                makeWacomView.setBackground(d);
            } else {
                Toast.makeText(context, "当前版本不支持", Toast.LENGTH_SHORT).show();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置对话框的宽高
     */
    private void initWeightandHeight() {
        getWindow().setLayout(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT
        );
    }

    /**
     * 设置点击方法
     */
    private void setClick() {
        btn_save_dmm.setOnClickListener(new MakeWacomClick());
        btn_cancel_dmm.setOnClickListener(new MakeWacomClick());
        btn_clear_dmm.setOnClickListener(new MakeWacomClick());
        btn_reset_dmm.setOnClickListener(new MakeWacomClick());
    }

    /**
     * 代码初始化
     */
    private void initView() {
        btn_save_dmm = findViewById(R.id.btn_save_dmm);//保存按钮
        btn_cancel_dmm = findViewById(R.id.btn_cancel_dmm);//取消按钮
        btn_clear_dmm = findViewById(R.id.btn_clear_dmm);//清空按钮
        btn_reset_dmm = findViewById(R.id.btn_reset_dmm);//重置按钮
        ll_wacom_dmm = findViewById(R.id.ll_wacom_dmm);//显示手绘板的控件
    }

    /**
     * 设置手绘板提示框的点击方法
     */
    private class MakeWacomClick implements View.OnClickListener {

        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btn_save_dmm://保存按钮
                    Bitmap bitmap = getBitmapFromView(makeWacomView);
                    mGetSignature.getSignature(makeWacomView, bitmap);
                    break;
                case R.id.btn_cancel_dmm://取消按钮
                    MakeWacomDialog.this.dismiss();//关闭页面
                    break;
                case R.id.btn_clear_dmm://清空按钮
                    if (TextUtils.isEmpty(localphoto)) {
                        makeWacomView.clear();
                    } else {
                        if (isdefaultimg) {//如果用户恢复了原图,这里就将原图作为底图
                            setBakcground(defaultimg);
                        } else {//如果用户没有恢复原图,就将接口传递过来的历史图作为底图
                            setBakcground(localphoto);
                        }
                    }
                    break;
                case R.id.btn_reset_dmm://重置按钮
                    setBakcground(defaultimg);//设置背景图
                    isdefaultimg = true;
                    break;
            }
        }
    }

    /**
     * 获取bitmap图
     *
     * @param makeWacomView
     * @return
     */
    private Bitmap getBitmapFromView(MakeWacomView makeWacomView) {
        Bitmap returnedBitmap = Bitmap.createBitmap(makeWacomView.getWidth(), makeWacomView.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(returnedBitmap);
        Drawable bgDrawable = makeWacomView.getBackground();
        if (bgDrawable != null)
            bgDrawable.draw(canvas);
        else
            canvas.drawColor(Color.WHITE);
        makeWacomView.draw(canvas);
        return returnedBitmap;
    }

    public interface GetSignature {
        public void getSignature(MakeWacomView makeWacomView, Bitmap bitmap);
    }
}

4.MakeWacomView

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

/**
 * @author Jay
 * @date 2021/3/9
 * File description.
 * 手绘板的核心代码
 */
public class MakeWacomView extends View {
    private static final float STROKE_WIDTH = 5f;
    private static final float HALF_STROKE_WIDTH = STROKE_WIDTH / 2;
    private Paint paint = new Paint();
    private Path path = new Path();

    private float lastTouchX;
    private float lastTouchY;
    private final RectF dirtyRect = new RectF();

    public MakeWacomView(Context context) {
        super(context);
        paint.setAntiAlias(true);
        paint.setColor(Color.RED);//设置画笔为红色
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeWidth(STROKE_WIDTH);
    }

    public void clear() {
        path.reset();
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawPath(path, paint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float eventX = event.getX();
        float eventY = event.getY();


        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                path.moveTo(eventX, eventY);
                lastTouchX = eventX;
                lastTouchY = eventY;
                return true;
            case MotionEvent.ACTION_MOVE:
            case MotionEvent.ACTION_UP:
                resetDirtyRect(eventX, eventY);
                int historySize = event.getHistorySize();
                for (int i = 0; i < historySize; i++) {
                    float historicalX = event.getHistoricalX(i);
                    float historicalY = event.getHistoricalY(i);
                    expandDirtyRect(historicalX, historicalY);
                    path.lineTo(historicalX, historicalY);
                }
                path.lineTo(eventX, eventY);
                break;

            default:
                Log.v("Ignored touch event: ", event.toString() + "");
                return false;
        }

        invalidate((int) (dirtyRect.left - HALF_STROKE_WIDTH),
                (int) (dirtyRect.top - HALF_STROKE_WIDTH),
                (int) (dirtyRect.right + HALF_STROKE_WIDTH),
                (int) (dirtyRect.bottom + HALF_STROKE_WIDTH));

        lastTouchX = eventX;
        lastTouchY = eventY;

        return true;
    }


    private void expandDirtyRect(float historicalX, float historicalY) {
        if (historicalX < dirtyRect.left) {
            dirtyRect.left = historicalX;
        } else if (historicalX > dirtyRect.right) {
            dirtyRect.right = historicalX;
        }

        if (historicalY < dirtyRect.top) {
            dirtyRect.top = historicalY;
        } else if (historicalY > dirtyRect.bottom) {
            dirtyRect.bottom = historicalY;
        }
    }

    private void resetDirtyRect(float eventX, float eventY) {
        dirtyRect.left = Math.min(lastTouchX, eventX);
        dirtyRect.right = Math.max(lastTouchX, eventX);
        dirtyRect.top = Math.min(lastTouchY, eventY);
        dirtyRect.bottom = Math.max(lastTouchY, eventY);
    }

    public void setSignature(Canvas signature) {
        signature.drawPath(path, paint);
    }

5.dialog_makewacom.xml

<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="horizontal">

        <Button
            android:id="@+id/btn_save_dmm"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:padding="10dp"
            android:text="保存" />

        <Button
            android:id="@+id/btn_cancel_dmm"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:padding="10dp"
            android:text="取消" />

        <Button
            android:id="@+id/btn_clear_dmm"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:padding="10dp"
            android:text="清空" />

        <Button
            android:id="@+id/btn_reset_dmm"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:padding="10dp"
            android:text="恢复" />
    </LinearLayout>
    <LinearLayout
        android:id="@+id/ll_wacom_dmm"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="vertical"
        />
</LinearLayout>

6.图片文件wacom.png

上面已经把所有的代码都贴出来了,当然,如果想要源码,地址在这里:https://download.csdn.net/download/u010802275/15681435

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐