安卓图片保存到本地和裁剪

安卓图片保存到本地和裁剪

这里的两个小功能做了我四天,实在是坑爹啊,对安卓的文件,uri还是懵懵懂懂,先把能实现的方法记录一下

安卓10,11之后的存储空间管理是一个大坑,有时间要系统的整理一下

保存图片

要保存图片到本地,我们有样学样,先看看其他应用保存到了哪里

打开相册,发现大多数app保存的图片都在内部存储/Pictures/xxx 下,xxx为应用自己命名的目录名,通常和应用名的英文或者拼音一致(我使用的是MIUI系统)

在安卓10适配时,要访问到这个内部存储,需要通过uri,因为我们保存的是图片,可以借助媒体库把图片插入进来,下面的代码和注释很好的说明了

val values = ContentValues()

// 指定相册, 这里是内部存储空间的Pictures相册下面再生成相册
values.put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/simple")

// 生成保存位置的uri
val saveUri: Uri?= requireContext().contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
if (saveUri != null) {
    // 利用输出流,把文件写出,并压缩
    requireContext().contentResolver.openOutputStream(saveUri).use{   
    if(bitmap.compress(Bitmap.CompressFormat.JPEG,100,it)){
    	Toast.makeText(requireContext(),"存储成功",Toast.LENGTH_SHORT).show()
	}else{
         Toast.makeText(requireContext(),"存储失败",Toast.LENGTH_SHORT).show()
     	}
    }
  }else{
      Toast.makeText(requireContext(),"存储失败",Toast.LENGTH_SHORT).show()
 }
}

这里根据文档的指导,要先生成我们插入位置的uri,然后才通过输出流的方式把文件写入存储中。在这里要注意,只有指定格式为JPG,才会在照片中直接看到我们保存的图片,若写入为PNG,则只能先寻找相册再找到图片。这里用了use拓展,把输出流指定为bitmap压缩的路径,压缩率为100

裁剪图片

打开相册

要从相册中选择图片,首先我们要能选出来。系统把打开相册封装为了一个具有返回值的Activity,我们选择的照片就是返回值

imageView!!.setOnClickListener {
     val intent = Intent()
     intent.type = "image/*"
     intent.action = "android.intent.action.GET_CONTENT" 
     intent.addCategory("android.intent.category.OPENABLE")
     startActivityForResult(intent, REQUEST_CODE_ALBUM) 
}

在这里,点击头像框的imageview后,会打开相册,然后等待返回值。当在相册中点击选到一张图片,就返回了

成功返回后,进行处理:

 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
	super.onActivityResult(requestCode, resultCode, data)
    if (resultCode == Activity.RESULT_OK) {
    	when (requestCode) {
        	REQUEST_CODE_ALBUM ->{  // 在这里处理逻辑
             	Log.d("返回值", "${REQUEST_CODE_ALBUM}")	
                // 下面的uCrop是裁剪函数,后面会介绍
                uCrop(data?.data!!)
               
	}
}

裁剪

如果要给用户做更换头像的功能,必须用到裁剪图片,这里我们使用第三方库UCrop进行裁剪

UCrop项目地址

首先导入依赖:

allprojects {
    repositories {
        ...
        maven { url "https://jitpack.io" }
    	...
    }
    
// :app中   
implementation ‘com.github.yalantis:ucrop:2.2.6-native‘
implementation ‘com.github.yalantis:ucrop:2.2.6‘

上面打开相册用了uCrop函数,我们考察这个函数的内容

 @RequiresApi(Build.VERSION_CODES.Q)
 fun uCrop(sUri:Uri){
	var mPhotoUri = getCacheuri()
     Log.d("返回的Uri","${mPhotoUri}")
     UCrop.of(sUri, mPhotoUri!!) //定义路径
     	.withAspectRatio(1f, 1f) //定义裁剪比例
        .withMaxResultSize(150, 150) //定义裁剪图片宽高最大值, 一般要适配你的imageview
        .start(this)
 }

在UCrop的调用中,我们要指定一个图片来源的Uri (这里采用的是打开相册返回的Uri) ,和一个裁剪后保存的Uri,把图片存到某个地方

我们可以把目标Uri定位在app缓存中,getCacheuri函数实现了这个功能

fun getCacheuri():Uri{
	var cacheFile:File? = null
    val  outpurDir = this.cacheDir
    if(outpurDir.exists()){
        cacheFile = File(outpurDir.path+File.separator+"${System.currentTimeMillis()}_"+"cache.png")
     }
     var mPhotoUri = Uri.fromFile(cacheFile)
     return mPhotoUri
}

在这里,我们获取到应用缓存目录,然后在缓存目录下创建一个新文件(格式可以修改,这里用了时间戳来保证唯一文件名),然后把这个文件对应的Uri返回回去,此时文件创建出来,但没有具体内容

裁剪成功后,显示我们裁剪的图片

// 在override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) 作为一个选择项
UCrop.REQUEST_CROP->{
	Log.d("裁剪返回", "${UCrop.REQUEST_CROP}")
    var uri = UCrop.getOutput(data!!)
    Log.d("返回Uri", "${uri}")
    imageView!!.setImageURI(uri) // 这里也可以运用Glide加载
}

这样,一般就能实现截图功能

简易的图片界面, 用了ShapeAbleImageView, 宽高都是150dp

安卓图片保存到本地和裁剪

截图使用

安卓图片保存到本地和裁剪

裁剪后图像,大致实现了个换头像的效果

安卓图片保存到本地和裁剪

安卓图片保存到本地和裁剪

上一篇:一张券APP的简介


下一篇:Web网站数据”实时”更新设计