Android类似微信聊天页面教程(Kotlin)五——选择发送图片

news/2024/11/28 19:40:36/

 

前提条件

安装并配置好Android Studio

Android Studio Electric Eel | 2022.1.1 Patch 2
Build #AI-221.6008.13.2211.9619390, built on February 17, 2023
Runtime version: 11.0.15+0-b2043.56-9505619 amd64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
Windows 11 10.0
GC: G1 Young Generation, G1 Old Generation
Memory: 1280M
Cores: 6
Registry:
    external.system.auto.import.disabled=true
    ide.text.editor.with.preview.show.floating.toolbar=false
    ide.balloon.shadow.size=0
 
Non-Bundled Plugins:
    com.intuit.intellij.makefile (1.0.15)
    com.github.setial (4.0.2)
    com.alayouni.ansiHighlight (1.2.4)
    GsonOrXmlFormat (2.0)
    GLSL (1.19)
    com.mistamek.drawablepreview.drawable-preview (1.1.5)
    com.layernet.plugin.adbwifi (1.0.5)
    com.likfe.ideaplugin.eventbus3 (2020.0.2)

gradle-wrapper.properties

#Tue Apr 25 13:34:44 CST 2023
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

build.gradle(:Project)

// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {id 'com.android.application' version '7.3.1' apply falseid 'com.android.library' version '7.3.1' apply falseid 'org.jetbrains.kotlin.android' version '1.7.20' apply false
}


setting.gradle

pluginManagement {repositories {maven { url 'https://maven.aliyun.com/repository/public' }google()mavenCentral()gradlePluginPortal()maven { url 'https://jitpack.io' }}
}
dependencyResolutionManagement {repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)repositories {maven { url 'https://maven.aliyun.com/repository/public' }google()mavenCentral()gradlePluginPortal()maven { url 'https://jitpack.io' }}
}
rootProject.name = "FeChat"
include ':app'


build.gralde(:app)

plugins {id 'com.android.application'id 'org.jetbrains.kotlin.android'id 'kotlin-android'id 'kotlin-kapt'
}android {namespace 'com.example.fechat'compileSdk 33defaultConfig {applicationId "com.example.fechat"minSdk 26targetSdk 33versionCode 1versionName "1.0"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}compileOptions {sourceCompatibility JavaVersion.VERSION_11targetCompatibility JavaVersion.VERSION_11}kotlinOptions {jvmTarget = '1.8'}
}dependencies {implementation 'androidx.core:core-ktx:1.7.0'implementation 'androidx.appcompat:appcompat:1.6.1'implementation 'com.google.android.material:material:1.8.0'implementation 'androidx.constraintlayout:constraintlayout:2.1.4'implementation 'androidx.cardview:cardview:1.0.0'implementation("androidx.activity:activity-ktx:1.7.1")// 沉浸式状态栏 https://github.com/gyf-dev/ImmersionBarimplementation 'com.gyf.immersionbar:immersionbar:3.0.0'implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0' // fragment快速实现(可选)implementation 'com.gyf.immersionbar:immersionbar-ktx:3.0.0' // kotlin扩展(可选)implementation 'com.google.code.gson:gson:2.8.9'implementation "androidx.room:room-runtime:2.4.2"implementation "androidx.room:room-ktx:2.4.2"kapt "androidx.room:room-compiler:2.4.2"implementation 'org.apache.commons:commons-csv:1.5'implementation 'com.permissionx.guolindev:permissionx:1.4.0'implementation 'com.blankj:utilcodex:1.30.0' // 无implementation 'com.github.bumptech.glide:glide:4.12.0'kapt 'com.github.bumptech.glide:compiler:4.12.0'implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.3'implementation 'com.github.li-xiaojun:XPopup:latest.release'
}


对Kotlin语言有基本了解

内容在前一篇博客中写了基础配置,如果本篇内容看不懂,可以先去上一篇。

使用 Jetpack activity 协定

为了简化照片选择器的集成,请添加 1.7.0 版或更高版本的 androidx.activity 库。

您可以使用以下 activity 结果协定来启动照片选择器:

  • PickVisualMedia,用于选择单张图片或单个视频。
  • PickMultipleVisualMedia,用于选择多张图片或多个视频。

如果照片选择器在设备上不可用,该库会自动调用 ACTION_OPEN_DOCUMENT intent 操作。搭载 Android 4.4(API 级别 19)或更高版本的设备支持此 intent。您可以通过调用 isPhotoPickerAvailable() 来验证照片选择器在给定设备上是否可用。

图片选择

照片选择器提供了一个可浏览、可搜索的界面,其中按日期(从最近到最早)顺序向用户呈现其媒体库中的文件。您可以指定用户只能看到照片或只能看到视频,并且默认情况下,允许的媒体选择量上限设置为 1

单图选择器

ActivityResultContracts.PickVisualMedia()

多图选择器

ActivityResultContracts.PickMultipleVisualMedia("自定义选择上限")

平台会限制您可以让用户在照片选择器中选择的文件数量上限。如需访问此限制,请调用 getPickImagesMaxLimit()。 在不支持照片选择器的设备上,系统会忽略此上限。

注意:如果照片选择器不可用,且支持库调用 ACTION_OPEN_DOCUMENT intent 操作,则系统会忽略指定的可选媒体文件数量上限。

适用的设备

照片选择器适用于符合以下条件的设备:

  • 搭载 Android 11(API 级别 30)或更高版本
  • 通过 Google 系统更新接收对模块化系统组件的更改

搭载 Android 4.4(API 级别 19)到 Android 10(API 级别 29)的旧款设备,以及搭载 Android 11 或 12 且支持 Google Play 服务的 Android Go 设备,都可以安装向后移植的照片选择器版本。如需通过 Google Play 服务自动安装向后移植的照片选择器模块,请将以下条目添加到应用清单文件的 <application> 标记中:

<!-- Trigger Google Play services to install the backported photo picker module. -->
<service android:name="com.google.android.gms.metadata.ModuleDependencies"android:enabled="false"android:exported="false"><intent-filter><action android:name="com.google.android.gms.metadata.MODULE_DEPENDENCIES" /></intent-filter><meta-data android:name="photopicker_activity:0:required" android:value="" />
</service>

保留媒体文件访问权限

默认情况下,系统会授予应用对媒体文件的访问权限,直到设备重启或应用停止运行。如果您的应用执行长时间运行的工作(例如在后台上传大型文件),您可能需要将此访问权限保留更长时间。为此,请调用 takePersistableUriPermission() 方法:

val flag = Intent.FLAG_GRANT_READ_URI_PERMISSION
context.contentResolver.takePersistableUriPermission(uri, flag)

实现方案

根据官方文档介绍,于是有了以下的初始化方式(此处在context的create生命周期中调用):

private var media: ActivityResultLauncher<PickVisualMediaRequest>? = null
fun initPicker(activity: AppCompatActivity,maxFiles: Int = 1,listener: PickFileResultListener
) {val contract = if (maxFiles == 1)ActivityResultContracts.PickVisualMedia()elseActivityResultContracts.PickMultipleVisualMedia(maxFiles)media =activity.registerForActivityResult(contract) { uri ->if (uri != null) {val uris = uri.toString().substring(1, uri.toString().length - 1).split(",")listener.onPick(uris)Log.e("PhotoPicker", "Selected URI: $uris")} else {Log.e("PhotoPicker", "No media selected")}}
}

选择回调监听器

interface PickFileResultListener {fun onPick(uris: List<String>)
}

调用如下

fun pickMedia(fileType: String) {media?.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.SingleMimeType(fileType)))
}

其中选择类型定义为:

const val PICK_IMAGE_VIDEO = "*/*"
const val PICK_IMAGE = "image/*"
const val PICK_VIDEO = "video/*"
const val PICK_GIF = "image/gif"

转化路径

这样得到的Uri如果想要使用,需要先转化为绝对路径

fun Uri2Path(context: Context, uri: Uri?): String? {if (uri == null) {return null}if (ContentResolver.SCHEME_FILE == uri.scheme) {return uri.path} else if (ContentResolver.SCHEME_CONTENT == uri.scheme) {val authority: String = uri.authority!!if (authority.startsWith("com.android.externalstorage")) {return "${Environment.getExternalStorageDirectory()}/${uri.path?.split(":")?.get(1)}"} else {try {var idStr = ""if (authority == "media") {idStr = uri.toString().substring(uri.toString().lastIndexOf('/') + 1)} else if (authority.startsWith("com.android.providers")) {idStr = DocumentsContract.getDocumentId(uri).split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1]}val contentResolver = context.contentResolverval cursor: Cursor? = contentResolver.query(MediaStore.Files.getContentUri("external"),arrayOf(MediaStore.Files.FileColumns.DATA),"_id=?",arrayOf(idStr),null)if (cursor != null) {cursor.moveToFirst()val idx: Int = cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA)val path = cursor.getString(idx)cursor.close()return path}} catch (e: Exception) {e.printStackTrace()}}}return null
}

大图预览

预览框架采用XPopup

需要添加依赖

implementation 'com.github.li-xiaojun:XPopup:latest.release'
private fun showImageView(imageView: ImageView, currentPosition: Int) {XPopup.Builder(context).isDestroyOnDismiss(true).asImageViewer(imageView, currentPosition, uris,{ popupView, position ->/*Toast.makeText(context, "切换到第" + position + "个图片", Toast.LENGTH_SHORT).show()*/},SmartGlideImageLoader(R.mipmap.ic_launcher)).show()
}

http://www.ppmy.cn/news/63002.html

相关文章

PAT A1035 Password

1035 Password 分数 20 作者 CHEN, Yue 单位 浙江大学 To prepare for PAT, the judge sometimes has to generate random passwords for the users. The problem is that there are always some confusing passwords since it is hard to distinguish 1 (one) from l (L i…

20230505----重返学习-回顾JavaScript知识体系的综合性整理-数据类型转化-堆栈内存及闭包作用域

day-062-sixty-two-20230505-回顾JavaScript知识体系的综合性整理-数据类型转化-堆栈内存及闭包作用域 回顾JavaScript知识体系的综合性整理 数据类型和堆栈内存 变量声明&#xff1a; 声明方式&#xff08;var、function、let、const、class、import模块&#xff09;命名方式…

【论文阅读】EPnP: An Accurate O(n) Solution to the PnP Problem

目录 EPnP: An Accurate O(n) Solution to the PnP ProblemOpencv.solvePnP documentationsimilar functionscv::SOLVEPNP_EPNP: Paper 008 EPnP: An Accurate O(n) Solution to the PnP Problem Opencv.solvePnP documentation solvePnP bool cv::solvePnP( InputArray ob…

Py之imbalanced-ensemble:imbalanced-ensemble库的简介、安装、使用方法之详细攻略

Py之imbalanced-ensemble&#xff1a;imbalanced-ensemble库的简介、安装、使用方法之详细攻略 目录 imbalanced-ensemble库的简介 imbalanced-ensemble库的安装 imbalanced-ensemble库的使用方法 1、基础用法 imbalanced-ensemble库的简介 imbalanced-ensemble是一个用于处…

晶振概述及工作原理

晶振在电路板中随处可见&#xff0c;只要用到处理器的地方就必定有晶振的存在&#xff0c;即使没有外部晶振&#xff0c;芯片内部也有晶振。 晶振概述 晶振一般指晶体振荡器。晶体振荡器是指从一块石英晶体上按一定方位角切下薄片&#xff08;简称为晶片&#xff09;&#xf…

中国社科院与美国杜兰大学金融管理硕士项目,引领你走在金融行业前沿

作为金融领域从业人员时刻都在关注行业最新资讯&#xff0c;只有掌握一手的前沿讯息&#xff0c;才能在职场上无往不胜。针对在职的你&#xff0c;如何利用业余时间让自己更增值呢&#xff0c;中国社科院与美国杜兰大学金融管理硕士项目引领你走在金融行业前沿。 金融管理硕士…

Spring的第十三阶段:Spring之JdbcTemplate使用(02)

Spring之JdbcTemplate使用 在Spring中提供了对jdbc的封装类叫JdbcTemplate。它可以很方便的帮我们执行sql语句&#xff0c;操作数据库。 1、先准备单表的数据库数据 drop database if exists jdbctemplate;create database jdbctemplate;use jdbctemplate;create table empl…

bigdata-file-viewer--大数据文件查看工具

bigdata-file-viewer--大数据文件查看工具 bigdata-file-viewer是什么常用功能安装 bigdata-file-viewer是什么 一个跨平台&#xff08;Windows&#xff0c;MAC&#xff0c;Linux&#xff09;桌面应用程序&#xff0c;用于查看常见的大数据二进制格式&#xff0c;例如Parquet&…