Android中对图片的操作,移动、缩放、涂鸦和保存到图库

news2024/12/24 0:00:00

一、实现方法

监听用户手势,提取用户操作
(1)移动: 分别计算X,Y轴的结束与初始之间移动偏移的量
(2)缩放:(结束两指间距离×伸缩比例)/ 初始两指间距离,scaleX,scaleY放大多少倍
(3)涂鸦:重写onDraw()方法,画布(canvas)结合画笔(Paint)构造Path实现,监听手势起始点坐标与结束坐标,使用path类的quadTo()方法绘制曲线
(4)保存:保存图片Insert到MediaStore.Images.Media下面,广播通知系统相册图库刷新数据

二、demo

在这里插入图片描述

1、移动缩放

通过 Matrix 矩阵 方式操作图片

    private static final int NONE = 0;
    private static final int DRAG = 1; //一个手指
    private static final int ZOOM = 2; //两个手指
    private int mode = NONE;

    private Matrix matrix = new Matrix();  //移动的矩阵
    private Matrix saveMatrix = new Matrix();
    private PointF startPoint = new PointF(); //第一个按下手指的点
    private PointF midPoint = new PointF();  // 两个按下手指触摸点的中点
    private float distance = 1f; //两个手指触摸点之间的距离

ImageView图片控件的监听

        imageView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View view) {
                return true;
            }
        });
        imageView.setOnTouchListener((view, motionEvent) -> {
            ImageView imageView = (ImageView) view;
            imageView.setScaleType(ImageView.ScaleType.MATRIX);  //注意:操作之前需设置ScaleType为matrix
//            final int x = (int) motionEvent.getRawX();  //触摸点到屏幕左边的距离
//            final int y = (int) motionEvent.getRawY();  //触摸点到屏幕上边的距离
//            Log.i(TAG,"触摸点离屏幕左边的距离:"+ x +"屏幕上方的距离:"+ y);
            switch (motionEvent.getAction() & MotionEvent.ACTION_MASK){
                case MotionEvent.ACTION_DOWN:
                    Log.i(TAG,"单点按下");
                    //单点按下
                    mode = DRAG;
                    //设置要操作的矩阵为该图片的图片矩阵
                    matrix.set(imageView.getImageMatrix());
                    saveMatrix.set(matrix);
                    startPoint.set(motionEvent.getX(),motionEvent.getY());
                    break;
                case MotionEvent.ACTION_POINTER_DOWN:
                    //多点按下
                    Log.i(TAG,"多点按下");
                    //计算两指间距离
                    distance = distance(motionEvent);
                    if (distance > 10f){
                        saveMatrix.set(matrix);
                        //计算两指间中点的坐标
                        midPoint = midPoint(motionEvent);
                        mode = ZOOM;
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    //手指滑动
                    if (mode == DRAG){
                        Log.i(TAG,"移动");
                        //获取当前图片矩阵
                        matrix.set(saveMatrix);
                        //分别在x、y轴上将图片矩阵移动相应的距离
                        matrix.postTranslate(motionEvent.getX() - startPoint.x,motionEvent.getY() - startPoint.y);
                    }else if(mode == ZOOM){
                        Log.i(TAG,"缩放");
                        float newDistance = distance(motionEvent);
                        if (newDistance > 10f){
                            //获取当前图片矩阵
                            matrix.set(saveMatrix);
                            //放大或缩小的倍数(缩放后手指间的距离/缩放前手指间的距离)
                            float scale = newDistance/distance;
                            //以两指中点为中心将当前图片矩阵放大或缩小scale倍
                            matrix.postScale(scale,scale,midPoint.x,midPoint.y);
                        }
                    }
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_POINTER_UP:
                    //手指抬起
                    mode = NONE;
                    break;
                default:
                    break;
            }
            //将操作后的图片矩阵赋值给imageView
            imageView.setImageMatrix(matrix);
            return true;
        });

计算两指间距离

    private float distance(MotionEvent motionEvent){
        float dx = motionEvent.getX(0) - motionEvent.getX(1);
        float dy = motionEvent.getY(0) - motionEvent.getY(1);
        return (float) Math.sqrt(dx * dx + dy * dy);
    }

计算两指间中点的坐标

    private PointF midPoint(MotionEvent motionEvent){
        float midx = (motionEvent.getX(0) + motionEvent.getX(1)) / 2;
        float midy = (motionEvent.getY(0) + motionEvent.getY(1)) / 2;
        return new PointF(midx,midy);
    }

控件布局,注意根据情况设置scaleType

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="500dp"
        android:paddingStart="10dp"
        android:paddingEnd="10dp"
        android:scaleType="fitCenter"
        android:src="@drawable/bbb"
        app:layout_constraintBottom_toTopOf="@+id/tv_start"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/state" />

2、涂鸦

持续更新中

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/193035.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

云计算|OpenStack|社区版OpenStack安装部署文档(五 --- 计算服务nova安装部署---Rocky版)

前言&#xff1a; nova服务是openstack最重要的一个组件&#xff0c;没有之一&#xff0c;该组件是云计算的计算核心&#xff0c;大体组件如下&#xff1a; OpenStack Docs: Compute service overview 挑些重点&#xff0c;nova-api&#xff0c;libvirt&#xff0c;nova-pla…

最小生成树与最短路径

目录 一.最小生成树 1.1概念 1.2Kruskal算法 1.3Prim算法 二.最短路径 2.11单源最短路径--Dijkstra算法 2.1.2单源最短路径--Bellman-Ford算法 一.最小生成树 1.1概念 连通图中的每一棵生成树&#xff0c;都是原图的一个极大无环子图&#xff0c;即&#xff1a;从其中删去…

虹科分享|论企业网络安全的重要性

拥有有效的企业网络安全不仅仅是让你的员工创建一个不是他们宠物名字的密码--除非他们的猫的名字至少有12个字符长&#xff0c;由大小写字母和符号组成。无论是经过充分研究的鱼叉式钓鱼尝试&#xff0c;还是绕过MFA&#xff0c;威胁者都变得更加大胆。随着全球各行业数据泄露事…

判断是否为平衡树

对二叉树有困惑的小伙伴可以看一下我之前的文章&#xff1a;二叉树&#xff08;一&#xff09;_染柒_GRQ的博客-CSDN博客二叉树&#xff08;二&#xff09;_染柒_GRQ的博客-CSDN博客二叉树&#xff08;三&#xff09;_染柒_GRQ的博客-CSDN博客点击上方链接即可查看。题目110. 平…

Ext2explore查看ext2/ext3/ext4 file

比如想查看Android system.img&#xff0c;file看起来是ext2文件&#xff0c;file system.img system.img: Linux rev 1.0 ext2 filesystem data, UUID49e89c77-3dc4-553f-a392-7d11ff348228 (extents) (large files) (huge files)2、windows下怎么看呢&#xff0c;Ext2explore…

Springboot——常用注解及实例

一、常用注解解释&#xff1a;ConfigurationBeanResourceSpringBootApplicationRestControllerRestController 注解包含了原来的 Controller 和 ResponseBody 注解&#xff0c;使用过 Spring 的朋友对 Controller 注解已经非常了解了&#xff0c;这里不再赘述&#xff0c; Resp…

【BSV应用范例】区块链上的自我主权身份

发表时间&#xff1a;2022年6月27日 信息来源&#xff1a;bsvblockchain.org 自我主权身份&#xff08;SSI&#xff09;只是一个空想吗&#xff1f; &#xff08;全球区块链组织联合创始人&#xff09;Jorge Sebastio对此表示&#xff1a;“并非如此&#xff01;” 更重要的是…

OS 学习笔记(7) 虚拟机

OS 学习笔记(7) 虚拟机 这篇笔记对应的王道OS 1.6 虚拟机&#xff0c;同时参考了 《Operating System Concepts, Ninth Edition》和 俗称ostep的《 Operating Systems: Three Easy Pieces》还有 《Operating Systems: Principles and Practice》 文章目录OS 学习笔记(7) 虚拟机…

软件测试之Android单元测试

根据维基百科的解释&#xff0c;单元测试又称为模块测试。是针对程序单元来进行正确性校验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中&#xff0c;一个单元就是单个程序&#xff0c;函数&#xff0c;过程等&#xff0c;对于面向对象编程&#xff0c;最小单元…

STL——string类

一、标准库中的string类 1.string类文档介绍 &#xff08;1&#xff09;字符串是表示字符序列的类。 &#xff08;2&#xff09;标准的字符串类提供了对此类对象的支持&#xff0c;其接口类似于标准字符容器的接口&#xff0c;但添加了专门用于操作单字节字符字符串的设计特…

IOS逆向--恢复Dyld的内存加载方式

之前我们一直在使用由dyld及其NSCreateObjectFileImageFromMemory/NSLinkModule API方法所提供的Mach-O捆绑包的内存加载方式。虽然这些方法我们今天仍然还在使用&#xff0c;但是这个工具较以往有一个很大的区别…现在很多模块都被持久化到了硬盘上。 roguesys 在 2022 年 2 …

还在用 OpenFeign?来试试 SpringBoot3 中的这个新玩意!

好久没发技术文章了&#xff0c;最近回到工作地&#xff0c;晚上有空又可以码码技术了&#xff0c;今天我们就来聊一个 Spring Boot3 中的新鲜玩意&#xff0c;声明式 HTTP 调用。 1. 由来 Spring Boot3 去年底就已经正式发布&#xff0c;我也尝了一把鲜&#xff0c;最近有空…

(02)Cartographer源码无死角解析-(53) 2D后端优化→位姿图优化理论(SPA)讲解、核型函数调用流程

讲解关于slam一系列文章汇总链接:史上最全slam从零开始&#xff0c;针对于本栏目讲解(02)Cartographer源码无死角解析-链接如下: (02)Cartographer源码无死角解析- (00)目录_最新无死角讲解&#xff1a;https://blog.csdn.net/weixin_43013761/article/details/127350885 文末…

Docker镜像部署至Rancher全局配置 以xxl-job-admin为例

流程以xxl-job-admin为例 1.基础环境 win/mac/linuxRancherDocker 2.下载源码 从Github上下载xxl-job xxl-jobGithub xxl-job官方地址 3.修改源码 打开 xxl-job 下的 xxl-job-admin 修改 application-properties 文件 修改数据库 修改为这种格式&#xff1a; 大括号包…

MPLS实验

目录实验要求mpls简介mpls工作过程实验的配置环回的配置R1和R5之间公网的ospf配置配置mpls-ldp配置R1和R5间的mplsvpn私网的rip及ospf的宣告配置公网mp-bgp的建立R2和R4上面的双向重发布R7和R8之间创建R7和R8间的mplsvpn配置静态路由及环回重发布实验要求 如图 要求&#xff1…

【C++修炼之路】15.C++继承

每一个不曾起舞的日子都是对生命的辜负 继承C继承一. 继承的概念及定义1.1 继承的引出1.2 继承的概念1.3 继承的定义二.基类和派生类对象赋值转换三.继承中的作用域3.1 作用域的概念3.2 举例说明同名冲突四.派生类的默认成员函数4.1 派生类的构造函数4.2 派生类的拷贝构造函数4…

【python学习笔记】:数据科学库操作(二)

接上一篇&#xff1a; 4、PIL Python Imaging Library(PIL) 已经成为 Python 事实上的图像处理标准库了&#xff0c;这是由于&#xff0c;PIL 功能非常强大&#xff0c;但API却非常简单易用。但是由于PIL仅支持到 Python 2.7&#xff0c;再加上年久失修&#xff0c;于是一群志…

如果写不好 SQL,有没有好用的报表软件?

业务和技术在做报表这件事情上&#xff0c;究竟有多大差别&#xff1f; 一家企业、一个组织&#xff0c;只要一直在经营和运作&#xff0c;因为税务和其他原因就需要通过数据报表来反映当期的经营管理状况。而“做报表”这个事情&#xff0c;在企业内部不管是业务人员还是技术人…

HTTP之Referrer和Referrer-policy

目录 HTTP之Referrer和Referrer-policy Referer Referrer-policy 如何设置referrer 盗链 防盗链的工作原理 绕过图片防盗链 利用https网站盗链http资源网站&#xff0c;refer不会发送 设置meta 设置referrerpolicy"no-referrer" 利用iframe伪造请求refe…

C语言指针变量的运算

指针变量保存的是地址&#xff0c;而地址本质上是一个整数&#xff0c;所以指针变量可以进行部分运算&#xff0c;例如加法、减法、比较等&#xff0c;请看下面的代码&#xff1a;#include<stdio.h>intmain(){ int a 10,*pa &a,*paa &a; double b 99.9,*pb &a…