【安卓开发】Android实现画板

简介: 【安卓开发】Android实现画板

普通画板

添加权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
package Draw;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import com.example.myapp_b.R;
public class CanvasActivity extends AppCompatActivity {
    private ImageView iv;
    private Bitmap bitmap;
    private Canvas canvas;
    private Paint paint;
    private float startX=0f;
    private float startY=0f;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_canvas);
        iv=findViewById(R.id.iv);
        bitmap=Bitmap.createBitmap(1000,1000,Bitmap.Config.ARGB_8888);
        paint=new Paint();
        canvas=new Canvas(bitmap);
        iv.setImageBitmap(bitmap);
        iv.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int action = event.getAction();
                switch (action){
                    case MotionEvent.ACTION_DOWN:
                        //按下时记录点击位置
                        startX = event.getX();
                        startY = event.getY();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        //移动时获取当前位置,并绘制直线
                        float endX = event.getX();
                        float endY = event.getY();
                        canvas.drawLine(startX,startY,endX,endY,paint);
                        iv.setImageBitmap(bitmap);
                        //将直线终点设置为下一次的起点
                        startX = endX;
                        startY = endY;
                        break;
                    case MotionEvent.ACTION_UP:
                        break;
                }
                return true;
            }
        });
    }
    public void setColor(View view) {
        paint.setColor(Color.RED);
    }
    public void setWidth(View view) {
        paint.setStrokeWidth(10);
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    tools:context="Draw.CanvasActivity">
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="设置画笔颜色"
        android:onClick="setColor"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="设置画笔宽度"
        android:onClick="setWidth"/>
    <ImageView
        android:background="@drawable/bg_border"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/iv"/>
</LinearLayout>

可以选择颜色、宽度、橡皮擦,可以保存文件到本地

添加权限

 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

file_path.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images" path="DRAW" />
</paths>
package Draw;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.icu.text.SimpleDateFormat;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import com.example.myapp_b.R;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.Date;
public class PaintActivity extends AppCompatActivity {
    private ImageView iv;
    private Bitmap bitmap;
    private Canvas canvas;
    private Paint paint;
    private float startX=0f;
    private float startY=0f;
    private Button bt_back,bt_sure;
    private ImageView res;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_paint);
        iv=findViewById(R.id.iv);
        res=findViewById(R.id.res);
        bt_back=findViewById(R.id.bt_back);
        bt_sure=findViewById(R.id.paint_sure);
        bitmap=Bitmap.createBitmap(1000,1000,Bitmap.Config.ARGB_8888);
        paint=new Paint();
        canvas=new Canvas(bitmap);
        iv.setImageBitmap(bitmap);
        iv.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int action = event.getAction();
                switch (action){
                    case MotionEvent.ACTION_DOWN:
                        //按下时记录点击位置
                        startX = event.getX();
                        startY = event.getY();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        //移动时获取当前位置,并绘制直线
                        float endX = event.getX();
                        float endY = event.getY();
                        canvas.drawLine(startX,startY,endX,endY,paint);
                        iv.setImageBitmap(bitmap);
                        //将直线终点设置为下一次的起点
                        startX = endX;
                        startY = endY;
                        break;
                    case MotionEvent.ACTION_UP:
                        break;
                }
                return true;
            }
        });
    }
    int id;
    public void setColor(View view) {
        //paint.setColor(Color.RED);
        id=0;
        final int [] col={Color.RED,Color.YELLOW,Color.GREEN,Color.BLUE,Color.WHITE,Color.BLACK};
        final String []s={"红色","黄色","绿色","蓝色","白色","黑色"};
        AlertDialog.Builder DanItem = new AlertDialog.Builder(PaintActivity.this);
        DanItem.setTitle("选择想要使用的颜色");
        DanItem.setSingleChoiceItems(s, -1, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                id =which;
            }
        });
        DanItem.setPositiveButton("确定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which){
                ShowMessage("恭喜你选择了"+s[id].toString());
                paint.setColor(col[id]);
            }
        });
        DanItem.create().show();
    }
    private void ShowMessage(String str) {
        Toast.makeText(PaintActivity.this, str, Toast.LENGTH_LONG).show();
    }
    public void setWidth(View view) {
        id=0;
        final int [] w={5,10,15,20,25,30,35,40};
        final String []s={"5","10","15","20","25","30"};
        AlertDialog.Builder DanItem = new AlertDialog.Builder(PaintActivity.this);
        DanItem.setTitle("选择想要使用的宽度");
        DanItem.setSingleChoiceItems(s, -1, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                id =which;
            }
        });
        DanItem.setPositiveButton("确定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which){
                ShowMessage("恭喜你选择了"+s[id]);
                paint.setStrokeWidth(w[id]);
            }
        });
        DanItem.create().show();
    }
    public void setErase(View view) {
        paint.setColor(Color.WHITE);
        paint.setStrokeWidth(30);
    }
    @RequiresApi(api = Build.VERSION_CODES.N)
    public void savePng(View view) throws FileNotFoundException {
        System.out.println(saveBitmap(bitmap));
    }
    @RequiresApi(api = Build.VERSION_CODES.N)
    public String saveBitmap(Bitmap bitmap) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
        Date curDate = new Date(System.currentTimeMillis());//获取当前时间
        String str = formatter.format(curDate);
        String paintPath = "";
        str = str + "paint.png";
        String imagePath = Environment.getExternalStorageDirectory()+"/DRAW";
        File file = new File(imagePath, str);
        try {
            FileOutputStream out = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
            //保存绘图文件路径
            paintPath =file.getAbsolutePath();
///  /storage/emulated/0/DRAW/20211202195458paint.png
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return paintPath;
    }
}
<?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="Draw.PaintActivity">
    <RelativeLayout
        android:layout_width="match_parent"
        android:orientation="horizontal"
        android:id="@+id/paint_sum"
        android:layout_height="wrap_content"
        tools:ignore="InvalidId">
        <Button
            android:id="@+id/paint_back"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="返回"
            android:textSize="30dp"></Button>
        <Button
            android:id="@+id/paint_sure"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:paddingLeft="40dp"
            android:onClick="savePng"
            android:text="确定"
            android:textSize="30dp"></Button>
    </RelativeLayout>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/paint_sum">
        <Button
            android:id="@+id/bnt_color"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="setColor"
            android:text="设置画笔颜色" />
        <Button
            android:id="@+id/bnt_width"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/bnt_color"
            android:onClick="setWidth"
            android:text="设置画笔宽度"
            tools:ignore="UnknownId" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/erase"
            android:text="橡皮擦"
            android:onClick="setErase"
            android:layout_toRightOf="@id/bnt_color"
            ></Button>
        <ImageView
            android:id="@+id/iv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/bnt_width" />
    </RelativeLayout>
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentBottom="true"
        android:id="@+id/res"
        ></ImageView>
</RelativeLayout>
目录
相关文章
|
13天前
|
前端开发 Java 编译器
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
70 36
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
|
3天前
|
JavaScript 搜索推荐 Android开发
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
22 8
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
|
2天前
|
数据采集 JavaScript Android开发
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
25 7
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
|
15天前
|
前端开发 Java Shell
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
115 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
12天前
|
Dart 前端开发 Android开发
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
36 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
28天前
|
缓存 前端开发 Android开发
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
79 12
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
|
1月前
|
Dart 前端开发 Android开发
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
36 1
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
|
9月前
|
存储 Java 开发工具
Android开发的技术与开发流程
Android开发的技术与开发流程
429 1
|
6月前
|
安全 Android开发 Swift
安卓与iOS开发:平台差异与技术选择
【8月更文挑战第26天】 在移动应用开发的广阔天地中,安卓和iOS两大平台各占一方。本文旨在探索这两个系统在开发过程中的不同之处,并分析开发者如何根据项目需求选择合适的技术栈。通过深入浅出的对比,我们将揭示各自平台的优势与挑战,帮助开发者做出更明智的决策。
103 5
|
6月前
|
移动开发 搜索推荐 Android开发
安卓与iOS开发:一场跨平台的技术角逐
在移动开发的广阔舞台上,两大主角——安卓和iOS,持续上演着激烈的技术角逐。本文将深入浅出地探讨这两个平台的开发环境、工具和未来趋势,旨在为开发者揭示跨平台开发的秘密,同时激发读者对技术进步的思考和对未来的期待。

热门文章

最新文章

  • 1
    如何修复 Android 和 Windows 不支持视频编解码器的问题?
  • 2
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 3
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
  • 4
    【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
  • 5
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
  • 6
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 7
    Android经典面试题之Kotlin中Lambda表达式和匿名函数的区别
  • 8
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 9
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
  • 10
    Android学习自定义View(四)——继承控件(滑动时ListView的Item出现删除按钮)