Android图片上传九宫格(添加,删除,预览)
龙旋
共 8824字,需浏览 18分钟
·
2022-04-24 09:19
越来越多的功能需要图片上传,所以封装了一个图片选取,展示的九宫格控件.包含了添加,删除,以及预览(为方便自定义,预览只提供点击方式外部自定义预览实现)的功能,如图所示:
思路:
自定义ViewGroup 包含RecycleView 实现九宫格
自定义属性 设置展示的行数,最大添加的个数设置AddItem 图片的展示样式,以及设置关闭按钮和错误页展示的央视
利用RecycleView 的 GridLayoutManager 设置九宫格展示
根据逻辑需要在RecyclerView.Adapter中动态添加图片和Add页面的两种不同他的Item
根据添加数据有没有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 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
到这里就结束啦。
评论