?
前提條件
安裝并配置好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 false
? ? id 'com.android.library' version '7.3.1' apply false
? ? id '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 33
defaultConfig {
applicationId "com.example.fechat"
minSdk 26
targetSdk 33
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility 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")
// 沉浸式狀態(tài)欄 https://github.com/gyf-dev/ImmersionBar
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0' // fragment快速實(shí)現(xiàn)(可選)
implementation 'com.gyf.immersionbar:immersionbar-ktx:3.0.0' // kotlin擴(kuò)展(可選)
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語言有基本了解
內(nèi)容在前一篇博客中寫了基礎(chǔ)配置,如果本篇內(nèi)容看不懂,可以先去上一篇。
使用 Jetpack activity 協(xié)定
為了簡化照片選擇器的集成,請?zhí)砑?1.7.0 版或更高版本的?androidx.activity?庫。
您可以使用以下 activity 結(jié)果協(xié)定來啟動照片選擇器:
- PickVisualMedia,用于選擇單張圖片或單個(gè)視頻。
- PickMultipleVisualMedia,用于選擇多張圖片或多個(gè)視頻。
如果照片選擇器在設(shè)備上不可用,該庫會自動調(diào)用?ACTION_OPEN_DOCUMENT?intent 操作。搭載 Android 4.4(API 級別 19)或更高版本的設(shè)備支持此 intent。您可以通過調(diào)用?isPhotoPickerAvailable()?來驗(yàn)證照片選擇器在給定設(shè)備上是否可用。
圖片選擇
照片選擇器提供了一個(gè)可瀏覽、可搜索的界面,其中按日期(從最近到最早)順序向用戶呈現(xiàn)其媒體庫中的文件。您可以指定用戶只能看到照片或只能看到視頻,并且默認(rèn)情況下,允許的媒體選擇量上限設(shè)置為 1
單圖選擇器
ActivityResultContracts.PickVisualMedia()
多圖選擇器
ActivityResultContracts.PickMultipleVisualMedia("自定義選擇上限")
平臺會限制您可以讓用戶在照片選擇器中選擇的文件數(shù)量上限。如需訪問此限制,請調(diào)用?getPickImagesMaxLimit()。 在不支持照片選擇器的設(shè)備上,系統(tǒng)會忽略此上限。
注意:如果照片選擇器不可用,且支持庫調(diào)用?
ACTION_OPEN_DOCUMENT
?intent 操作,則系統(tǒng)會忽略指定的可選媒體文件數(shù)量上限。
適用的設(shè)備
照片選擇器適用于符合以下條件的設(shè)備:
- 搭載 Android 11(API 級別 30)或更高版本
- 通過?Google 系統(tǒng)更新接收對模塊化系統(tǒng)組件的更改
搭載 Android 4.4(API 級別 19)到 Android 10(API 級別 29)的舊款設(shè)備,以及搭載 Android 11 或 12 且支持 Google Play 服務(wù)的 Android Go 設(shè)備,都可以安裝向后移植的照片選擇器版本。如需通過 Google Play 服務(wù)自動安裝向后移植的照片選擇器模塊,請將以下條目添加到應(yīng)用清單文件的?<application>
?標(biāo)記中:
<!-- 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>
保留媒體文件訪問權(quán)限
默認(rèn)情況下,系統(tǒng)會授予應(yīng)用對媒體文件的訪問權(quán)限,直到設(shè)備重啟或應(yīng)用停止運(yùn)行。如果您的應(yīng)用執(zhí)行長時(shí)間運(yùn)行的工作(例如在后臺上傳大型文件),您可能需要將此訪問權(quán)限保留更長時(shí)間。為此,請調(diào)用?takePersistableUriPermission()?方法:
val flag = Intent.FLAG_GRANT_READ_URI_PERMISSION
context.contentResolver.takePersistableUriPermission(uri, flag)
實(shí)現(xiàn)方案
根據(jù)官方文檔介紹,于是有了以下的初始化方式(此處在context的create生命周期中調(diào)用):
private var media: ActivityResultLauncher<PickVisualMediaRequest>? = null
fun initPicker(
activity: AppCompatActivity,
maxFiles: Int = 1,
listener: PickFileResultListener
) {
val contract = if (maxFiles == 1)
ActivityResultContracts.PickVisualMedia()
else
ActivityResultContracts.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")
}
}
}
選擇回調(diào)監(jiān)聽器
interface PickFileResultListener {
fun onPick(uris: List<String>)
}
調(diào)用如下
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"
轉(zhuǎn)化路徑
這樣得到的Uri如果想要使用,需要先轉(zhuǎn)化為絕對路徑
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.contentResolver
val 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
}
大圖預(yù)覽
預(yù)覽框架采用XPopup文章來源:http://www.zghlxwxcb.cn/news/detail-437840.html
需要添加依賴文章來源地址http://www.zghlxwxcb.cn/news/detail-437840.html
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 + "個(gè)圖片", Toast.LENGTH_SHORT
).show()*/
},
SmartGlideImageLoader(R.mipmap.ic_launcher)
)
.show()
}
到了這里,關(guān)于Android類似微信聊天頁面教程(Kotlin)五——選擇發(fā)送圖片的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!