一、图片显示
1、要做到图片不变形,不裁剪,正常显示,必须知道图片的宽高或者是宽高比,加载的时候,如果高度大于宽度,就先加载高度为父布局高度,宽度根据比例加载,反之一样。
private fun setImageWidthHeight(imageView: ImageView,width:Int,height:Int){
imageView.post {
val params: RelativeLayout.LayoutParams = imageView.layoutParams as RelativeLayout.LayoutParams
if (height >= width){ //撑满高度
imageView.layoutParams.height = mImageWidth
val tempWidth: Float = (width.toFloat()) / (height.toFloat())
imageView.layoutParams.width = (tempWidth * mImageWidth).toInt()
imageView.layoutParams = params
Log.d("setImageWidthHeight", "setImageWidthHeight: 图片宽度是:${imageView.layoutParams.width},," +
",高度是:${imageView.layoutParams.height}"+ ",,,,"+tempWidth)
}else{
imageView.layoutParams.width = mImageWidth
val tempHeight: Float = (height.toFloat()) / (width.toFloat())
imageView.layoutParams.height = (tempHeight * mImageWidth).toInt()
imageView.layoutParams = params
Log.d("setImageWidthHeight", "setImageWidthHeight: 图片宽度是:${imageView.layoutParams.width},," +
",高度是:${imageView.layoutParams.height}"+ ",,,,"+tempHeight)
}
}
}
或者使用约束布局,前提也是必须知道宽高比或者宽高,只有知道了宽高比,才不会压缩和变形
二、图片加载
图片的选取,压缩、显示,建议使用第三方加载库:pictureselector,里面已经适配了Android 13版本
注:GIF图片不能进行压缩,一旦压缩就变成了静态图片
三、图片上传
上传时区分类型
gif图片使用MediaType.parse("image/gif");
静态图片使用MediaType.parse("image/png");类型
fun <T> uploadImage(
cls: Class<T>,
reqUrl: String,
fileList: ArrayList<BeanImage>,
callBack: RequestCallBack<T>
) {
val params = HashMap<String, Any>()
HttpUtils.addCommonData(params)
val multipartBodyBuilder = MultipartBody.Builder()
multipartBodyBuilder.setType(MultipartBody.FORM)
//遍历map中所有参数到builder
for (key in params.keys) {
multipartBodyBuilder.addFormDataPart(key, params[key].toString() + "")
}
//遍历paths中所有图片绝对路径到builder,并约定key如“upload”作为后台接受多张图片的key
LogUtils.d(TAG, "uploadImage: 需要上传的图片是:${fileList}")
for (index in 0 until fileList.size) {
val url = fileList[index].url ?: ""
val file = File(url)
if (!file.exists()) {
return
}
val fileName = System.currentTimeMillis().toString() + "_" + file.name
LogUtils.d(TAG, "uploadImage 文件的名称是: $fileName")
if (fileList[index].isGif()) {
Log.d(TAG, "uploadImage: 当前是gif图,,$fileName")
multipartBodyBuilder.addFormDataPart(
"file${index}",
fileName,
file.asRequestBody(HttpUtils.MEDIA_TYPE_GIF)
)
} else {
multipartBodyBuilder.addFormDataPart(
"file${index}",
fileName,
file.asRequestBody(HttpUtils.MEDIA_TYPE_PNG)
)
}
multipartBodyBuilder.addFormDataPart("type", "1")
}
val builder = CacheControl.Builder()
builder.noCache() //不使用缓存,全部走网络
builder.noStore() //不使用缓存,也不存储缓存
val cache: CacheControl = builder.build()
val requestBody: RequestBody = multipartBodyBuilder.build()
val requestBuilder = Request.Builder()
requestBuilder.url(reqUrl)
requestBuilder.cacheControl(cache)
requestBuilder.post(requestBody)
//设置header
var headersMap: HashMap<String, String> = HashMap()
headersMap = OKHttpExecuter.initHttpRequestHeader(headersMap)
if (headersMap != null && headersMap.size > 0) {
try {
val headers: Headers = headersMap.toHeaders()
requestBuilder.headers(headers)
} catch (e: Exception) {
Log.d(TAG, "uploadImage: " + e.message)
}
}
val request: Request = requestBuilder.build()
HttpUtils.client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
call.cancel()
Log.d(TAG, "onFailure: " + e.message.toString())
BaseUtils.getHandler().post {
callBack.error(e.message.toString())
}
}
@Throws(IOException::class)
override fun onResponse(call: Call, response: Response) {
val str = response.body?.string() //图片返回json数据
call.cancel()
}
})
}
三、图片下载
图片下载保存到图库需要申请存储权限,使用XXPermissions申请权限。
保存到图库需要适配Android12分区存储,代码参考pictureselector,静态图和动态图的下载要注意区分。
/**
* 保存文件
*
* @param context 上下文
* @param path 文件下载路径url
* @param mimeType 文件类型
* @param listener 结果回调监听
*/
public static void saveLocalFile(Context context, String path, String mimeType,
OnCallbackListener<String> listener) {
PictureThreadUtils.executeByIo(new PictureThreadUtils.SimpleTask<String>() {
@Override
public String doInBackground() {
try {
Uri uri;
ContentValues contentValues = new ContentValues();
String time = ValueOf.toString(System.currentTimeMillis());
if (PictureMimeType.isHasAudio(mimeType)) {
contentValues.put(MediaStore.Audio.Media.DISPLAY_NAME, DateUtils.getCreateFileName("AUD_"));
contentValues.put(MediaStore.Audio.Media.MIME_TYPE, TextUtils.isEmpty(mimeType)
|| mimeType.startsWith(PictureMimeType.MIME_TYPE_PREFIX_VIDEO)
|| mimeType.startsWith(PictureMimeType.MIME_TYPE_PREFIX_IMAGE) ? PictureMimeType.MIME_TYPE_AUDIO : mimeType);
if (SdkVersionUtils.isQ()) {
contentValues.put(MediaStore.Audio.Media.DATE_TAKEN, time);
contentValues.put(MediaStore.Audio.Media.RELATIVE_PATH, Environment.DIRECTORY_MUSIC);
} else {
File dir = TextUtils.equals(Environment.getExternalStorageState(), Environment.MEDIA_MOUNTED)
? Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC)
: context.getExternalFilesDir(Environment.DIRECTORY_MUSIC);
contentValues.put(MediaStore.MediaColumns.DATA, dir.getAbsolutePath() + File.separator
+ DateUtils.getCreateFileName("AUD_") + PictureMimeType.AMR);
}
uri = context.getContentResolver().insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, contentValues);
} else if (PictureMimeType.isHasVideo(mimeType)) {
contentValues.put(MediaStore.Video.Media.DISPLAY_NAME, DateUtils.getCreateFileName("VID_"));
contentValues.put(MediaStore.Video.Media.MIME_TYPE, TextUtils.isEmpty(mimeType)
|| mimeType.startsWith(PictureMimeType.MIME_TYPE_PREFIX_AUDIO)
|| mimeType.startsWith(PictureMimeType.MIME_TYPE_PREFIX_IMAGE) ? PictureMimeType.MIME_TYPE_VIDEO : mimeType);
if (SdkVersionUtils.isQ()) {
contentValues.put(MediaStore.Video.Media.DATE_TAKEN, time);
contentValues.put(MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_MOVIES);
} else {
File dir = TextUtils.equals(Environment.getExternalStorageState(), Environment.MEDIA_MOUNTED)
? Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)
: context.getExternalFilesDir(Environment.DIRECTORY_MOVIES);
contentValues.put(MediaStore.MediaColumns.DATA, dir.getAbsolutePath() + File.separator
+ DateUtils.getCreateFileName("VID_") + PictureMimeType.MP4);
}
uri = context.getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, contentValues);
} else { // 如果是图片
contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, DateUtils.getCreateFileName("IMG_"));
contentValues.put(MediaStore.Images.Media.MIME_TYPE, TextUtils.isEmpty(mimeType)
|| mimeType.startsWith(PictureMimeType.MIME_TYPE_PREFIX_AUDIO)
|| mimeType.startsWith(PictureMimeType.MIME_TYPE_PREFIX_VIDEO) ? PictureMimeType.MIME_TYPE_IMAGE : mimeType);
if (SdkVersionUtils.isQ()) {
contentValues.put(MediaStore.Images.Media.DATE_TAKEN, time);
contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, PictureMimeType.DCIM);
} else {
if (PictureMimeType.isHasGif(mimeType) || PictureMimeType.isUrlHasGif(path)) {
File dir = TextUtils.equals(Environment.getExternalStorageState(), Environment.MEDIA_MOUNTED)
? Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
: context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
contentValues.put(MediaStore.MediaColumns.DATA, dir.getAbsolutePath() + File.separator
+ DateUtils.getCreateFileName("IMG_") + PictureMimeType.GIF);
}
}
//插入到图库相册
uri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
}
if (uri != null) {
InputStream inputStream;
if (PictureMimeType.isHasHttp(path)) {
inputStream = new URL(path).openStream();
} else {
if (PictureMimeType.isContent(path)) {
inputStream = PictureContentResolver.getContentResolverOpenInputStream(context, Uri.parse(path));
} else {
inputStream = new FileInputStream(path);
}
}
OutputStream outputStream = PictureContentResolver.getContentResolverOpenOutputStream(context, uri);
boolean bufferCopy = PictureFileUtils.writeFileFromIS(inputStream, outputStream);
if (bufferCopy) {
return PictureFileUtils.getPath(context, uri);
}
}
} catch (Exception e) {
Log.d("saveLocalFile", "Exception - doInBackground: " + e.getMessage());
PictureThreadUtils.cancel(this);
if (listener != null) {
listener.onCall("");
}
e.printStackTrace();
}
return null;
}
@Override
public void onSuccess(String result) {
PictureThreadUtils.cancel(this);
ModifyExif.setExif(context,result);
if (listener != null) {
listener.onCall(result);
}
}
@Override
public void onCancel() {
Log.d("saveLocalFile", "onCancel: " + "");
PictureThreadUtils.cancel(this);
if (listener != null) {
listener.onCall("");
}
}
@Override
public void onFail(Throwable t) {
Log.d("saveLocalFile", "onFail: " + t.getMessage());
// PictureThreadUtils.cancel(this);
// if (listener != null) {
// listener.onCall("");
// }
}
});
}
2、坑:解决图片插入到图库时间不对的bug,系统自带的相册图库会根据图片携带的时间信息进行时间顺序排列,可以通过代码修改图片的创建时间来修改图片原始的创建时间
导入exifinterface框架,需要先申请存储权限
implementation 'androidx.exifinterface:exifinterface:1.3.0'
//设置exif
public static void setExif(Context context,String filepath) {
boolean granted = XXPermissions.isGranted(context, Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE);
if (!granted){
return;
}
LogUtils.d("ModifyExif","需要修改的图片的路径是:" + filepath);
SimpleDateFormat lastModifiedDate = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss", Locale.CHINA);
try {
exif = new ExifInterface(filepath); //根据图片的路径获取图片的Exif
} catch (IOException ex) {
Log.e("Mine", "cannot read exif", ex);
}
exif.setAttribute(ExifInterface.TAG_DATETIME, lastModifiedDate.format(System.currentTimeMillis())); //把时间写进exif
try {
exif.saveAttributes(); //最后保存起来
} catch (IOException e) {
Log.e("Mine", "cannot save exif", e);
}
}
网友评论