云豹相亲相册选择图片功能实现

发布来源:云豹科技
发布人:云豹科技
2022-12-08 10:11:31

云豹相亲交友是一款聊天交友类app,主打相亲直播和聊天交友,用户可以结识各种优质的异性朋友,进行直播视频等互动,也可以类似微信一样进行文字语音聊天。其中有很多选择图片的场景,比如设置个人头像,聊天发送图片,发布动态等,都用到了图片选择功能。下面介绍一下云豹相亲交友中图片选择功能的具体实现方式。


图片1.png图片2.png图片3.png


如上图所示,在选择图片的时候,会搜索相册中的全部图片,以网格列表呈现图片,可进行多选图片,选中的图片以选中的顺序进行标记。点击网格上的小图片时候,可以放大预览,底部有被选中的图片列表,预览的大图可进行拖拽,向下拖拽并且放手后,大图自动缩小返回到对应的小图的位置。

部分代码如下:


class ChooseImageVM : BaseViewModel() {
 
    private val mChooseImageFlowUtil = RefreshFlowUtil<ChooseImageBean>()
    private val mPreviewCheckListFlowUtil = RefreshFlowUtil<ChooseImageBean>()
    private val mCheckedCountFlow = MutableStateFlow("")
    private val mStringDone: String = WordUtil.getString(R.string.完成)
 
 
    fun activityCallback(
        onImageList: suspend (MutableList<ChooseImageBean>) -> Unit,
        onCheckedCount: (String) -> Unit
    ) = Callback(
        on(mChooseImageFlowUtil.mFlow) {
            onImageList(it.mList)
        },
        on(mCheckedCountFlow) {
            onCheckedCount(it)
        }
    )
 
    /**
     * 预览弹窗下方选中列表回调
     */
    fun previewDialogCallback(
        onPreviewCheckList: suspend (MutableList<ChooseImageBean>) -> Unit,
        onCheckedCount: (String) -> Unit
    ) = Callback(
        on(mPreviewCheckListFlowUtil.mFlow) {
            onPreviewCheckList(it.mList)
        },
        on(mCheckedCountFlow) {
            onCheckedCount(it)
        }
    )
 
    /**
     * 查询本地图片
     */
    fun queryImages(context: Context) {
        viewModelScope.launch {
            val permissions = applyPermission(
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
            )
            if (!permissions.isAllGranted()) return@launch
            val uriList = withContext(Dispatchers.Default) {
                val tempList = mutableListOf<Uri>()
                val cursor = context.contentResolver.query(
                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    null,
                    "mime_type=? or mime_type=? or mime_type=?",
                    arrayOf("image/jpeg", "image/png", "image/webp"),
                    "${MediaStore.MediaColumns.DATE_ADDED} desc"
                )
                if (cursor != null) {
                    while (cursor.moveToNext()) {
                        val id = cursor.getLong(cursor.getColumnIndex(MediaStore.MediaColumns._ID))
                        if (id > 0) {
                            val uri =
                                ContentUris.withAppendedId(
                                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                                    id
                                )
                            tempList.add(uri)
                        }
                    }
                    cursor.close()
                }
                tempList
            }
            val imageBeanList = uriList.mapIndexed { index, uri ->
                ChooseImageBean(mIndex = index, mUri = uri)
            } as MutableList<ChooseImageBean>
            mChooseImageFlowUtil.refresh(imageBeanList)
            mCheckedCountFlow.update {
                "(0/${mChooseImageFlowUtil.mData.size})$mStringDone"
            }
        }
    }
 
    fun getDataList(): MutableList<ChooseImageBean> {
        return mChooseImageFlowUtil.mData
    }
 
    fun getListItem(position: Int) = mChooseImageFlowUtil.getItem(position)
 
    /**
     * 切换选中和取消
     */
    fun toggleCheck(toggleBean: ChooseImageBean, maxCount: Int) {
        val choosed = if (toggleBean.mCheckedNumber > 0) {
            if (maxCount > 1) {
                mChooseImageFlowUtil.mData.forEach {
                    if (it.mCheckedNumber > toggleBean.mCheckedNumber) {
                        mChooseImageFlowUtil.setItem(
                            it.mIndex,
                            it.copy(mCheckedNumber = it.mCheckedNumber - 1)
                        )
                    }
                }
            }
            mChooseImageFlowUtil.setItem(
                toggleBean.mIndex,
                toggleBean.copy(mCheckedNumber = 0)
            )
            false
        } else {
            if (maxCount > 1) {
                var checkedCount = 0
                mChooseImageFlowUtil.mData.forEach {
                    if (it.mCheckedNumber > 0) {
                        checkedCount++
                    }
                }
                if (checkedCount >= maxCount) {
                    toast(R.string.已达到最大数量)
                    return
                }
                mChooseImageFlowUtil.setItem(
                    toggleBean.mIndex,
                    toggleBean.copy(mCheckedNumber = checkedCount + 1)
                )
            } else {
                for (bean in mChooseImageFlowUtil.mData) {
                    if (bean.mCheckedNumber > 0) {
                        mChooseImageFlowUtil.setItem(
                            bean.mIndex,
                            bean.copy(mCheckedNumber = 0)
                        )
                        break
                    }
                }
                mChooseImageFlowUtil.setItem(
                    toggleBean.mIndex,
                    toggleBean.copy(mCheckedNumber = 1)
                )
            }
            true
        }
        mChooseImageFlowUtil.update()
        val previewCheckList = mChooseImageFlowUtil.mData.filter {
            it.mCheckedNumber > 0
        } as MutableList<ChooseImageBean>
        if (maxCount > 1) {
            previewCheckList.sortBy { it.mCheckedNumber }
        }
        if (choosed) {
            setPreviewListChecked(previewCheckList, toggleBean.mIndex)
        }
        mPreviewCheckListFlowUtil.refresh(previewCheckList)
        mCheckedCountFlow.update {
            "(${previewCheckList.size}/$maxCount)$mStringDone"
        }
    }
 
    private fun setPreviewListChecked(
        previewCheckList: MutableList<ChooseImageBean>,
        chooseIndex: Int
    ) {
        for (i in 0 until previewCheckList.size) {
            val bean = previewCheckList[i]
            if (bean.mIndex == chooseIndex) {
                if (!bean.mPreviewListChecked) {
                    previewCheckList[i] = bean.copy(mPreviewListChecked = true)
                }
            } else {
                if (bean.mPreviewListChecked) {
                    previewCheckList[i] = bean.copy(mPreviewListChecked = false)
                }
            }
        }
    }
 
    fun setPreviewListChecked(chooseIndex: Int) {
        setPreviewListChecked(mPreviewCheckListFlowUtil.mData, chooseIndex)
        mPreviewCheckListFlowUtil.update()
    }
}
class ChooseImagePreviewDialog :
    BaseDialog<ChooseImagePreviewDialogBinding>() {
 
    val mVM by activityViewModels<ChooseImageVM>()
    var mGetBackTargetView: ((Any?) -> View?)? = null
    var mEnterPageIndex = 0
    var mMaxCount = 1
    private var mPageSize = 0
    private val mTopHeight = ScreenDimenUtil.sIntance.statusBarHeight + DpUtil.dp2px(40)
    private val mBottomHeight = DpUtil.dp2px(126)
    private var mDrawableCheckOutline: Drawable? = null
    private var mDrawableCheckFill: Drawable? = null
 
 
    override fun getStyle() = R.style.dialog
 
    override fun cancelable() = true
 
    override fun setWindowAttributes(window: Window) {
        val params = window.attributes
        window.decorView.systemUiVisibility = (
                View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                        or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
        window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            params.layoutInDisplayCutoutMode =
                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            params.layoutInDisplayCutoutMode =
                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
        }
        params.width = WindowManager.LayoutParams.MATCH_PARENT
        params.height = WindowManager.LayoutParams.MATCH_PARENT
        window.attributes = params
    }
 
    override fun setUp() {
        mPageSize = mVM.getDataList().size
        mDrawableCheckOutline =
            ContextCompat.getDrawable(mContext, R.drawable.choose_image_check_outline)
        mDrawableCheckFill = ContextCompat.getDrawable(mContext, R.drawable.choose_image_check_fill)
        val viewPagerAdapter = ChooseImagePreviewPageAdapter(
            mContext,
            mVM.getDataList(),
            mEnterPageIndex,
            object : DragBackImageView.Callback {
                override fun onEnterAnimCompleted() {
                    mVB.apply {
                        groupTop.animate().apply {
                            duration = 200
                            translationY(0f)
                        }.start()
                        groupBottom.animate().apply {
                            duration = 200
                            translationY(0f)
                        }.start()
                    }
                }
 
                override fun onMoveStart() {
                    mVB.apply {
                        groupTop.animate().apply {
                            duration = 200
                            translationY(-mTopHeight)
                        }.start()
                        groupBottom.animate().apply {
                            duration = 200
                            translationY(mBottomHeight)
                        }.start()
                    }
                }
 
                override fun onMoveCancel() {
                    mVB.apply {
                        groupTop.animate().apply {
                            duration = 200
                            translationY(0f)
                        }.start()
                        groupBottom.animate().apply {
                            duration = 200
                            translationY(0f)
                        }.start()
                    }
                }
 
                override fun onBackAnimCompleted() {
                    dismiss()
                }
 
                override fun getBackTargetView(backTag: Any?): View? {
                    return mGetBackTargetView?.invoke(backTag)
                }
            }
        )
        val previewListAdapter = ChooseImagePreviewListAdapter(mContext) {
            mVB.viewPager.setCurrentItem(it.mIndex, false)
        }
        mVB.apply {
            btnChoose.setOnClickListener {
                mVM.getListItem(viewPager.currentItem)?.let {
                    mVM.toggleCheck(it,mMaxCount)
                }
                val bean = mVM.getListItem(viewPager.currentItem)
                imgCheck.setImageDrawable(
                    if (bean != null && bean.mCheckedNumber > 0) {
                        mDrawableCheckFill
                    } else {
                        mDrawableCheckOutline
                    }
                )
            }
            groupTop.translationY = -mTopHeight
            groupBottom.translationY = mBottomHeight
            title.setText("${mEnterPageIndex + 1}/$mPageSize")
            viewPager.apply {
                registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
                    override fun onPageSelected(position: Int) {
                        title.setText("${position + 1}/$mPageSize")
                        val bean = mVM.getListItem(viewPager.currentItem)
                        imgCheck.setImageDrawable(
                            if (bean != null && bean.mCheckedNumber > 0) {
                                mDrawableCheckFill
                            } else {
                                mDrawableCheckOutline
                            }
                        )
                        mVM.setPreviewListChecked(position)
                    }
                })
                offscreenPageLimit = 1
                adapter = viewPagerAdapter
                setCurrentItem(mEnterPageIndex, false)
            }
            recyclerView.apply {
                layoutManager = LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false)
                adapter = previewListAdapter
            }
        }
        mVM.previewDialogCallback(
            onPreviewCheckList = {
                previewListAdapter.refreshData(it)
                val checkedPosition = previewListAdapter.getCheckedPosition()
                if (checkedPosition > -1) {
                    mVB.recyclerView.smoothScrollToPosition(checkedPosition)
                }
            },
            onCheckedCount = {
                mVB.btnDone.text = it
            }
        ).register(this)
    }
}


这样就实现了图片选择的功能。

声明:以上内容为云豹科技作者本人原创,未经作者本人同意,禁止转载,否则将追究相关法律责任www.yunbaokj.com

声明:
以上内容为云豹科技作者本人原创,未经作者本人同意,禁止转载,否则将追究相关法律责任
立即查看