44人参与 • 2025-02-13 • Android
本文将介绍如何构建一个支持图片选择、裁剪(包括手动缩放和旋转)、以及保存到自定义路径的android应用demo。
首先,在androidmanifest.xml
中添加必要的权限:
<uses-permission android:name="android.permission.read_external_storage" /> <uses-permission android:name="android.permission.write_external_storage" />
对于 android 6.0 (api level 23) 及以上版本,需要在运行时请求权限。
创建一个简单的布局文件activity_main.xml
,包含一个用于显示图片的customcropimageview
,以及几个按钮用于控制裁剪操作。
<?xml version="1.0" encoding="utf-8"?> <relativelayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <com.example.customcropimageview android:id="@+id/customcropimageview" android:layout_width="match_parent" android:layout_height="wrap_content" /> <button android:id="@+id/buttonpickimage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="pick image" android:layout_below="@id/customcropimageview" /> <button android:id="@+id/buttoncrop" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="crop" android:layout_toendof="@id/buttonpickimage" android:layout_below="@id/customcropimageview" /> <button android:id="@+id/buttoncancel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="cancel" android:layout_toendof="@id/buttoncrop" android:layout_below="@id/customcropimageview" /> <button android:id="@+id/buttonsave" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="save" android:layout_toendof="@id/buttoncancel" android:layout_below="@id/customcropimageview" /> </relativelayout>
接下来,我们将详细实现customcropimageview
,这个自定义视图负责所有与裁剪相关的交互逻辑。
```java import android.content.context; import android.graphics.bitmap; import android.graphics.canvas; import android.graphics.color; import android.graphics.matrix; import android.graphics.paint; import android.graphics.path; import android.graphics.porterduff; import android.graphics.porterduffxfermode; import android.graphics.rectf; import android.util.attributeset; import android.view.gesturedetector; import android.view.motionevent; import android.view.scalegesturedetector; import android.widget.framelayout; public class customcropimageview extends framelayout { // 成员变量定义 private bitmap mbitmap; // 要裁剪的图片 private matrix mmatrix = new matrix(); // 用于变换(缩放、旋转)图像的矩阵 private rectf mrect = new rectf(); // 定义裁剪框的位置和大小 private float[] mlasttouchpos = new float[2]; // 上次触摸位置,用于计算移动距离 private float[] mcurrentpos = new float[2]; // 当前触摸位置,用于更新图像位置 private float mrotation = 0f; // 图像的旋转角度 private boolean misdragging = false; // 标记是否正在拖动图像 private scalegesturedetector mscaledetector; // 检测多点触控缩放手势 private gesturedetector mgesturedetector; // 检测单点触控手势(如点击) // 构造函数,初始化自定义视图 public customcropimageview(context context, attributeset attrs) { super(context, attrs); // 初始化手势检测器 mscaledetector = new scalegesturedetector(context, new scalelistener()); mgesturedetector = new gesturedetector(context, new gesturelistener()); } @override protected void ondraw(canvas canvas) { super.ondraw(canvas); if (mbitmap != null) { // 绘制背景蒙层,使非裁剪区域变暗 drawoverlay(canvas); // 保存当前canvas状态,以便稍后恢复 canvas.save(); // 将canvas原点移动到裁剪框中心,进行旋转操作 canvas.translate(mrect.centerx(), mrect.centery()); canvas.rotate(mrotation); // 移回原点以绘制旋转后的图像 canvas.translate(-mrect.centerx(), -mrect.centery()); // 使用变换矩阵绘制图像 canvas.drawbitmap(mbitmap, mmatrix, null); // 恢复canvas到之前的状态 canvas.restore(); // 绘制裁剪框,让用户知道哪里会被裁剪 drawcropbox(canvas); } } private void drawoverlay(canvas canvas) { paint paint = new paint(); // 设置半透明黑色作为蒙层颜色 paint.setcolor(color.argb(128, 0, 0, 0)); // 填充整个视图为半透明黑色 canvas.drawrect(0, 0, getwidth(), getheight(), paint); // 创建一个路径,添加裁剪框形状 path path = new path(); path.addrect(mrect, path.direction.cw); // 使用canvas.clippath剪切出裁剪框区域,使其透明 // 注意:region.op.difference在api 26以上已被弃用,应考虑使用其他方式实现相同效果 canvas.clippath(path, region.op.difference); canvas.drawcolor(color.transparent, porterduff.mode.clear); } private void drawcropbox(canvas canvas) { paint paint = new paint(paint.anti_alias_flag); // 抗锯齿 paint.setstyle(paint.style.stroke); // 只绘制边框,不填充内部 paint.setstrokewidth(5); // 边框宽度 paint.setcolor(color.blue); // 裁剪框颜色设置为蓝色 // 绘制裁剪框矩形 canvas.drawrect(mrect, paint); } @override public boolean ontouchevent(motionevent event) { // 分别将事件传递给缩放和手势检测器 mscaledetector.ontouchevent(event); mgesturedetector.ontouchevent(event); switch (event.getaction()) { case motionevent.action_down: // 记录按下时的坐标,开始拖动 mlasttouchpos[0] = event.getx(); mlasttouchpos[1] = event.gety(); misdragging = true; break; case motionevent.action_move: if (misdragging) { // 更新当前位置,并根据位移调整矩阵和平移裁剪框 mcurrentpos[0] = event.getx(); mcurrentpos[1] = event.gety(); updatematrix(); invalidate(); // 请求重新绘制界面 } break; case motionevent.action_up: // 结束拖动 misdragging = false; break; } return true; } private void updatematrix() { // 更新矩阵以反映图像的新位置 mmatrix.settranslate(mcurrentpos[0] - mlasttouchpos[0], mcurrentpos[1] - mlasttouchpos[1]); // 同步裁剪框的位置 mrect.offset(mcurrentpos[0] - mlasttouchpos[0], mcurrentpos[1] - mlasttouchpos[1]); } private class scalelistener extends scalegesturedetector.simpleonscalegesturelistener { @override public boolean onscale(scalegesturedetector detector) { // 获取缩放因子并应用到矩阵上,保持缩放中心点不变 float scalefactor = detector.getscalefactor(); mmatrix.postscale(scalefactor, scalefactor, detector.getfocusx(), detector.getfocusy()); invalidate(); // 请求重绘以反映变化 return true; } } private class gesturelistener extends gesturedetector.simpleongesturelistener { @override public boolean ondoubletap(motionevent e) { // 双击时重置所有变换 resettransformations(); return true; } } private void resettransformations() { // 重置矩阵和旋转角度,以及裁剪框位置 mmatrix.reset(); mrotation = 0f; mrect.set(/* default values */); invalidate(); // 请求重绘 } // 设置要裁剪的图片 public void setimagebitmap(bitmap bitmap) { mbitmap = bitmap; // 根据新图片尺寸调整裁剪框大小 updatecropboxsize(); requestlayout(); // 请求布局更新 invalidate(); // 请求重绘 } private void updatecropboxsize() { // 根据所选图片的尺寸设置合适的裁剪框大小 int width = mbitmap.getwidth(); int height = mbitmap.getheight(); float aspectratio = (float) width / height; // 设定裁剪框的初始尺寸为图片的中心区域,同时确保其宽高比与原始图片一致 float rectwidth = math.min(getwidth(), getheight() * aspectratio); float rectheight = math.min(getheight(), getwidth() / aspectratio); mrect.set((getwidth() - rectwidth) / 2, (getheight() - rectheight) / 2, (getwidth() + rectwidth) / 2, (getheight() + rectheight) / 2); } // 获取裁剪后的图片 public bitmap getcroppedbitmap() { // 创建一个新的位图来容纳裁剪结果 bitmap croppedbitmap = bitmap.createbitmap( (int)mrect.width(), (int)mrect.height(), bitmap.config.argb_8888 ); canvas canvas = new canvas(croppedbitmap); // 平移画布以对齐裁剪框左上角 canvas.translate(-mrect.left, -mrect.top); // 绘制变换后的原始图片到新的位图中 canvas.drawbitmap(mbitmap, mmatrix, null); return croppedbitmap; } }
自定义的customcropimageview
,它允许用户通过触摸屏交互来裁剪图片。该视图支持基本的手势操作,包括拖动、缩放和双击重置。此外,还提供了设置图片和获取裁剪后图片的方法。
现在我们将更新mainactivity.java
,以加载图片到自定义视图,并处理裁剪后的保存逻辑。
import android.manifest; import android.content.intent; import android.content.pm.packagemanager; import android.graphics.bitmap; import android.net.uri; import android.os.bundle; import android.provider.mediastore; import androidx.annotation.nonnull; import androidx.annotation.nullable; import androidx.appcompat.app.appcompatactivity; import androidx.core.app.activitycompat; import androidx.core.content.contextcompat; import java.io.file; import java.io.fileoutputstream; import java.io.ioexception; public class mainactivity extends appcompatactivity { private static final int pick_image_request = 1; private static final int request_permissions = 2; private customcropimageview customcropimageview; private uri imageuri; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); customcropimageview = findviewbyid(r.id.customcropimageview); // 检查并请求存储权限 if (contextcompat.checkselfpermission(this, manifest.permission.write_external_storage) != packagemanager.permission_granted) { activitycompat.requestpermissions(this, new string[]{manifest.permission.read_external_storage, manifest.permission.write_external_storage}, request_permissions); } findviewbyid(r.id.buttonpickimage).setonclicklistener(v -> pickimage()); findviewbyid(r.id.buttoncrop).setonclicklistener(v -> cropimage()); findviewbyid(r.id.buttoncancel).setonclicklistener(v -> cancelcrop()); findviewbyid(r.id.buttonsave).setonclicklistener(v -> saveimage()); } private void pickimage() { intent intent = new intent(intent.action_get_content); intent.settype("image/*"); startactivityforresult(intent, pick_image_request); } private void cropimage() { // 如果使用第三方库如ucrop,可以在这里启动裁剪活动 // 这里我们假设customcropimageview已经包含了所有裁剪功能 // 因此不需要启动新的活动。 } private void cancelcrop() { // 重置customcropimageview的状态 customcropimageview.resettransformations(); } private void saveimage() { bitmap bitmap = customcropimageview.getcroppedbitmap(); // 获取裁剪后的位图 try { file path = new file(getexternalfilesdir(null), "custom_folder"); if (!path.exists()) { path.mkdirs(); } file file = new file(path, "cropped_image.jpg"); fileoutputstream out = new fileoutputstream(file); bitmap.compress(bitmap.compressformat.jpeg, 90, out); out.flush(); out.close(); // 提示用户图片已保存 } catch (ioexception e) { e.printstacktrace(); // 处理保存失败的情况 } } @override protected void onactivityresult(int requestcode, int resultcode, @nullable intent data) { super.onactivityresult(requestcode, resultcode, data); if (requestcode == pick_image_request && resultcode == result_ok && data != null && data.getdata() != null) { imageuri = data.getdata(); try { // 将选择的图片加载到customcropimageview中 bitmap bitmap = mediastore.images.media.getbitmap(getcontentresolver(), imageuri); customcropimageview.setimagebitmap(bitmap); } catch (ioexception e) { e.printstacktrace(); } } } @override public void onrequestpermissionsresult(int requestcode, @nonnull string[] permissions, @nonnull int[] grantresults) { super.onrequestpermissionsresult(requestcode, permissions, grantresults); if (requestcode == request_permissions) { if (grantresults.length > 0 && grantresults[0] == packagemanager.permission_granted) { // 权限授予成功,可以继续进行图片选择等操作 } else { // 用户拒绝了权限,需要提示用户或者禁用相关功能 } } } }
通过上述步骤,我们完成了一个具有裁剪功能的android demo。该应用允许用户从相册或相机选择图片,在界面上进行裁剪、旋转和缩放,并最终将处理过的图片保存到指定位置。
以上就是android实现图片裁剪处理的操作步骤的详细内容,更多关于android图片裁剪处理的资料请关注代码网其它相关文章!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论