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

共 8824字,需浏览 18分钟

 ·

2022-04-24 09:19

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



思路:


  1. 自定义ViewGroup 包含RecycleView 实现九宫格

  2. 自定义属性 设置展示的行数,最大添加的个数设置AddItem 图片的展示样式,以及设置关闭按钮和错误页展示的央视

  3. 利用RecycleView 的 GridLayoutManager 设置九宫格展示

  4. 根据逻辑需要在RecyclerView.Adapter中动态添加图片和Add页面的两种不同他的Item

  5. 根据添加数据有没有AddItem类型动态处理数据


实现:


1.attrs.xml自定义属性

    



2.九宫格RecycleView的Adapter

class AddImagesAdapter(    mContext: Context,    limtNum: Int,    addImgs: Int,    addCloseImgs: Int,    addErrImgs: Int,    addLimitNums: Int) :    RecyclerView.Adapter() {    var mContext: Context    var limtNum = 5    var addImgs = -1    var addCloseImgs = -1    var addErrImgs = -1    var addLimitNums = 9    var addImages = ArrayList()
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) { processData(lists) }
fun addItem(info: AddImagesInfo) { addImages.add(info) notifyDataSetChanged() }
fun getItems(): ArrayList? { if (this.addImages == null) this.addImages = ArrayList() return this.addImages }
private fun processData(addDatas: List) { 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): ArrayList { 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

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( 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,图片预览功能可以根据项目需要封装在库中,在此没做单独设置(需要封装通用传递的数据),用到的小伙伴可以根据自己需要再单独扩展。


源码地址:

https://github.com/wukuiqing49/AddImageViews


到这里就结束啦。

浏览 47
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报