Android 实现仿微博列表九宫图

作者: 笑里藏刀我不会AI | 来源:发表于2019-02-25 16:38 被阅读59次

    先看效果图

    1. IMG_2494.PNG
    2. IMG_2495.PNG

    需求

    1. 类似微博九宫图一样,单张图片显示比例(此处具体先省略)
    2. 2张图和4张图片显示 格子列数为4宫格

    需要的库

    com.github.bumptech.glide:glide:4.9.0
    com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.44
    

    大概思路

    1. 数据请求 省略(我用的酷安的数据热门评论接口)
    2. 根据评论中图片数据设置图片RecyclerViewSpanCount,每一条评论都含有一个展示图片的RecycleView,再设置ItemDecoration
    3. 对不同的图片个数的ViewHolder设置不同的type

    上代码

    CmsStyleCommentNormalViewHolder:类中

    if (!TextUtils.isEmpty(dateItem.pic) && dateItem.picArr != null) {
                    val nineImageList = arrayListOf<NineImageBean>()
                    var spanCount = 0
                    dateItem.picArr?.let { it1 ->
                        spanCount = if (it1.size == 1) {
                            1
                        } else if (it1.size == 2 || it1.size == 4) {
                            2
                        } else {
                            3
                        }
                        it1.forEachIndexed { index, s ->
                            nineImageList.add(NineImageBean().apply {
                                this.isGif = StringUtils.isGifUrl(s)
                                this.url = s
                                this.positionAdapter = index
                                if (spanCount == 1) {
                                    this.type = NineImageBean.LargeImageType
                                } else {
                                    this.type = NineImageBean.SmallImageType
                                }
                            })
                        }
                    }
                    val cmsChildImageNineAdapter: CmsChildImageNineAdapter
                    val adapterTag = nineImageRv.tag
                    if (adapterTag is CmsChildImageNineAdapter) {
                        cmsChildImageNineAdapter = adapterTag
                    } else {
                        cmsChildImageNineAdapter = CmsChildImageNineAdapter(ArrayList())
                        nineImageRv.apply {
                            cmsChildImageNineAdapter.bindToRecyclerView(this)
                            this.isNestedScrollingEnabled = false
                            this.setHasFixedSize(true)
                            this.tag = cmsChildImageNineAdapter
                        }
                        cmsChildImageNineAdapter.setOnItemClickListener { adapter, _, position ->
                            val pictureBeanList = ArrayList<PictureBean>()
                            for (item in adapter.data) {
                                if (item is NineImageBean) {
                                    pictureBeanList.add(PictureBean().apply {
                                        this.originalUrl = item.url
                                    })
                                }
                            }
                            if (pictureBeanList.isNotEmpty()) {
                                LaunchNormalUtils.startPictureActivity(mContext, pictureBeanList, position)
                            }
                        }
                    }
                    nineImageRv.apply {
                        this.layoutParams.width = if (spanCount == 4 || spanCount == 2) {
                            singleImageWidth.toInt() * 2
                        } else if (spanCount == 1) {
                            ViewGroup.LayoutParams.WRAP_CONTENT
                        } else {
                            ViewGroup.LayoutParams.MATCH_PARENT
                        }
                        for (i in 0 until this.itemDecorationCount) {
                            this.removeItemDecorationAt(i)
                        }
                        this.layoutManager = GridLayoutManager(mContext, spanCount)
                        this.addItemDecoration(RecyclerViewItemDividerHelper.getNineImageAdapterDividerItem(mContext, spanCount, this, 16f))
                    }
                    cmsChildImageNineAdapter.setNewData(nineImageList)
                    nineImageRv.visibility = View.VISIBLE
                } else {
                    nineImageRv.visibility = View.GONE
                }
            }
    
    • 上面代码位于一个评论ViewHolder类
    • CmsChildImageNineAdapter:
    class CmsChildImageNineAdapter(data: MutableList<NineImageBean>?): BaseMultiItemQuickAdapter<NineImageBean, BaseViewHolder>(data) {
        init {
            addItemType(NineImageBean.emptyType, R.layout.item_multi_not_found)
            addItemType(NineImageBean.SmallImageType, R.layout.item_multi_nine_image_small)
            addItemType(NineImageBean.LargeImageType, R.layout.item_multi_nine_image_large)
        }
    
        override fun convert(helper: BaseViewHolder, item: NineImageBean) {
            var associatedObject = helper.associatedObject
            when (item.itemType) {
                NineImageBean.SmallImageType -> {
                    if (associatedObject == null) {
                        associatedObject = NineSmallViewHolder(mContext, helper)
                        helper.associatedObject = associatedObject
                    }
                    if (associatedObject is NineSmallViewHolder) {
                        associatedObject.updateView(item)
                    }
                }
                NineImageBean.LargeImageType -> {
                    if (associatedObject == null) {
                        associatedObject = NineLargeViewHolder(mContext, helper)
                        helper.associatedObject = associatedObject
                    }
                    if (associatedObject is NineLargeViewHolder) {
                        associatedObject.updateView(item)
                    }
                }
            }
        }
    
    • NineSmallViewHolder
    class NineSmallViewHolder(val mContext: Context, val baseViewHolder: BaseViewHolder) : IBaseViewMultiHolder<NineImageBean>(baseViewHolder.itemView) {
        private val smallImageIv: CustomGifImageView = itemView.findViewById(R.id.small_image_iv)
        private val smallGifFlagRtv: RoundTextView = itemView.findViewById(R.id.small_gif_flag_rtv)
        private var gifHandler: GifHandler? = null
    
        private inner class ParamTag {
            var isFirstFrame = true
            var isAlwaysPlayerGif = true
        }
    
        override fun updateView(dateItem: NineImageBean) {
            super.updateView(dateItem)
            smallImageIv.apply {
                if (dateItem.isGif && !this.isGifRunning()) {
                    smallGifFlagRtv.visibility = View.VISIBLE
                } else {
                    smallGifFlagRtv.visibility = View.GONE
                }
                if (!dateItem.isGif) {
                    loadNormalImage(dateItem)
                } else {
                    if (!this.isGifRunning()) {
                        loadGifImage(ParamTag().apply {
                            this.isFirstFrame = true
                        })
                    }
                }
            }
        }
    
     private fun loadNormalImage(dateItem: NineImageBean) {
            ImageLoader.Builder(mContext)
                    .getRequestManager()
                    .asBitmap()
                    .load(dateItem.url)
                    .apply(ImageLoader.defaultRequestOptions(R.color.placeholder_color))
                    .into(smallImageIv)
        }
    
    • 我粘贴的事项目中代码,我也懒得删除了,所以CustomGifImageView 就用imageview就行,也不用判断GIF加载什么的,就gilde直接加载就OK
    • NineLargeViewHolder
    class NineLargeViewHolder(val mContext: Context, val baseViewHolder: BaseViewHolder) : IBaseViewMultiHolder<NineImageBean>(baseViewHolder.itemView) {
        private val largeIv: MatrixScaleImageView = itemView.findViewById(R.id.large_iv)
        private val largeFlagRtv: RoundTextView = itemView.findViewById(R.id.large_flag_rtv)
        private val gifFlagRtv: RoundTextView = itemView.findViewById(R.id.gif_flag_rtv)
    
        override fun updateView(dateItem: NineImageBean) {
            super.updateView(dateItem)
            largeFlagRtv.visibility = View.GONE
            gifFlagRtv.visibility = View.GONE
            dateItem.picImageSize?.apply {
                val matrixScaleHelper = MatrixScaleHelper(this[0].toFloat(), this[1].toFloat())
                largeIv.apply {
                    gifFlagRtv.visibility = if (dateItem.isGif && !this.isGifRunning()) {
                        View.VISIBLE
                    } else {
                        View.GONE
                    }
                    largeFlagRtv.visibility = if (matrixScaleHelper.isLongBitmap && !dateItem.isGif) {
                        View.VISIBLE
                    } else {
                        View.GONE
                    }
                    if (!dateItem.isGif) {
                        loadNormalImage()
                    } else {
                        if (!this.isGifRunning()) {
                            loadGifImage(true)
                        }
                    }
                }
            }
        }
    
        override fun changeTheme(theme: Theme) {
            super.changeTheme(theme)
            largeFlagRtv.setBackgroundColor(ColorUtils.getThemeColor(mContext, R.attr.colorAccent))
            gifFlagRtv.setBackgroundColor(ColorUtils.getThemeColor(mContext, R.attr.colorAccent))
        }
    
        fun startPlayerGif() {
            val nineImageBean = getItemTagDate() as? NineImageBean ?: return
            if (nineImageBean.isGif) {
                loadGifImage(false)
            }
        }
    
        fun stopPlayerGif() {
            val nineImageBean = getItemTagDate() as? NineImageBean ?: return
            if (nineImageBean.isGif) {
                loadGifImage(true)
            }
        }
    
        private fun loadNormalImage() {
            val nineImageBean = getItemTagDate()
            if (nineImageBean is NineImageBean) {
                val picImageSize = nineImageBean.picImageSize ?: return
                val matrixScaleHelper = MatrixScaleHelper(picImageSize[0].toFloat(), picImageSize[1].toFloat())
                ImageLoader.Builder(mContext, nineImageBean.url)
                        .setTransition(ImageLoader.defaultTransitionOptions())
                        .setRequestOptions(ImageLoader.defaultRequestOptions(R.color.placeholder_color)
                                .transform(matrixScaleHelper.getCropTransformation(largeIv)))
                        .build(largeIv)
            }
        }
    
    • GIF 代码我就不粘贴了,其中一部分,这个viewHolder比较特殊,一问微博中单个图片比较特殊,是有比例显示的,大长图显示上半部分,普通图片等比例缩放,MatrixScaleHelper类就是一个等比缩放类
    • 粘贴的是部分代码和思路,全部代码整理起来比较麻烦,实现效果比较多
    • 后面会陆续贴出来实现微博九宫图 GIF图片依次播放,还有单张图片等比缩放,以及换肤(不重启应用)过程中RecycleView的处理

    最后看一样我实现的效果图吧

    Screenshot_20190225-163519.png Screenshot_20190225-163534.png Screenshot_20190225-163557.png Screenshot_20190225-163649.png

    相关文章

      网友评论

        本文标题:Android 实现仿微博列表九宫图

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