bg上传 初步

This commit is contained in:
renhaoting 2025-11-05 15:25:22 +08:00
parent 52cc3a4cf2
commit a1f5a40ba5
12 changed files with 639 additions and 62 deletions

View File

@ -1,20 +1,15 @@
package com.remax.visualnovel.entity.response
import android.net.Uri
import com.remax.visualnovel.entity.model.base.BasePhoto
/**
* Created by HJW on 2025/8/18
*/
data class ChatBackground(
var backgroundId: Int? = 0,
var imgUrl: String? = "",
var imageId: Long? = 0L,
var imageUrl: String? = "",
var localUri: Uri? = null,
var isDefault: Boolean = false,
var select: Boolean = false,
var isSelected: Boolean? = null,
var deletable: Boolean = false,
var isUploadLocalItem: Boolean = false
) : BasePhoto() {
override fun paramId(): Long {
return imgUrl.hashCode().toLong()
}
}
var isSelected: Boolean = false,
var isCustomBg: Boolean = false,
) : ChatBackgroundBase()

View File

@ -0,0 +1,9 @@
package com.remax.visualnovel.entity.response
import android.net.Uri
import com.remax.visualnovel.entity.model.base.BasePhoto
abstract class ChatBackgroundBase(
)

View File

@ -0,0 +1,10 @@
package com.remax.visualnovel.entity.response
import android.net.Uri
data class ChatBackgroundUpload(
var imageId: Long? = 0L,
var imageUrl: String? = "",
var localUri: Uri? = null,
) : ChatBackgroundBase()

View File

@ -2,6 +2,7 @@ package com.remax.visualnovel.extension.glide
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.net.Uri
import android.view.View
import android.widget.ImageView
import android.widget.TextView
@ -112,6 +113,15 @@ fun ImageView.load(url: String?) {
.into(this)
}
fun ImageView.load(uri: Uri) {
visibility = View.VISIBLE
Glide.with(context)
.load(uri)
.centerCrop()
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
.into(this)
}
fun TextView.loadNinePatch(nineImageUrl: String?) {
Glide.with(context)
.asBitmap()

View File

@ -11,6 +11,7 @@ import androidx.core.graphics.toColorInt
import com.remax.visualnovel.R
import com.remax.visualnovel.databinding.LayoutChatMenuViewBinding
import com.remax.visualnovel.entity.response.ChatBackground
import com.remax.visualnovel.entity.response.ChatBackgroundUpload
import com.remax.visualnovel.entity.response.ChatBubble
import com.remax.visualnovel.entity.response.ChatHistory
import com.remax.visualnovel.entity.response.ChatMode
@ -291,36 +292,30 @@ class ChatSettingView @JvmOverloads constructor(
fun initBackgroundSelectView() {
val items = listOf(
ChatBackground(
backgroundId = 1,
imgUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png",
imageId = 1,
imageUrl = "https://vsn.s3.cn-north-1.amazonaws.com.cn/coverImage/fe8e3c7b-5b22-40f4-bacc-0183888c5149_test.png"
),
ChatBackground(
backgroundId = 1,
imgUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png",
imageId = 1,
imageUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png"
),
ChatBackground(
backgroundId = 1,
imgUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png",
imageId = 1,
imageUrl = "https://vsn.s3.cn-north-1.amazonaws.com.cn/coverImage/fe8e3c7b-5b22-40f4-bacc-0183888c5149_test.png"
),
ChatBackground(
backgroundId = 1,
imgUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png",
imageId = 1,
imageUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png"
),
ChatBackground(
backgroundId = 1,
imgUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png",
imageId = 1,
imageUrl = "https://vsn.s3.cn-north-1.amazonaws.com.cn/coverImage/fe8e3c7b-5b22-40f4-bacc-0183888c5149_test.png"
),
ChatBackground(
backgroundId = 1,
imgUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png",
imageId = 1,
imageUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png"
),
ChatBackground(
backgroundId = 1,
imgUrl = "https://cdhrss.chengdu.gov.cn/cdrsj/xhtml/images/2022_logo.png",
deletable = true
),
ChatBackground(
isUploadLocalItem = true
ChatBackgroundUpload(
)
)

View File

@ -8,6 +8,7 @@ import android.widget.LinearLayout
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import com.drake.brv.annotaion.DividerOrientation
import com.drake.brv.utils.addModels
import com.drake.brv.utils.bindingAdapter
import com.drake.brv.utils.divider
import com.drake.brv.utils.grid
@ -17,13 +18,28 @@ import com.remax.visualnovel.R
import com.remax.visualnovel.databinding.LayoutItemSettingBackgroundBinding
import com.remax.visualnovel.databinding.LayoutSettingBgSubViewBinding
import com.remax.visualnovel.entity.response.ChatBackground
import com.remax.visualnovel.entity.response.ChatBackgroundBase
import com.remax.visualnovel.entity.response.ChatBackgroundUpload
import com.remax.visualnovel.extension.glide.load
import com.remax.visualnovel.extension.toast
import com.remax.visualnovel.utils.imagepick.EpalPickerPresenter
import com.remax.visualnovel.widget.imagepicker.ImagePicker
import com.remax.visualnovel.widget.imagepicker.bean.ImageItem
import com.remax.visualnovel.widget.imagepicker.bean.MimeType
import com.remax.visualnovel.widget.imagepicker.bean.PickerError
import com.remax.visualnovel.widget.imagepicker.bean.SelectMode
import com.remax.visualnovel.widget.imagepicker.data.OnImagePickCompleteListener2
import com.remax.visualnovel.widget.imageviewer.utils.activity
class ExpandBackgroundSubView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : android.widget.LinearLayout(context, attrs, defStyleAttr) {
private lateinit var items: List<ChatBackground>
) : LinearLayout(context, attrs, defStyleAttr) {
private lateinit var items: List<ChatBackgroundBase>
private var mBinding: LayoutSettingBgSubViewBinding
@ -42,36 +58,104 @@ class ExpandBackgroundSubView @JvmOverloads constructor(
orientation = DividerOrientation.VERTICAL
}.setup {
addType<ChatBackground>(R.layout.layout_item_setting_background)
addType<ChatBackgroundUpload>(R.layout.layout_item_setting_background_upload)
onClick(R.id.root) {
when (val item = getModel<Any>(it)) {
is ChatBackground -> {
val chatBackground = getModel<ChatBackground>()
if (!chatBackground.select) {
if (!chatBackground.isSelected) {
itemsRv.bindingAdapter.models?.filterIsInstance<ChatBackground>()?.forEach { item ->
item.select = item == chatBackground
item.isSelected = item == chatBackground
}
itemsRv.bindingAdapter.notifyDataSetChanged()
}
}
is ChatBackgroundUpload -> {
selectCustomBg()
}
}
/*when (itemViewType) {
R.layout.layout_item_setting_background -> {
}
R.layout.layout_item_setting_background_upload -> {
selectCustomBg()
}
}*/
}
onBind {
when (itemViewType) {
R.layout.layout_item_setting_background -> {
val item = getModel<ChatBackground>()
with(getBinding<LayoutItemSettingBackgroundBinding>()) {
if (!item.imgUrl.isNullOrEmpty()) {
//ivBackgroundSrc.load(item.imgUrl)
if (!item.imageUrl.isNullOrEmpty()) {
ivBackgroundSrc.load(item.imageUrl)
} else if (item.localUri != null) {
ivBackgroundSrc.load(item.localUri!!)
}
ivDel.visibility = if (item.deletable) VISIBLE else GONE
ivUpload.isVisible = item.isUploadLocalItem
ivBackgroundSrc.isVisible = !item.isUploadLocalItem
ivDel.visibility = if (item.isCustomBg) VISIBLE else GONE
ivBackgroundSrc.isVisible = item.isSelected
}
}
R.layout.layout_item_setting_background_upload -> {
val item = getModel<ChatBackgroundUpload>()
}
}
}
}
}
fun setItems(newItems: List<ChatBackground>) {
fun setItems(newItems: List<ChatBackgroundBase>) {
items = newItems
mBinding.itemsRv.models = items
}
private fun selectCustomBg(showCamera: Boolean = true) {
ImagePicker.withMulti(EpalPickerPresenter())
.setMaxCount(1)
.setSelectMode(SelectMode.MODE_SINGLE)
.setColumnCount(3)
.mimeTypes(MimeType.ofImage())
.filterMimeTypes(MimeType.GIF)
.showCamera(showCamera)
.setPreview(true)
.setSinglePickImageOrVideoType(true)
.pick(activity, object : OnImagePickCompleteListener2 {
override fun onPickFailed(error: PickerError?) {
activity?.toast(error?.message)
}
override fun onImagePickComplete(items: ArrayList<ImageItem>?) {
appendCustomBg(items)
uploadImageAndRequest(items)
}
})
}
private fun appendCustomBg(items: ArrayList<ImageItem>?) {
val customBgList = items?.map { imageItem ->
ChatBackground(
imageId = imageItem.id,
imageUrl = imageItem.path,
localUri = imageItem.uri
)
}
mBinding.itemsRv.addModels(customBgList)
}
private fun uploadImageAndRequest(items: ArrayList<ImageItem>?) {
// TODO
}
}

View File

@ -0,0 +1,272 @@
package com.remax.visualnovel.utils.imagepick
import android.app.Activity
import android.content.Context
import android.content.DialogInterface
import android.graphics.drawable.Drawable
import android.view.View
import android.widget.ImageView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.DecodeFormat
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.load.resource.gif.GifDrawable
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target
import com.remax.visualnovel.R
import com.remax.visualnovel.app.widget.LoadingDialog
import com.remax.visualnovel.extension.findActivityContext
import com.remax.visualnovel.extension.toast
import com.remax.visualnovel.widget.imagepicker.adapter.PickerItemAdapter
import com.remax.visualnovel.widget.imagepicker.bean.ImageItem
import com.remax.visualnovel.widget.imagepicker.bean.selectconfig.BaseSelectConfig
import com.remax.visualnovel.widget.imagepicker.data.ICameraExecutor
import com.remax.visualnovel.widget.imagepicker.data.IReloadExecutor
import com.remax.visualnovel.widget.imagepicker.data.ProgressSceneEnum
import com.remax.visualnovel.widget.imagepicker.presenter.IPickerPresenter
import com.remax.visualnovel.widget.imagepicker.views.PickerUiConfig
import com.remax.visualnovel.widget.imagepicker.views.PickerUiProvider
import com.remax.visualnovel.widget.imagepicker.views.base.PickerControllerView
import com.remax.visualnovel.widget.imagepicker.views.base.PickerFolderItemView
import com.remax.visualnovel.widget.imagepicker.views.base.SingleCropControllerView
import com.remax.visualnovel.widget.imagepicker.views.wrapper.BottomBar
import com.remax.visualnovel.widget.imagepicker.views.wrapper.FolderItemView
import com.remax.visualnovel.widget.imagepicker.views.wrapper.TitleBar
import com.remax.visualnovel.widget.uitoken.handleUIToken
import java.util.*
/**
* Created by HJW on 2020/10/13
*/
class EpalPickerPresenter(private val isAlbum: Boolean = false) : IPickerPresenter {
/**
* 提示
*
* @param context 上下文
* @param msg 提示文本
*/
override fun tip(context: Context?, msg: String?) {
context?.let {
if (!msg.isNullOrBlank()) {
it.toast(msg)
}
}
}
/**
* 选择超过数量限制提示
*
* @param context 上下文
* @param maxCount 最大数量
*/
override fun overMaxCountTip(context: Context?, maxCount: Int) {
tip(context, String.format(context?.getString(R.string.upload_up_to_images) ?: "", maxCount))
}
/**
* 显示loading加载框注意需要调用show方法
*
* @param activity 启动加载框的activity
* @param progressSceneEnum {@link ProgressSceneEnum}
*
* <p>
* 当progressSceneEnum==当ProgressSceneEnum.loadMediaItem 代表在加载媒体文件时显示加载框
* 目前框架内规定当文件夹内媒体文件少于1000时强制不显示加载框大于1000时才会执行此方法
* </p>
* <p>
* 当progressSceneEnum==当ProgressSceneEnum.crop 代表是剪裁页面的加载框
* </p>
* @return DialogInterface 对象用于关闭加载框返回null代表不显示加载框
*/
override fun showProgressDialog(activity: Activity?, progressSceneEnum: ProgressSceneEnum?): DialogInterface {
return LoadingDialog().build(activity!!).getDialog().thisShow()
}
/**
* 拦截选择器取消操作用于弹出二次确认框
*
* @param activity 当前选择器页面
* @param selectedList 当前已经选择的文件列表
* @return true:则拦截选择器取消 false不处理选择器取消操作
*/
override fun interceptPickerCancel(activity: Activity?, selectedList: ArrayList<ImageItem>?): Boolean {
return false
}
/**
* <p>
* 图片点击事件拦截如果返回true则不会执行选中操纵如果要拦截此事件并且要执行选中
* 请调用如下代码
* <p>
* adapter.preformCheckItem()
* <p>
* <p>
* 此方法可以用来跳转到任意一个页面比如自定义的预览
*
* @param activity 上下文
* @param imageItem 当前图片
* @param selectImageList 当前选中列表
* @param allSetImageList 当前文件夹所有图片
* @param selectConfig 选择器配置项如果是微信样式则selectConfig继承自MultiSelectConfig
* 如果是小红书剪裁样式则继承自CropSelectConfig
* @param adapter 当前列表适配器用于刷新数据
* @param isClickCheckBox 是否点击item右上角的选中框
* @param reloadExecutor 刷新器
* @return 是否拦截
*/
override fun interceptItemClick(
activity: Activity?,
imageItem: ImageItem?,
selectImageList: ArrayList<ImageItem>?,
allSetImageList: ArrayList<ImageItem>?,
selectConfig: BaseSelectConfig?,
adapter: PickerItemAdapter?,
isClickCheckBox: Boolean,
reloadExecutor: IReloadExecutor?
): Boolean {
return false
}
/**
* 拍照点击事件拦截
*
* @param activity 当前activity
* @param takePhoto 拍照接口
* @return 是否拦截
*/
override fun interceptCameraClick(activity: Activity?, takePhoto: ICameraExecutor?): Boolean {
return false
}
/**
* 图片加载在安卓10上外部存储的图片路径只能用Uri加载私有目录的图片可以用绝对路径加载
* 所以这个方法务必需要区分有uri和无uri的情况
* 一般媒体库直接扫描出来的图片是含有uri的而剪裁生成的图片保存在私有目录中因此没有uri只有绝对路径
* 所以这里需要做一个兼容处理
*
* @param view imageView
* @param item 图片信息
* @param size 加载尺寸
* @param isThumbnail 是否是缩略图
*/
override fun displayImage(view: View?, imageItem: ImageItem?, size: Int, isThumbnail: Boolean) {
imageItem?.let { item ->
view?.let { v ->
(v.context.findActivityContext() as? Activity)?.also { act ->
if (!act.isDestroyed) {
val loadPath = if (item.uri != null) item.uri.toString() else item.path
Glide.with(act).load(loadPath)
.apply(RequestOptions().format(if (isThumbnail) DecodeFormat.PREFER_RGB_565 else DecodeFormat.PREFER_ARGB_8888))
// .override(if (isThumbnail) size else Target.SIZE_ORIGINAL)
.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>, isFirstResource: Boolean): Boolean {
return false
}
override fun onResourceReady(
resource: Drawable,
model: Any,
target: Target<Drawable>?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
return if (resource is GifDrawable) {
if (item.isGif || loadPath.toString().substring(loadPath.toString().lastIndexOf(".") + 1) == "gif") {
false
} else {
if (!loadPath.startsWith("http")) {
(v as ImageView).setImageBitmap(resource.firstFrame)
true
} else {
false
}
}
} else {
false
}
}
})
.into(view as ImageView)
}
}
}
}
}
/**
* 拦截选择器完成按钮点击事件
*
* @param activity 当前选择器activity
* @param selectedList 已选中的列表
* @return true:则拦截选择器完成回调 false执行默认的选择器回调
*/
override fun interceptPickerCompleteClick(activity: Activity?, selectedList: ArrayList<ImageItem>?, selectConfig: BaseSelectConfig?): Boolean {
return false
}
/**
* 设置自定义ui显示样式不可返回null
* 该方法返回一个PickerUiConfig对象
*
* <p>
* 该对象可以配置如下信息
* 1.主题色
* 2.相关页面背景色
* 3.选择器标题栏底部栏item文件夹列表item预览页面剪裁页面的定制
* <p>
* <p>
* 详细使用方法参考 (@link https://github.com/yangpeixing/YImagePicker/blob/master/YPX_ImagePicker_androidx/app/src/main/java/com/ypx/imagepickerdemo/style/WeChatPresenter.java)
*
* @param context 上下文
* @return PickerUiConfig
*/
override fun getUiConfig(context: Context?): PickerUiConfig {
val uiConfig = PickerUiConfig()
with(uiConfig) {
//设置主题色
themeColor = context?.handleUIToken(R.string.color_primary_normal)?.color ?: 0
//设置是否显示状态栏
isShowStatusBar = true
//设置状态栏颜色
statusBarColor = context?.handleUIToken(R.string.color_background_default)?.color ?: 0
//设置选择器背景
pickerBackgroundColor = context?.handleUIToken(R.string.color_background_default)?.color ?: 0
//设置单图剪裁背景色
singleCropBackgroundColor = context?.handleUIToken(R.string.color_background_default)?.color ?: 0
//设置预览页面背景色
previewBackgroundColor = context?.handleUIToken(R.string.color_background_default)?.color ?: 0
//设置选择器文件夹打开方向
folderListOpenDirection = PickerUiConfig.DIRECTION_TOP
//设置文件夹列表距离顶部/底部边距
folderListOpenMaxMargin = 120
//设置小红书剪裁区域的背景色
cropViewBackgroundColor = context?.handleUIToken(R.string.color_background_default)?.color ?: 0
pickerUiProvider = object : PickerUiProvider() {
override fun getTitleBar(context: Context?): PickerControllerView {
return TitleBar(context)
}
override fun getFolderItemView(context: Context?): PickerFolderItemView {
return FolderItemView(context)
}
override fun getSingleCropControllerView(context: Context?): SingleCropControllerView {
return com.remax.visualnovel.widget.imagepicker.views.wrapper.SingleCropControllerView(context)
}
override fun getBottomBar(context: Context?): PickerControllerView {
return BottomBar(context, isAlbum)
}
override fun getPreviewControllerView(context: Context): com.remax.visualnovel.widget.imagepicker.views.wrapper.PreviewControllerView {
return super.getPreviewControllerView(context)
}
}
}
return uiConfig
}
}

View File

@ -0,0 +1,178 @@
package com.remax.visualnovel.utils.imagepick
import android.app.Activity
import com.remax.visualnovel.extension.toast
import com.remax.visualnovel.manager.login.LoginManager
import com.remax.visualnovel.utils.spannablex.utils.dp
import com.remax.visualnovel.widget.imagepicker.ImagePicker
import com.remax.visualnovel.widget.imagepicker.bean.ImageItem
import com.remax.visualnovel.widget.imagepicker.bean.MimeType
import com.remax.visualnovel.widget.imagepicker.bean.PickerError
import com.remax.visualnovel.widget.imagepicker.bean.SelectMode
import com.remax.visualnovel.widget.imagepicker.bean.selectconfig.CropConfig
import com.remax.visualnovel.widget.imagepicker.data.OnImagePickCompleteListener
import com.remax.visualnovel.widget.imagepicker.data.OnImagePickCompleteListener2
/**
* Created by HJW on 2020/10/13
*/
class ImagePickUtils {
companion object {
/**
* 选择单张图片无剪裁
*/
fun pickOneWithoutCrop(activity: Activity, showCamera: Boolean = true, imagePickCompleteListener: OnImagePickCompleteListener) {
ImagePicker.withMulti(EpalPickerPresenter())
.setMaxCount(1)
//设置单选模式当maxCount==1时可执行单选下次选中会取消上一次选中
.setSelectMode(SelectMode.MODE_SINGLE)
.setColumnCount(3)
.mimeTypes(MimeType.ofImage())
//设置需要过滤掉加载的文件类型
.filterMimeTypes(MimeType.GIF)
.showCamera(showCamera)
.setPreview(true)
//设置图片和视频单一类型选择
.setSinglePickImageOrVideoType(true)
.pick(activity, object : OnImagePickCompleteListener2 {
override fun onPickFailed(error: PickerError?) {
activity.toast(error?.message)
}
override fun onImagePickComplete(items: ArrayList<ImageItem>?) {
imagePickCompleteListener.onImagePickComplete(items)
}
})
}
/**
* 用户选择头像
* VIP才可以选择gif图
*/
fun pickHeadWithCrop(activity: Activity, margin: Int? = null, cropTaskFrame: Int? = null, onImagePickCompleteListener: OnImagePickCompleteListener) {
val mimeTypes = mutableSetOf(MimeType.JPEG, MimeType.PNG, MimeType.BMP, MimeType.WEBP)
ImagePicker.withMulti(EpalPickerPresenter())
.setMaxCount(1)
//设置单选模式当maxCount==1时可执行单选下次选中会取消上一次选中
.setSelectMode(SelectMode.MODE_SINGLE)
.setColumnCount(3)
.mimeTypes(mimeTypes)
.showCamera(true)
.setPreview(true)
//设置图片和视频单一类型选择
.setSinglePickImageOrVideoType(true)
.cropAsCircle()
.cropRectMinMargin(margin ?: 48.dp)
.setCropTaskFrame(cropTaskFrame ?: 0)
//设置剪裁模式,留白或充满 CropConfig.STYLE_GAP 或 CropConfig.STYLE_FILL
.cropStyle(CropConfig.STYLE_FILL)
//x y 比例
.setCropRatio(1, 1)
//剪裁完成的图片是否保存在DCIM目录下
//true存储在DCIM下 false存储在 data/包名/files/imagePicker/ 目录下
.cropSaveInDCIM(false)
.crop(activity, object : OnImagePickCompleteListener2 {
override fun onPickFailed(error: PickerError?) {
activity.toast(error?.message)
}
override fun onImagePickComplete(items: ArrayList<ImageItem>?) {
onImagePickCompleteListener.onImagePickComplete(items)
}
})
}
/**
* 选择单张图片有剪裁,无gif,默认1 1
*/
fun pickOneWithCrop(
activity: Activity,
x: Int = 1,
y: Int = 1,
onImagePickCompleteListener: OnImagePickCompleteListener,
showCamera: Boolean = true
) {
ImagePicker.withMulti(EpalPickerPresenter())
.setMaxCount(1)
//设置单选模式当maxCount==1时可执行单选下次选中会取消上一次选中
.setSelectMode(SelectMode.MODE_SINGLE)
.setColumnCount(3)
.mimeTypes(MimeType.ofImage())
//设置需要过滤掉加载的文件类型
.filterMimeTypes(MimeType.GIF)
.showCamera(showCamera)
.setPreview(true)
//设置图片和视频单一类型选择z
.setSinglePickImageOrVideoType(true)
.cropRectMinMargin(48.dp)
//设置剪裁模式,留白或充满 CropConfig.STYLE_GAP 或 CropConfig.STYLE_FILL
.cropStyle(CropConfig.STYLE_FILL)
//x y 比例
.setCropRatio(x, y)
//剪裁完成的图片是否保存在DCIM目录下
//true存储在DCIM下 false存储在 data/包名/files/imagePicker/ 目录下
.cropSaveInDCIM(false)
.crop(activity, object : OnImagePickCompleteListener2 {
override fun onPickFailed(error: PickerError?) {
activity.toast(error?.message)
}
override fun onImagePickComplete(items: ArrayList<ImageItem>?) {
onImagePickCompleteListener.onImagePickComplete(items)
}
})
}
/**
* 直接剪裁头像
* UI圆形显示输出是11
*/
fun cropCircleImage(activity: Activity, imageUrl: String, onImagePickCompleteListener: OnImagePickCompleteListener) {
ImagePicker.crop(activity, EpalPickerPresenter(), CropConfig().apply {
this.cropStyle = CropConfig.STYLE_FILL
isCircle = true
saveInDCIM(false)
cropRectMargin = 48.dp
}, imageUrl, onImagePickCompleteListener)
}
/**
* 选择多张图片无剪裁
*/
fun pickMaxCount(
activity: Activity,
maxCount: Int,
onImagePickCompleteListener: OnImagePickCompleteListener,
showCamera: Boolean = false,
filterGif: Boolean = true,
isAlbum: Boolean = false
) {
val presenter = EpalPickerPresenter(isAlbum)
ImagePicker.withMulti(presenter)
.setMaxCount(maxCount)
.setColumnCount(3)
.mimeTypes(MimeType.ofImage())
//设置需要过滤掉加载的文件类型
.filterMimeTypes(if (filterGif) MimeType.GIF else null)
.setPreview(true)
.showCamera(showCamera)
//设置图片和视频单一类型选择
.setSinglePickImageOrVideoType(true)
.pick(activity, object : OnImagePickCompleteListener2 {
override fun onPickFailed(error: PickerError?) {
activity.toast(error?.message)
}
override fun onImagePickComplete(items: ArrayList<ImageItem>?) {
onImagePickCompleteListener.onImagePickComplete(items)
}
})
}
}
}

View File

@ -51,7 +51,7 @@ class MyImageLoader : ImageLoader {
}
is ChatBackground -> {
data.imgUrl
data.imageUrl
}
is CustomAlbumData -> {

View File

@ -46,17 +46,6 @@
/>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_upload"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/icon_upload_image"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_selected_indi"
android:layout_width="wrap_content"

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/dp_10">
<com.remax.visualnovel.widget.roundedimageview.RoundedImageView
android:id="@+id/iv_background_src"
android:layout_width="0dp"
android:layout_height="0dp"
android:src="@color/grayf3"
android:scaleType="centerCrop"
app:riv_corner_radius="@dimen/dp_10"
app:layout_constraintDimensionRatio="h,87:116"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_upload"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/icon_upload_image"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -193,6 +193,8 @@
<color name="gray9">#ff999999</color>
<color name="grayf6">#fff6f6f6</color>
<color name="gray28">#ff282828</color>
<color name="grayf3">#fff3f4ff</color>
<color name="red_ff3b30">#ffff3b30</color>