Skip to content

Commit d56ed7e

Browse files
committed
图片预览页面新增分享以及保存本地功能
1 parent e25e94c commit d56ed7e

File tree

18 files changed

+384
-6
lines changed

18 files changed

+384
-6
lines changed

app/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ dependencies {
5555
//Androidx
5656
implementation 'androidx.appcompat:appcompat:1.2.0'
5757
implementation 'androidx.constraintlayout:constraintlayout:2.0.2'
58+
implementation project(path: ':common')
5859
testImplementation 'junit:junit:4.13'
5960
androidTestImplementation 'androidx.test:runner:1.3.0'
6061
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'

app/src/main/java/com/fmt/github/App.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class App : Application() {
1818
TaskDispatcher.createInstance()
1919
.addTask(InitBuGlyTask())
2020
.addTask(InitKoInTask())
21+
.addTask(InitImageLoaderTask())
2122
.addTask(InitLiveEventBusTask())
2223
.addTask(InitSmartRefreshLayoutTask())
2324
.start()

app/src/main/java/com/fmt/github/ext/DataBindExt.kt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,17 @@ import android.widget.ImageView
99
import androidx.core.content.ContextCompat
1010
import androidx.databinding.BindingAdapter
1111
import androidx.databinding.BindingConversion
12-
import androidx.databinding.ViewDataBinding
1312
import com.fmt.github.AppContext
14-
import com.fmt.github.GlideApp
1513
import com.fmt.github.R
14+
import com.fmt.github.common.image.ImageLoader
1615
import com.fmt.github.home.model.ReceivedEventModel
1716
import com.fmt.github.repos.model.ReposItemModel
1817

1918
//DataBinding自定义属性
2019
@BindingAdapter("url")
2120
fun loadImage(imageView: ImageView, url: String) {
22-
GlideApp.with(AppContext).load(url)
23-
.placeholder(R.mipmap.ic_github)
24-
.into(imageView)
21+
ImageLoader.LoaderOptions().setImageUrl(url).setPlaceholderId(R.mipmap.ic_github)
22+
.setTargetView(imageView).build().load()
2523
}
2624

2725
//DataBinding类型转换
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.fmt.github.tasks
2+
3+
import android.graphics.drawable.Drawable
4+
import android.view.View
5+
import android.widget.ImageView
6+
import com.bumptech.glide.Glide
7+
import com.bumptech.glide.request.RequestOptions
8+
import com.bumptech.glide.request.target.CustomViewTarget
9+
import com.bumptech.glide.request.transition.Transition
10+
import com.fmt.github.common.image.ImageLoadStrategyManager
11+
import com.fmt.github.common.image.ImageLoader
12+
import com.fmt.launch.starter.task.MainTask
13+
14+
class InitImageLoaderTask : MainTask() {
15+
16+
override fun run() {
17+
ImageLoadStrategyManager.init(GlideLoadStrategy())
18+
}
19+
20+
class GlideLoadStrategy : ImageLoadStrategyManager.ILoaderStrategy {
21+
22+
override fun loadImage(options: ImageLoader.LoaderOptions) {
23+
24+
var requestOptions = RequestOptions()
25+
if (options.placeholderId != null) {
26+
requestOptions = requestOptions.placeholder(options.placeholderId!!)
27+
}
28+
29+
options.targetView?.let { view ->
30+
if (view is ImageView) {
31+
Glide.with(view.context).load(options.url).apply(requestOptions).into(view)
32+
} else {
33+
Glide.with(view.context).load(options.url).apply(requestOptions).into(object :
34+
CustomViewTarget<View, Drawable>(view) {
35+
36+
override fun onResourceReady(
37+
resource: Drawable,
38+
transition: Transition<in Drawable>?
39+
) {
40+
view.background = resource
41+
}
42+
43+
override fun onLoadFailed(errorDrawable: Drawable?) {
44+
}
45+
46+
override fun onResourceCleared(placeholder: Drawable?) {
47+
}
48+
})
49+
}
50+
}
51+
}
52+
}
53+
}

app/src/main/java/com/fmt/github/user/activity/PhotoPreviewActivity.kt

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,30 @@
11
package com.fmt.github.user.activity
22

33
import android.app.Activity
4+
import android.content.Intent
5+
import android.graphics.Bitmap
6+
import android.graphics.drawable.Drawable
7+
import android.net.Uri
8+
import android.os.Build
49
import android.os.Bundle
10+
import androidx.core.content.FileProvider
11+
import com.bumptech.glide.Glide
12+
import com.bumptech.glide.request.target.CustomTarget
13+
import com.bumptech.glide.request.transition.Transition
514
import com.fmt.github.R
615
import com.fmt.github.base.activity.BaseDataBindActivity
716
import com.fmt.github.databinding.ActivityPhotoPreviewBinding
817
import com.fmt.github.ext.startActivity
18+
import com.fmt.github.utils.FileUtils
19+
import com.lxj.xpopup.XPopup
920
import kotlinx.android.synthetic.main.activity_photo_preview.*
21+
import java.io.File
22+
import java.io.FileOutputStream
1023

1124
class PhotoPreviewActivity : BaseDataBindActivity<ActivityPhotoPreviewBinding>() {
1225

26+
lateinit var mImageUrl: String
27+
1328
companion object {
1429
private const val IMAGE_URL = "image_url"
1530

@@ -24,9 +39,81 @@ class PhotoPreviewActivity : BaseDataBindActivity<ActivityPhotoPreviewBinding>()
2439
override fun getLayoutId(): Int = R.layout.activity_photo_preview
2540

2641
override fun initView() {
27-
mDataBind.url = intent.getStringExtra(IMAGE_URL)
42+
mImageUrl = intent.getStringExtra(IMAGE_URL)
43+
mDataBind.url = mImageUrl
44+
mPhotoView.setOnLongClickListener {
45+
showBottomDialog()
46+
false
47+
}
2848
mPhotoView.setOnClickListener {
2949
finish()
3050
}
3151
}
52+
53+
private fun showBottomDialog() {
54+
XPopup.Builder(this)
55+
.asBottomList(
56+
getString(R.string.options), arrayOf(
57+
getString(R.string.share_picture),
58+
getString(R.string.save_picture)
59+
)
60+
) { position, _ ->
61+
run {
62+
when (position) {
63+
0 -> {
64+
share()
65+
}
66+
1 -> {
67+
savePic {
68+
FileUtils.saveFile(it)
69+
}
70+
}
71+
}
72+
}
73+
74+
}.show()
75+
}
76+
77+
private fun savePic(handle: (Bitmap) -> Unit) {
78+
Glide.with(this@PhotoPreviewActivity).asBitmap().load(mImageUrl)
79+
.into(object : CustomTarget<Bitmap>() {
80+
override fun onResourceReady(
81+
resource: Bitmap,
82+
transition: Transition<in Bitmap>?
83+
) {
84+
handle(resource)
85+
}
86+
87+
override fun onLoadCleared(placeholder: Drawable?) {
88+
}
89+
})
90+
}
91+
92+
private fun share() {
93+
val file = File(getExternalFilesDir("img_download"), "${IMAGE_URL}.jpg")
94+
if (!file.exists()) {
95+
savePic { bitmap ->
96+
FileOutputStream(file).use { os ->
97+
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, os)
98+
}
99+
sharePic(file)
100+
}
101+
} else {
102+
sharePic(file)
103+
}
104+
}
105+
106+
private fun sharePic(file: File) {
107+
val picUri: Uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
108+
FileProvider.getUriForFile(this, "${packageName}.provider", file)
109+
} else {
110+
Uri.fromFile(file)
111+
}
112+
var shareIntent = Intent()
113+
shareIntent.action = Intent.ACTION_SEND //设置分享行为
114+
shareIntent.type = "image/*" //设置分享内容的类型
115+
shareIntent.putExtra(Intent.EXTRA_STREAM, picUri)
116+
shareIntent = Intent.createChooser(shareIntent, "")
117+
startActivity(shareIntent)
118+
}
32119
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.fmt.github.utils
2+
3+
import android.content.ContentResolver
4+
import android.content.ContentValues
5+
import android.content.Intent
6+
import android.graphics.Bitmap
7+
import android.net.Uri
8+
import android.os.Build
9+
import android.os.Environment
10+
import android.provider.MediaStore
11+
import com.fmt.github.AppContext
12+
import com.fmt.github.R
13+
import com.fmt.github.ext.successToast
14+
import java.io.*
15+
16+
object FileUtils {
17+
18+
/**
19+
* 保存图片到相册,适配Android Q以上
20+
*/
21+
fun saveFile(bitmap: Bitmap) {
22+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
23+
val fileName = "${System.currentTimeMillis()}.jpg"
24+
val values = ContentValues()
25+
values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
26+
values.put(MediaStore.MediaColumns.MIME_TYPE, "image/JPEG")
27+
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM + "/")
28+
val contentResolver: ContentResolver = AppContext.contentResolver
29+
val uri: Uri? =
30+
contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
31+
uri?.let {
32+
//若生成了uri,则表示该文件添加成功
33+
//使用流将内容写入该uri中即可
34+
contentResolver.openOutputStream(it).use { os ->
35+
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, os)
36+
successToast(R.string.save_picture_success)
37+
}
38+
}
39+
} else {
40+
val picDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
41+
val file = File(picDir, "${System.currentTimeMillis()}.jpg")
42+
FileOutputStream(file).use { os ->
43+
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, os)
44+
}
45+
if (file.exists()) {
46+
// 发送广播,通知刷新图库显示
47+
val intent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
48+
val uri = Uri.fromFile(file)
49+
intent.data = uri
50+
AppContext.sendBroadcast(intent)
51+
successToast(R.string.save_picture_success)
52+
}
53+
}
54+
}
55+
}

app/src/main/res/values/strings.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@
6363
<string name="retry_load">retry load</string>
6464
<string name="load_fail">Load Failed</string>
6565

66+
<string name="options">options</string>
67+
<string name="save_picture">save picture</string>
68+
<string name="save_picture_fail">save picture fail</string>
69+
<string name="save_picture_success">save picture success</string>
70+
<string name="save_picture_path">save picture success</string>
71+
<string name="share_picture">share picture</string>
72+
6673
<string name="no_browser_clients">There are no browser clients installed.</string>
6774

6875
<string-array name="github_glyph_strings">

app/src/main/res/xml/file_paths.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,9 @@
99
<external-files-path
1010
name="external-files-path"
1111
path="apk_download/"/>
12+
13+
<external-files-path
14+
name="external-files-path"
15+
path="img_download/"/>
1216
</paths>
1317
</resource>

common/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

common/build.gradle

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
apply plugin: 'com.android.library'
2+
apply plugin: 'kotlin-android'
3+
apply plugin: 'kotlin-android-extensions'
4+
5+
android {
6+
compileSdkVersion 30
7+
buildToolsVersion "30.0.2"
8+
9+
defaultConfig {
10+
minSdkVersion 21
11+
targetSdkVersion 30
12+
versionCode 1
13+
versionName "1.0"
14+
15+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
16+
consumerProguardFiles "consumer-rules.pro"
17+
}
18+
19+
buildTypes {
20+
release {
21+
minifyEnabled false
22+
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23+
}
24+
}
25+
}
26+
27+
dependencies {
28+
implementation fileTree(dir: "libs", include: ["*.jar"])
29+
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
30+
implementation 'androidx.core:core-ktx:1.1.0'
31+
implementation 'androidx.appcompat:appcompat:1.1.0'
32+
testImplementation 'junit:junit:4.12'
33+
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
34+
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
35+
36+
}

0 commit comments

Comments
 (0)