安卓自定义画板

这篇具有很好参考价值的文章主要介绍了安卓自定义画板。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

包含功能:

包含  获取当前画板的截图、设置画笔样式、获取画笔样式、设置画笔宽度、获取画笔宽度、设置画笔颜色、获取画笔颜色、加载图片、获取图片位图对象、设置图片位图对象,并在画布上绘制图片、撤销上一步操作、重做上一步撤销的操作、清空所有绘图路径,重新绘制位图

 自定义视图组件

package com.zx.drawing_board;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Stack;

public class DrawingBoard extends View {

    // 上下文对象,用于获取资源和应用程序信息
    public Context context;

    // 画布对象,用于绘制图形
    public Canvas canvas;

    // 画笔对象,用于设置绘制样式和颜色
    public Paint paint;

    // 位图对象,用于在其中进行绘制操作
    public Bitmap bitmap;

    // 绘制路径对象,记录用户绘制的路径
    public Path path;

    // 图片的URI地址
    public Uri uri;

    // 图片位图对象,用于加载图片
    private Bitmap mImageBitmap;

    // 保存用户绘制路径的栈结构
    private Stack<Path> paths = new Stack<>();

    /**
     * 构造函数,创建一个新的FingerPainterView对象
     * @param context 上下文对象,用于获取资源和应用程序信息
     */
    public DrawingBoard(Context context) {
        super(context);
        // 执行初始化方法
        init(context);
    }

    /**
     * 构造函数,创建一个新的FingerPainterView对象
     * @param context 上下文对象,用于获取资源和应用程序信息
     * @param attrs 属性集合对象,用于获取视图的自定义属性
     */
    public DrawingBoard(Context context, AttributeSet attrs) {
        super(context, attrs);

        // 执行初始化方法
        init(context);
    }

    /**
     * 构造函数,创建一个新的FingerPainterView对象
     * @param context 上下文对象,用于获取资源和应用程序信息
     * @param attrs 属性集合对象,用于获取视图的自定义属性
     * @param defStyle 样式属性,用于设置默认样式
     */
    public DrawingBoard(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // 执行初始化方法
        init(context);
    }
    /**
     * 获取当前画板的截图
     * @return 画板的截图
     */
    public Bitmap getScreenshot() {
        return Bitmap.createBitmap(bitmap);
    }
    /**
     * 初始化方法,设置默认的画笔样式和颜色
     * @param context 上下文对象,用于获取资源和应用程序信息
     */
    private void init(Context context) {
        this.context = context;

        // 创建路径对象和画笔对象
        path = new Path();
        paint = new Paint();

        // 默认的画笔样式和颜色
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeWidth(20);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setARGB(255,0,0,0);
    }

    /**
     * 设置画笔样式
     * @param brush 画笔样式
     */
    public void setBrush(Paint.Cap brush) {
        paint.setStrokeCap(brush);
    }

    /**
     * 获取画笔样式
     * @return 画笔样式
     */
    public Paint.Cap getBrush() {
        return paint.getStrokeCap();
    }

    /**
     * 设置画笔宽度
     * @param width 画笔宽度
     */
    public void setBrushWidth(int width) {
        paint.setStrokeWidth(width);
    }

    /**
     * 获取画笔宽度
     * @return 画笔宽度
     */
    public int getBrushWidth() {
        return (int) paint.getStrokeWidth();
    }

    /**
     * 设置画笔颜色
     * @param colour 画笔颜色
     */
    public void setColour(int colour) {
        paint.setColor(colour);
    }

    /**
     * 获取画笔颜色
     * @return 画笔颜色
     */
    public int getColour() {
        return paint.getColor();
    }

    /**
     * 加载图片
     * @param uri 图片的URI地址
     */
    public void load(Uri uri) {
        this.uri = uri;
    }

    /**
     * 获取图片位图对象
     * @return 图片位图对象
     */
    public Bitmap getmImageBitmap() {
        return mImageBitmap;
    }

    /**
     * 设置图片位图对象,并在画布上绘制图片
     * @param mImageBitmap 图片位图对象
     */
    public void setmImageBitmap(Bitmap mImageBitmap) {
        this.mImageBitmap = mImageBitmap;
        canvas.drawColor(Color.WHITE);
        canvas.drawBitmap(mImageBitmap, 0, 0, paint);
    }


    /**
     * 撤销上一步操作
     */
    public void undo() {
        if (!paths.isEmpty()) {
            // 移除最近的路径,并重新绘制位图
            paths.pop();
            redrawBitmap();
        }
    }

    /**
     * 重做上一步撤销的操作
     */
    public void redo() {
        if (!paths.isEmpty()) {
            // 将最近撤销的路径重新添加到绘图路径中,并重新绘制位图
            Path lastPath = paths.peek();
            paths.push(new Path(lastPath));
            redrawBitmap();
        }
    }

    /**
     * 清空所有绘图路径,重新绘制位图
     */
    public void clear() {
        paths.clear();
        redrawBitmap();
    }
    @Override
    public Parcelable onSaveInstanceState() {
        Bundle bundle = new Bundle();
        // 保存父类视图状态
        bundle.putParcelable("superState", super.onSaveInstanceState());

        try {
            // 将位图保存到临时缓存文件中,以克服Binder事务大小限制
            File f = File.createTempFile("fingerpaint", ".png", context.getCacheDir());
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, new FileOutputStream(f));
            // 将临时文件名保存到bundle中
            bundle.putString("tempfile", f.getAbsolutePath());
        } catch(IOException e) {
            Log.e("FingerPainterView", e.toString());
        }
        return bundle;
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        if (state instanceof Bundle) {
            Bundle bundle = (Bundle) state;

            try {
                // 从bundle中获取缓存文件
                File f = new File(bundle.getString("tempfile"));
                Bitmap b = BitmapFactory.decodeStream(new FileInputStream(f));
                // 需要复制位图以创建可变版本
                bitmap = b.copy(b.getConfig(), true);
                b.recycle();
                f.delete();
            } catch(IOException e) {
                Log.e("FingerPainterView", e.toString());
            }

            state = bundle.getParcelable("superState");
        }
        super.onRestoreInstanceState(state);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // 画布是白色的,并在顶部绘制带有alpha通道的位图
        canvas.drawColor(Color.WHITE);
        canvas.drawBitmap(bitmap, 0, 0, paint);
        // 显示当前的绘图路径
        for (Path p : paths) {
            canvas.drawPath(p, paint);
        }
        canvas.drawPath(path, paint);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        // 在Activity创建后,当视图被膨胀时调用
        if(bitmap==null) {
            if(uri!=null) {
                try {
                    // 尝试加载提供的uri,并进行缩放以适应我们的画布
                    InputStream stream = context.getContentResolver().openInputStream(uri);
                    Bitmap bm = BitmapFactory.decodeStream(stream);
                    bitmap  = Bitmap.createScaledBitmap(bm, Math.max(w, h), Math.max(w, h), false);
                    stream.close();
                    bm.recycle();
                } catch(IOException e) {
                    Log.e("FingerPainterView", e.toString());
                }
            }
            else {
                // 创建一个正方形位图,以便即使在旋转到横向时也可绘制
                bitmap = Bitmap.createBitmap(Math.max(w,h), Math.max(w,h), Bitmap.Config.ARGB_8888);
            }
        }
        canvas = new Canvas(bitmap);
    }

    /**
     * 触摸事件处理方法,用于绘制路径
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 按下手指时,重置路径并移动到指定位置
                path.reset();
                path.moveTo(x, y);
                path.lineTo(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:
                // 手指移动时,连线到当前位置
                path.lineTo(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                // 手指抬起时,将路径保存,并重置路径
                paths.push(new Path(path));
                path.reset();
                invalidate();
                break;
        }
        return true;
    }

    /**
     * 重新绘制位图,根据当前的绘图路径
     */
    private void redrawBitmap() {
        bitmap.eraseColor(Color.WHITE);
        for (Path p : paths) {
            canvas.drawPath(p, paint);
        }
        invalidate();
    }
}

用法

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.zx.drawing_board.DrawingBoard
        android:id="@+id/fp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

效果

安卓自定义画板,android文章来源地址https://www.toymoban.com/news/detail-828103.html

到了这里,关于安卓自定义画板的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity 实现简单画板画画功能(笔记)

    创建一个plan 摄像机调成正交摄像机 创建三个cube,附上材质 再创建一个cube,找个色板, 创建一个脚本,挂在非失活物体上 创建一个slider,放在旁边 Unity 画板

    2024年02月15日
    浏览(38)
  • 安卓学习笔记:安卓11访问/读写 Android/data 目录

    省流提示:采用android studio工具开发,记录一次低级的开发,避免以后忘记或者踩坑。 最近有个业余项目开发到一小半,过程中需要读写 Android/data目录的文件,采用常规的文件操作总是提示权限被拒绝,无奈上网参考了很多资料,终于得到了解决。 无法访问Android/data 的原因

    2024年02月13日
    浏览(45)
  • Flutter笔记:手写一个简单的画板工具

    Flutter笔记 手写一个简单的画板工具 作者 : 李俊才 (jcLee95):https://blog.csdn.net/qq_28550263 邮箱 : 291148484@163.com 本文地址 :https://blog.csdn.net/qq_28550263/article/details/133418742 在本文中,我们将一起开发一个基本的Flutter画板应用,用户可以在画板上自由绘制,选择不同的颜色来绘

    2024年02月07日
    浏览(35)
  • [Android Studio] 导入安卓Android项目教程

    A项目指:要导入的项目;B项目指自己电脑上可以运行的项目 根据步骤一步一步来,别急。 将要导入的项目(简称为A)根目录下的这些文件删掉:.gradle、.idea 、.iml后缀的文件、 local.properties 进入app文件夹,将这些文件删掉:build、.iml后缀的文件 打开一个你在自己电脑上可

    2024年02月04日
    浏览(46)
  • 安卓Android开发快速入门

    配合天哥视频食用更佳:【天哥】Android开发视频教程最新版 Android Studio开发 LinearLayout(线性布局) 可嵌套 最常用属性 id 起标记布局的作用 layout_width [wrap_content根据内容选择大小、match_parent匹配父级、具体数值(单位-dp)] layout_height layout_weight 权重,按照权重比例分配父级

    2023年04月16日
    浏览(44)
  • 安卓android记单词软件

    课程设计项目总结,基于安卓的记单词软件,分为前端和服务器端,前端使用安卓,后端使用SSM框架。 具体技术栈为: 前端:android、okhttp、sqlite、litepal等 后端:SSM(SpringMVC+Spring+Mybatis)、mysql数据库、tomcat服务器等 项目的总体介绍 基于安卓的记单词软件,用户在第一次使用的时

    2024年02月05日
    浏览(36)
  • 【电子学会】2023年03月图形化二级 -- 电子画板

    (1)删除默认的小猫角色,保留默认白色背景; (2)从角色库添加Arrow1角色作为画笔; (3)绘制五个角色:颜色分别为红、黄、绿、蓝、紫的圆形; (4)将Arrow1角色的第一个造型修改为下图所示状态,箭头尖端在角色中心位置。 (1)点击绿旗,Arrow1跟随鼠标指针移动;

    2024年02月07日
    浏览(44)
  • 【Qt 一个简易画板的实现(Graphics View)】

    Qt专栏 Qt 学习之路(32): 一个简易画板的实现(Graphics View) 这一次将介绍如何使用 Graphics View 来实现前面所说的画板。前面说了很多有关 Graphics View的好话,但是没有具体的实例很难说究竟好在哪里。现在我们就把前面的内容使用 Graphics View 重新实现一下,大家可以对比一下看有

    2024年02月16日
    浏览(47)
  • 【android】安卓大作业「课程日历」

    项目: 课程日历 -项目概况: 项目记录一周的课程信息。 •用户可以编辑周一~周五的课程表( 每天最多安排5门课程 ) ; •用户可以按日查看课程表。 -项目要求: •项目包含2个活动及其对应的布局: ① 显示课程活动:单击“周一”~“周五”按钮中的一个,按时间顺

    2024年02月04日
    浏览(42)
  • 安卓进阶之android系统架构

    安卓进阶躲不开阅读源码和深入了解安卓的底层,这是一篇入门级别的文章,可以对安卓架构有个大体的认识。 首先要理解andriod和AOSP的关系,我们日常开发的安卓跟市面上的安卓不是一个意思,我们开发的是安卓app,市面上的安卓其实是安卓系统。 维基百科: Android 是基于

    2023年04月12日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包