实战指南:相机拍照 + 相册选取 + 图片裁剪全流程)
移动开发UI组件【免费下载链接】AndroidPicker安卓选择器类库包括日期及时间选择器可用于出生日期、营业时间等、单项选择器可用于性别、民族、职业、学历、星座等、二三级联动选择器可用于车牌号、基金定投日期等、城市地址选择器分省级、地市级及区县级、数字选择器可用于年龄、身高、体重、温度等、日历选日期择器可用于酒店及机票预定日期、颜色选择器、文件及目录选择器、图片选择器等……WheelPicker/DatePicker/TimePicker/OptionPicker/NumberPicker/LinkagePicker/AddressPicker/CarPlatePicker/CalendarPicker/ColorPicker/FilePicker/ImagePicker etc.项目地址https://gitcode.com/gh_mirrors/an/AndroidPicker点击查看免费下载本篇技术指南围绕 AndroidPicker 项目中的 ImagePicker 模块 展开讲解如何通过ImagePicker单例快速完成「相机拍照」「相册选取」与「图片裁剪」三合一流程包括权限处理、结果回调、裁剪参数定制以及底层FileProvider、content://URI 转换等实现原理。读完本文你将能够在一个FragmentActivity或Fragment中独立集成完整的图片选取与裁剪能力并掌握每个裁剪配置项的默认值与取值范围。模块定位一个方法搞定「选图 裁剪」AndroidPicker 的 ImagePicker 模块是一套基于startActivityForResult的图片选择组件整合了两种经典开源方案的能力图片选择相机与相册改造自 ImagePicker裁剪 UI 与手势交互改造自 Android-Image-Cropper。模块对外暴露的核心 API 只有ImagePicker一个类通过ImagePicker.getInstance()获取单例后即可分别调用startCamera(...)、startGallery(...)、startChooser(...)启动三类来源再配合一个抽象的 PickCallback 完成回调闭环。在仓库中ImagePicker 已被注册为独立模块见 settings.gradle 中的include :ImagePicker可通过 Gradle 依赖方式引入示例工程中的 ImagePickerActivity 是它的完整可运行范例。第一步声明权限与合规注意模块自身的 AndroidManifest.xml 已声明三项权限android.permission.CAMERA调用相机拍照时需要android.permission.READ_EXTERNAL_STORAGE读取相册/外置存储中的图片android.permission.WRITE_EXTERNAL_STORAGE写入裁剪结果等文件。集成时需注意两点这三个权限属于 Android 6.0API 23及以上的运行时权限除在 manifest 中声明外还必须在运行时向用户动态申请调用startCamera/startGallery/startChooser之前要确保用户已授予对应权限否则系统可能直接抛出安全异常或返回无数据。好消息是ImagePicker 内部会自动处理一部分运行时权限请求详见下文「底层实现」小节你只需要在Activity/Fragment的回调方法里把结果转发给ImagePicker即可。第二步最小可用示例源自模块 READMEImagePicker/README.md 给出了一个可直接照搬的完整示例使用FragmentActivity承载public class ImagePickerActivity extends FragmentActivity { private final PickCallback cropCallback new PickCallback() { Override public void onPermissionDenied(String[] permissions, String message) { Toast.makeText(ImagePickerActivity.this, message, Toast.LENGTH_SHORT).show(); } Override public void cropConfig(ActivityBuilder builder) { builder.setMultiTouchEnabled(true) .setGuidelines(CropImageView.Guidelines.ON_TOUCH) .setCropShape(CropImageView.CropShape.OVAL) .setRequestedSize(400, 400) .setFixAspectRatio(true) .setAspectRatio(1, 1); } Override public void onCropImage(Nullable Uri imageUri) { Toast.makeText(ImagePickerActivity.this, String.valueOf(imageUri), Toast.LENGTH_SHORT).show(); } }; public void onCamera(View view) { ImagePicker.getInstance().startCamera(this, true, cropCallback); } public void onGallery(View view) { ImagePicker.getInstance().startGallery(this, true, cropCallback); } Override protected void onActivityResult(int requestCode, int resultCode, Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); ImagePicker.getInstance().onActivityResult(this, requestCode, resultCode, data); } Override public void onRequestPermissionsResult(int requestCode, NonNull String[] permissions, NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); ImagePicker.getInstance().onRequestPermissionsResult(this, requestCode, permissions, grantResults); } }示例工程中的 ImagePickerActivity 与上述写法一致两个按钮分别触发相机与相册见布局文件 activity_picker_image.xml并在onActivityResult、onRequestPermissionsResult两个生命周期回调中把结果原样转发给ImagePicker.getInstance()。其中第二、三个参数的含义需要区分startCamera(this, true, callback)的true表示拍照后进入裁剪startGallery(this, true, callback)的true表示选图后进入裁剪如果只想取原图不裁剪传false即可示例工程中的相册按钮正是如此见 ImagePickerActivity.java#L80。第三步理解 PickCallback 的五个回调时机PickCallback 是一个抽象类非接口空方法全部可选覆写按调用顺序包含五个回调回调方法触发时机说明onCanceled()用户取消选择/拍照内部在resultCode ! RESULT_OK时触发onPermissionDenied(String[] permissions, String message)用户拒绝相机或存储权限内部会传入中文提示如「没有相机权限」「没有外部存储权限」onPickImage(Nullable Uri imageUri)图片已选定在裁剪之前回调若cropEnabledfalse此回调即最终结果cropConfig(ActivityBuilder builder)即将进入裁剪页在此统一配置裁剪参数默认实现为 OVAL、640×640、5:5 宽高比onCropImage(Nullable Uri imageUri)裁剪完成最终结果以Uri形式返回可直接用于显示或上传onCropError(NonNull Exception error)裁剪出错例如图片 URI 为空时抛出的IllegalArgumentException(Uri is null or empty)值得注意的是回调的顺序设计onPickImage会先于onCropImage触发源码见 ImagePicker.java#L236-L248因此即使cropEnabledtrue你也可以在onPickImage中拿到裁剪前的原始图片 URI若cropEnabledfalseonPickImage收到的就是最终结果。第四步启动入口 API 全览ImagePicker.java 是单例类内部使用静态内部类Holder实现懒加载单例对外提供三类启动方法且每个方法都同时支持Activity与Fragment两个重载// 相机拍照cropEnabled 控制是否继续裁剪 ImagePicker.getInstance().startCamera(activity, true, callback); ImagePicker.getInstance().startCamera(fragment, true, callback); // 相册/图库选取内部即 startChooser(..., image/*, ...) ImagePicker.getInstance().startGallery(activity, true, callback); ImagePicker.getInstance().startGallery(fragment, true, callback); // 自定义 MIME 的文件选择例如 image/*、video/*默认不裁剪 ImagePicker.getInstance().startChooser(activity, image/*, callback); ImagePicker.getInstance().startChooser(fragment, image/*, callback);从 HybridityUtils.java#L33-L42 的源码可见相册选取底层发送的是Intent.ACTION_GET_CONTENT并附带Intent.CATEGORY_OPENABLE类型为image/*startChooser允许传入任意 MIME 类型且实现中强制cropEnabled false见 ImagePicker.java#L93相机拍照发送的是MediaStore.ACTION_IMAGE_CAPTURE并通过MediaStore.EXTRA_OUTPUT指定输出文件见 HybridityUtils.java#L26-L31。第五步ActivityBuilder 裁剪参数完全参考当进入裁剪流程后cropConfig(ActivityBuilder builder)中拿到的 ActivityBuilder 承载了所有裁剪外观与输出参数。它内部持有一个 CropImageOptions所有 setter 均为链式调用并最终写入mOptions由 CropImageOptions.validate() 在启动前统一校验取值范围。裁剪窗口与手势方法默认值说明setCropShape(CropShape)RECTANGLE裁剪窗形状枚举见 CropImageView.java#L1466-L1469支持RECTANGLE矩形、OVAL圆形/椭圆通常配合 1:1 宽高比实现圆形头像setGuidelines(Guidelines)ON_TOUCH辅助参考线显示策略OFF永不显示、ON_TOUCH拖动时显示、ON始终显示见 CropImageView.java#L1518-L1533setScaleType(ScaleType)FIT_CENTER图片初始缩放适配方式setMultiTouchEnabled(boolean)false是否允许双指多点触控缩放/旋转setMaxZoom(int)4最大缩放倍数setTouchRadius(float)24dp手柄可触摸区域半径依据 48dp Rhythm 设计规范setSnapRadius(float)3dp裁剪框边缘吸附到边界的触发距离setAutoZoomEnabled(boolean)true拖动/缩放时是否自动缩放适配setShowCropOverlay(boolean)true是否显示裁剪窗外部的半透明遮罩宽高比与结果尺寸方法默认值说明setFixAspectRatio(boolean)false是否锁定宽高比注意setAspectRatio(...)内部会将其强制置为truesetAspectRatio(int x, int y)1 / 1裁剪窗宽高比例如setAspectRatio(1, 1)配合OVAL即圆形裁剪x、y都必须大于 0否则validate()抛出异常setRequestedSize(int w, int h)0, 0不缩放裁剪输出的目标尺寸默认使用RESIZE_INSIDE策略等比缩放至不超过该尺寸图片小于目标尺寸时不变setRequestedSize(int w, int h, RequestSizeOptions)—可指定缩放策略NONE不缩放、SAMPLING仅采样、RESIZE_INSIDE等比缩小、RESIZE_FIT等比适配、RESIZE_EXACT拉伸填满见 CropImageView.java#L1541-L1578setMinCropWindowSize(w, h)42dp, 42dp裁剪窗允许的最小尺寸setMinCropResultSize(w, h)40, 40裁剪结果允许的最小宽高setMaxCropResultSize(w, h)99999, 99999裁剪结果允许的最大宽高必须不小于最小值边框、辅助线与遮罩外观方法默认值说明setBorderLineThickness(float)3dp裁剪框边框线宽setBorderLineColor(int)Color.argb(170, 255, 255, 255)裁剪框边框颜色setBorderCornerThickness(float)2dp四角边线粗细setBorderCornerOffset(float)5dp角线与裁剪框边缘的偏移setBorderCornerLength(float)14dp角线的长度setBorderCornerColor(int)WHITE角线颜色setGuidelinesThickness(float)1dp辅助参考线线宽setGuidelinesColor(int)Color.argb(170, 255, 255, 255)辅助参考线颜色setBackgroundColor(int)Color.argb(119, 0, 0, 0)裁剪窗外遮罩背景色输出与旋转方法默认值说明setOutputUri(Uri)Uri.EMPTY裁剪结果的保存位置不设置时自动创建临时文件setOutputCompressFormat(Bitmap.CompressFormat)JPEG输出压缩格式setOutputCompressQuality(int)90压缩质量0–100setNoOutputImage(boolean)false设为true时不保存裁剪位图仅返回裁剪矩形与旋转数据高级用法setInitialCropWindowRectangle(Rect)null裁剪窗初始位置不设置则由 padding 比例推算setInitialRotation(int)-1初始旋转角度0–360默认读取图片 EXIFsetAllowRotation(boolean)true是否允许在裁剪过程中旋转setRotationDegrees(int)90单次旋转步长0–360必须在此范围内setInitialCropWindowPaddingRatio(float)0.1初始裁剪窗相对图片边缘的内边距比例取值必须小于 0.5第六步底层实现与关键调用链6.1 运行时权限的自动申请逻辑startCamera启动前会调用 HybridityUtils.isExplicitCameraPermissionRequired当系统为 Android 6.0、manifest 中声明了CAMERA权限、且当前未授予时自动通过ActivityCompat.requestPermissions请求相机权限授权成功后才真正拉起相机 Intent。选图结果回来后onActivityResultInner 会先尝试用ContentResolver.openInputStream探测 URI 是否可读见 HybridityUtils.isUriRequiresPermissions若不可读则自动请求READ_EXTERNAL_STORAGE。整个过程对调用方透明你只需要在两个权限回调中把结果转发给ImagePicker.getInstance()。6.2 content:// 到 file:// 的自动转换handleUri 会将回调中的content://协议 URI 通过 getRealPathFromUri查询MediaStore.Images.Media.DATA列转换为file://路径避免后续读写时抛出FileNotFoundException若转换失败则保留原始 URI 原样返回。6.3 FileProvider 与 Android 7.0 兼容相机拍照输出文件默认位于context.getExternalCacheDir()下的pickImageResult.jpeg见 HybridityUtils.java#L53-L60。由于 Android 7.0API 24起禁止在 Intent 中传递file://URIgetIntentUri 会自动改用FileProvider生成的content://URI其 authority 固定为${applicationId}.imagepicker.provider见 AndroidManifest.xml且grantUriPermissionstrue允许临时授权给相机应用。路径映射配置在 crop_image_paths.xml 中覆盖了external-path、external-cache-path、external-files-path三类根目录。6.4 裁剪页与结果回传裁剪由 CropImageActivity 承担manifest 中已声明竖屏。ActivityBuilder通过 getCropIntent 把源图片 URI 与CropImageOptionsParcelable打包进 Intent请求码CROP_IMAGE_ACTIVITY_REQUEST_CODE 203见 CropImageConsts.java。结果通过CROP_IMAGE_EXTRA_RESULT键以 ActivityResult 返回ImagePicker 解析出其中的错误或图片 URI 后分发给onCropError/onCropImage。第七步集成到自己的项目ImagePicker 以独立 Gradle 模块存在主仓库 README 中给出的引入方式为dependencies { implementation com.github.gzu-liyujiang.AndroidPicker:ImagePicker:version }若以源码方式集成则需在 settings.gradle 中include :ImagePicker并在依赖中加入project(:ImagePicker)。模块自带的 consumer-rules.pro 是专用于该库的混淆规则文件内容为空说明无需额外 keep 规则随 AAR 打包发布。集成清单总结如下在AndroidManifest.xml中声明CAMERA、READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE权限库模块已自带宿主工程声明后合并生效在Activity/Fragment中调用startCamera/startGallery/startChooser重写onActivityResult与onRequestPermissionsResult并转发给ImagePicker.getInstance()在PickCallback中按需覆写cropConfig配置裁剪参数在onCropImage中消费最终结果处理得到Uri后即可配合任意图片加载库进行显示或上传。常见问题与注意事项只想要原图不想裁剪将startCamera/startGallery的第二个参数传false此时最终结果在onPickImage中返回见 ImagePicker.java#L246-L248圆形头像setCropShape(CropImageView.CropShape.OVAL)配合setAspectRatio(1, 1)、setRequestedSize(400, 400)即 README 示例与 demo 中相机入口的配置参数非法会直接抛异常宽高比不能小于等于 0、initialCropWindowPaddingRatio必须在[0, 0.5)、rotationDegrees必须在[0, 360]、最大结果尺寸不得小于最小结果尺寸这些约束在CropImageOptions.validate()中强制执行配置时需注意取值范围相机权限兼容Android 6.0 以下系统无需动态申请相机权限isExplicitCameraPermissionRequired会直接返回false并跳过申请步骤临时输出文件相机拍照的原始输出固定为外置缓存目录下的pickImageResult.jpeg属于应用缓存系统可能随时清理如需要持久化请及时处理裁剪结果。至此从权限声明、入口调用、回调闭环到裁剪参数定制与底层原理ImagePicker 模块的完整使用路径已全部打通你也可以直接运行示例工程中的 ImagePickerActivity 体验「相机拍照」与「相册选取」两个入口的实际效果。赞分享移动开发UI组件【免费下载链接】AndroidPicker安卓选择器类库包括日期及时间选择器可用于出生日期、营业时间等、单项选择器可用于性别、民族、职业、学历、星座等、二三级联动选择器可用于车牌号、基金定投日期等、城市地址选择器分省级、地市级及区县级、数字选择器可用于年龄、身高、体重、温度等、日历选日期择器可用于酒店及机票预定日期、颜色选择器、文件及目录选择器、图片选择器等……WheelPicker/DatePicker/TimePicker/OptionPicker/NumberPicker/LinkagePicker/AddressPicker/CarPlatePicker/CalendarPicker/ColorPicker/FilePicker/ImagePicker etc.项目地址https://gitcode.com/gh_mirrors/an/AndroidPicker点击查看免费下载相关推荐Flutter图片选择器终极指南相机拍照与相册选择功能详解Flutter图片选择器终极指南相机拍照与相册选择功能详解 想要在Flutter应用中实现强大的图片选择功能吗flutter_deer项目提供了一个完整的解移动开发电商UI组件图片选择与裁剪AndroidPicker ImagePicker的完整解决方案图片选择与裁剪AndroidPicker ImagePicker的完整解决方案 本文详细解析了AndroidPicker ImagePicker模块的完整技术移动开发UI组件Mage-VL API完全指南图像理解、视频分析与主动流模式调用示例Mage VL API完全指南图像理解、视频分析与主动流模式调用示例 Mage VL是一款功能强大的多模态AI模型专注于图像理解、视频分析和主动流模式处理。人工智能基础模型多模态计算机视觉视频NLP创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考