美文网首页
Android 图片上传九宫格(添加,删除,预览)

Android 图片上传九宫格(添加,删除,预览)

作者: 没有了遇见 | 来源:发表于2022-01-04 13:07 被阅读0次

    越来越多的功能需要图片上传,所以封装了一个图片选取,展示的九宫格控件.包含了添加,删除,以及预览(为方便自定义,预览只提供点击方式外部自定义预览实现)的功能


    效果.gif

    思路:

    1. 自定义ViewGroup 包含RecycleView 实现九宫格
    2. 自定义属性 设置展示的行数,最大添加的个数设置AddItem 图片的展示样式,以及设置关闭按钮和错误页展示的央视
    3. 利用RecycleView 的 GridLayoutManager 设置九宫格展示
    4. 根据逻辑需要在RecyclerView.Adapter中动态添加图片和Add页面的两种不同他的Item
    5. 根据添加数据有没有AddItem类型动态处理数据

    实现:

    1.attrs.xml自定义属性

        <declare-styleable name="AddImagesStyle">
    
            <!--限制每行展示的个数-->
            <attr name="column_nums" format="integer"/>
            <!--限制添加的个数-->
            <attr name="add_limit_nums" format="integer"/>
          
            <!--添加Item图片资源-->
            <attr name="add_imgs" format="reference"/>
            <!--删除按钮的图片资源-->
            <attr name="add_close_imgs" format="reference"/>
            <!--错误展示的图片资源-->
            <attr name="add_err_imgs" format="reference"/>
          
        </declare-styleable>
    

    2.九宫格RecycleView的Adapter

    package com.wu.add
    
    import android.content.Context
    import android.util.DisplayMetrics
    import android.view.LayoutInflater
    import android.view.View
    import android.view.ViewGroup
    import android.view.WindowManager
    import android.widget.RelativeLayout
    import androidx.databinding.DataBindingUtil
    import androidx.recyclerview.widget.RecyclerView
    import com.bumptech.glide.Glide
    import com.bumptech.glide.request.RequestOptions
    import com.wkq.lib_base.adapter.AddImagesViewHolder
    import com.wu.add.databinding.ItemAddImagesBinding
    
    /**
     *
     * 作者:吴奎庆
     *
     * 时间:2021/12/30
     *
     * 用途:
     */
    
    
    class AddImagesAdapter(
        mContext: Context,
        limtNum: Int,
        addImgs: Int,
        addCloseImgs: Int,
        addErrImgs: Int,
        addLimitNums: Int
    ) :
        RecyclerView.Adapter<RecyclerView.ViewHolder>() {
        var mContext: Context
        var limtNum = 5
        var addImgs = -1
        var addCloseImgs = -1
        var addErrImgs = -1
        var addLimitNums = 9
        var addImages = ArrayList<AddImagesInfo>()
    
        init {
            this.mContext = mContext
            this.limtNum = limtNum
            this.addCloseImgs = addCloseImgs
            this.addImgs = addImgs
            this.addErrImgs = addErrImgs
            this.addLimitNums = addLimitNums
        }
    
        var listener: OnAddClickListener? = null
    
        fun setOnAddListener(listener: OnAddClickListener) {
            this.listener = listener
        }
    
        fun getHeight(): Int {
            return (getScreenWidth(mContext)) / 5
        }
    
        private fun dip2px(context: Context, dp: Int): Int {
            val density = context.resources.displayMetrics.density
            return (dp * density + 0.5).toInt()
        }
    
        private fun getScreenWidth(context: Context): Int {
            val wm = context
                .getSystemService(Context.WINDOW_SERVICE) as WindowManager
            val outMetrics = DisplayMetrics()
            wm.defaultDisplay.getMetrics(outMetrics)
            return outMetrics.widthPixels
        }
    
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
            var viedataBinding: ItemAddImagesBinding =
                DataBindingUtil.inflate(
                    LayoutInflater.from(mContext),
                    R.layout.item_add_images,
                    parent,
                    false
                )
    
            var layout = RelativeLayout.LayoutParams(getHeight(), getHeight())
            layout.setMargins(dip2px(mContext,1), dip2px(mContext,1), dip2px(mContext,1), dip2px(mContext,1))
            viedataBinding.root.layoutParams = layout
    
            var dataBindingViewHolder: AddImagesViewHolder = AddImagesViewHolder(viedataBinding.root)
            dataBindingViewHolder.setBinding(viewBinding = viedataBinding)
            return dataBindingViewHolder
        }
    
    
        override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
            var ktHolder = holder as? AddImagesViewHolder
            var binding = ktHolder!!.getBinding() as ItemAddImagesBinding
            ktHolder?.getBinding()?.executePendingBindings()
            if (addImgs!=-1){
                binding!!.ivAdd.setBackgroundResource(addImgs)
            }else{
                binding!!.ivAdd.setBackgroundResource(R.drawable.iv_add_images_add)
            }
            if (addCloseImgs!=-1){
                binding!!.ivClose.setBackgroundResource(addCloseImgs)
            }else{
                binding!!.ivClose.setBackgroundResource(R.drawable.iv_add_img_close)
            }
    
    
            binding.rlClose.setOnClickListener {
                processDelete(getItem(position))
            }
    
            binding.rlAdd.setOnClickListener {
                if (listener != null) listener!!.onAddClick(binding.rlAdd, getItem(position))
            }
    
            binding.ivContent.setOnClickListener {
                if (listener != null) listener!!.onAddClick(binding.ivContent, getItem(position))
            }
    
            if (getItem(position)!!.type.equals("2")) {
                binding.ivContent.visibility = View.VISIBLE
                binding.rlClose.visibility = View.VISIBLE
                binding.rlAdd.visibility = View.GONE
                if (addErrImgs!=-1){
                 var requestOptions=   RequestOptions().error(addErrImgs)
                    Glide.with(mContext).load(getItem(position)!!.imgUrl).apply(requestOptions).into(binding.ivContent)
                }else{
                    var requestOptions=   RequestOptions().error(R.drawable.iv_add_err)
                    Glide.with(mContext).load(getItem(position)!!.imgUrl).apply(requestOptions).into(binding.ivContent)
                }
    
            } else {
                binding.ivContent.visibility = View.GONE
                binding.rlAdd.visibility = View.VISIBLE
                binding.rlClose.visibility = View.GONE
            }
    
        }
    
        private fun processDelete(item: AddImagesInfo?) {
            addImages.remove(item)
            if (!hasAdd()) {
                addItem(AddImagesInfo(R.drawable.iv_add_images_add, "1"))
            } else {
                notifyDataSetChanged()
            }
    
        }
    
        fun addItems(lists: List<AddImagesInfo>) {
            processData(lists)
        }
    
        fun addItem(info: AddImagesInfo) {
            addImages.add(info)
            notifyDataSetChanged()
        }
    
        fun getItems(): ArrayList<AddImagesInfo>? {
            if (this.addImages == null) this.addImages = ArrayList()
            return this.addImages
        }
    
        private fun processData(addDatas: List<AddImagesInfo>) {
            if (addDatas == null) return
    
            var newList = processEnd(getItems()!!)
            if (newList.size >= limtNum) return
            if (newList!!.size + addDatas.size < addLimitNums) {
                newList!!.addAll(addDatas)
                newList!!.add(AddImagesInfo("", "1"))
            } else {
                newList!!.addAll(addDatas.subList(0, addLimitNums - newList.size))
            }
            notifyDataSetChanged()
    
        }
    
        private fun processEnd(addDatas: ArrayList<AddImagesInfo>): ArrayList<AddImagesInfo> {
            if (addDatas == null) return addDatas
            var iterator = addDatas.iterator()
            while (iterator.hasNext()) {
                var info = iterator.next()
                if (info.type.equals("1")) iterator.remove()
            }
            return addDatas
        }
    
        private fun hasAdd(): Boolean {
            getItems()!!.forEach {
                if (it.type.equals("1")) {
                    return true
                }
            }
            return false
        }
    
    
        override fun getItemCount(): Int {
            return addImages.size
        }
    
        fun getItem(position: Int): AddImagesInfo? {
            if (addImages != null && position < addImages!!.size) {
                return this.addImages!!.get(position)
            }
            return null
        }
    
        interface OnAddClickListener {
            fun onAddClick(view: View?, item: AddImagesInfo?)
        }
    }
    

    3.自定义ViewGroup

    package com.wu.add
    
    import android.content.Context
    import android.util.AttributeSet
    import android.view.LayoutInflater
    import android.view.View
    import android.widget.FrameLayout
    import androidx.databinding.DataBindingUtil
    import androidx.recyclerview.widget.GridLayoutManager
    import com.wu.add.databinding.LayoutAddImagesBinding
    
    /**
     *
     * 作者:吴奎庆
     *
     * 时间:2021/12/30
     *
     * 用途: 九宫格动态添加图片
     */
    
    
    class AddImagesView @JvmOverloads constructor(
        mContext: Context,
        attrs: AttributeSet? = null,
        defStyleAttr: Int = 0
    ) : FrameLayout(mContext, attrs, defStyleAttr) {
        private var mContext: Context
        // 添加的图片资源
        private var addImgs = -1
        //关闭的图片资源
        private var addCloseImgs = -1
        //错误页的图片资源
        private var addErrImgs = -1
        //列数
        private var columnNums = 5
        //最大图片数
        private var add_limit_nums = 9
    
        private var mAdapter: AddImagesAdapter? = null
    
    
        init {
            this.mContext = mContext
            val tapeArray = mContext.obtainStyledAttributes(attrs, R.styleable.AddImagesStyle)
            addImgs = tapeArray.getResourceId(R.styleable.AddImagesStyle_add_imgs, -1)
            addCloseImgs = tapeArray.getResourceId(R.styleable.AddImagesStyle_add_close_imgs, -1)
            addErrImgs = tapeArray.getResourceId(R.styleable.AddImagesStyle_add_err_imgs, -1)
            columnNums = tapeArray.getInt(R.styleable.AddImagesStyle_column_nums, 5)
            add_limit_nums = tapeArray.getInt(R.styleable.AddImagesStyle_add_limit_nums, 9)
            initView()
        }
    
        var listener: AddImagesViewListener? = null
    
        fun setAddImagesViewListener(listener: AddImagesViewListener) {
            this.listener = listener
        }
    
        //初始换数据
        private fun initView() {
            var binding = DataBindingUtil.inflate<LayoutAddImagesBinding>(
                LayoutInflater.from(mContext),
                R.layout.layout_add_images,
                this,
                false
            )
            addView(binding.root)
            if (columnNums>5)columnNums=5
            binding.rvContent.layoutManager = GridLayoutManager(mContext, columnNums)
            mAdapter = AddImagesAdapter(mContext, columnNums,addImgs,addCloseImgs,addErrImgs,add_limit_nums)
            binding.rvContent.adapter = mAdapter
            mAdapter!!.addItem(AddImagesInfo("", "1"))
            mAdapter!!.setOnAddListener(object : AddImagesAdapter.OnAddClickListener {
                override fun onAddClick(view: View?, item: AddImagesInfo?) {
                    when (view!!.id) {
                        R.id.rl_add -> {
                            if (listener!=null)
                            listener!!.onAdd()
                        }
                        R.id.iv_content -> {
                            if (listener!=null)
                            listener!!.onPreview(item,mAdapter!!.getItems())
                        }
                    }
                }
    
            })
        }
        //添加数据
        fun addAddImages(lists: List<AddImagesInfo>) {
            mAdapter!!.addItems(lists)
        }
    
    
        interface AddImagesViewListener {
            fun onAdd()
            fun onPreview(item:AddImagesInfo?,lists: List<AddImagesInfo>?)
        }
    
    }
    

    总结:

    自定义ViewGroup 中间的布局可以设置成动态添加RecycleView,图片预览功能可以根据项目需要封装在库中,在此没做单独设置(需要封装通用传递的数据),用到的小伙伴可以根据自己需要再单独扩展

    引用:

    1.源码地址

    2.用到的相册项目地址

    相关文章

      网友评论

          本文标题:Android 图片上传九宫格(添加,删除,预览)

          本文链接:https://www.haomeiwen.com/subject/bruqcrtx.html