package com.gh.common.view import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater import android.view.View import android.widget.LinearLayout import androidx.core.content.ContextCompat import com.facebook.drawee.drawable.ScalingUtils import com.facebook.drawee.view.SimpleDraweeView import com.gh.common.util.* import com.gh.gamecenter.ImageViewerActivity import com.gh.gamecenter.R import com.gh.gamecenter.common.utils.debounceActionWithInterval import com.gh.gamecenter.common.utils.dip2px import com.gh.gamecenter.common.utils.toResString import com.gh.gamecenter.core.utils.DisplayUtils import com.gh.gamecenter.common.utils.ImageUtils import com.gh.gamecenter.core.utils.TopCutProcess import com.gh.gamecenter.databinding.ItemCommunityImageBinding import com.gh.gamecenter.login.user.UserManager import com.gh.gamecenter.feature.entity.AnswerEntity import com.gh.gamecenter.feature.entity.CommunityVideoEntity import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel class ImageContainerView : LinearLayout { private var mAnswerEntity: AnswerEntity? = null //三图默认宽度 private var mDefaultWidth = 0f //单图固定宽度 private var mFixdWidth = 0f //最小比例 private var mMinRatio = 3 / 4f //最大比例 private var mMaxRatio = 3 / 2f //长图比例 private var mLongPictureRatio = 9 / 18f private var mEntrance = "" private var mPath = "" //图片之间的间距 private val mItemSpace = 4f.dip2px() private var mOffset = 0 private var index = 0 private val imageViewList = arrayListOf() constructor(context: Context) : this(context, null) constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { initView(attrs) } private fun initView(attrs: AttributeSet?) { orientation = HORIZONTAL val ta = context.obtainStyledAttributes(attrs, R.styleable.ImageContainerView) mOffset = ta.getDimensionPixelSize(R.styleable.ImageContainerView_offset, 0) calculateWidth() ta.recycle() } private fun calculateWidth() { mDefaultWidth = (DisplayUtils.getScreenWidth() - mOffset.toFloat() - mItemSpace * 2) / 3 mFixdWidth = (DisplayUtils.getScreenWidth() - mOffset.toFloat() - mItemSpace * 2) * 2 / 3 } fun setOffset(offset: Float) { mOffset = offset.dip2px() calculateWidth() } fun bindData(entity: AnswerEntity, entrance: String = "", path: String = "", imageClick: (() -> Unit)? = null) { imageViewList.clear() if (entity.id != mAnswerEntity?.id) { removeAllViews() } mAnswerEntity = entity mEntrance = entrance mPath = path index = 0 if ((entity.user.id == UserManager.getInstance().userId && entity.videos.isNotEmpty()) || (entity.user.id != UserManager.getInstance().userId && entity.getPassVideos().isNotEmpty()) || entity.images.isNullOrEmpty() ) { visibility = View.GONE return } visibility = View.VISIBLE if (mAnswerEntity?.type == "community_article") { //若文章内容含有图片及视频,则信息流卡片,仅展示图片,且标题后带有‘有视频’标签 //若文章内容仅含有图片,则信息流卡片,仅展示图片,无标签 //若文章内容仅含有视频,则信息流卡片,仅展示视频,无标签 when { entity.images.isNotEmpty() -> { val imagesInfo = entity.imagesInfo val images = entity.images.take(3) images.forEachIndexed { index, url -> val width = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].width else 0 val height = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].height else 0 bindImage(url, width, height, images.size == 1, imageClick) } } entity.getPassVideos().isNotEmpty() -> { val video = entity.getPassVideos()[0] bindVideo(video, video.width, video.height, true) } else -> { // do noting } } } else { //若问答内容含有图片及视频,则信息流卡片,同时展示图片及视频,且参考以往排序逻辑(视频优先放置第一位),无标签 //若问答内容仅含有图片,则信息流卡片,仅展示图片,无标签 //若问答内容仅含有视频,则信息流卡片,仅展示视频,无标签 if (entity.getPassVideos().isNotEmpty()) { val video = entity.getPassVideos()[0] bindVideo(video, video.width, video.height, mAnswerEntity?.images.isNullOrEmpty()) entity.images.take(2).forEachIndexed { index, url -> val imagesInfo = entity.imagesInfo val width = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].width else 0 val height = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].height else 0 bindImage(url, width, height, false, imageClick) } } else { val images = entity.images.take(3) images.forEachIndexed { index, url -> val imagesInfo = entity.imagesInfo val width = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].width else 0 val height = if (index <= entity.imagesInfo.size - 1) imagesInfo[index].height else 0 bindImage(url, width, height, images.size == 1, imageClick) } } } } private fun bindVideo(video: CommunityVideoEntity, width: Int, height: Int, isChangeRatio: Boolean) { val oldView = if (childCount == 0 || index >= childCount) null else getChildAt(index) val binding = if (oldView != null) { ItemCommunityImageBinding.bind(oldView) } else { ItemCommunityImageBinding.inflate(LayoutInflater.from(context), null, false) } if (oldView == null) { addView(binding.root) } binding.durationOrNumTv.visibility = View.VISIBLE binding.videoPlay.visibility = View.VISIBLE binding.labelIcon.visibility = View.GONE binding.durationOrNumTv.text = video.duration displayImage(binding, video.poster, width.toFloat(), height.toFloat(), isChangeRatio, true) binding.root.setOnClickListener { debounceActionWithInterval(it.id, 1000) { if (mAnswerEntity == null) return@debounceActionWithInterval val videoEntity = mAnswerEntity!!.getPassVideos()[0] DirectUtils.directToVideoDetail( context, videoEntity.id, VideoDetailContainerViewModel.Location.VIDEO_HOT.value, showComment = false, entrance = mEntrance, path = mPath ) } } index++ } private fun bindImage( url: String, width: Int, height: Int, isChangeRatio: Boolean, imageClick: (() -> Unit)? ) { val oldView = if (childCount == 0 || index >= childCount) null else getChildAt(index) val binding = if (oldView != null) { ItemCommunityImageBinding.bind(oldView) } else { ItemCommunityImageBinding.inflate(LayoutInflater.from(context), null, false) } binding.root.tag = index if (oldView == null) { addView(binding.root) } imageViewList.add(binding.image) binding.durationOrNumTv.visibility = View.GONE binding.videoPlay.visibility = View.GONE displayImage(binding, url, width.toFloat(), height.toFloat(), isChangeRatio) binding.root.setOnClickListener { if (mAnswerEntity?.status == "pending" || mAnswerEntity?.status == "fail") return@setOnClickListener imageClick?.invoke() debounceActionWithInterval(it.id, 1000) { if (mAnswerEntity == null) return@debounceActionWithInterval val position = if (mAnswerEntity?.type == "community_article") { binding.root.tag as Int } else { if (mAnswerEntity!!.getPassVideos() .isNullOrEmpty() ) binding.root.tag as Int else (binding.root.tag as Int) - 1 } if (mAnswerEntity?.communityId.isNullOrEmpty()) { mAnswerEntity?.communityId = mAnswerEntity?.bbs?.id } val intent = ImageViewerActivity.getIntent( context, mAnswerEntity!!.images as ArrayList, position, imageViewList, if (mAnswerEntity?.type == "community_article") mAnswerEntity else null, mEntrance, true ) context.startActivity(intent) } } index++ } private fun displayImage( binding: ItemCommunityImageBinding, url: String, width: Float, height: Float, isChangeRatio: Boolean, isVideo: Boolean = false ) { val params = binding.root.layoutParams as LayoutParams val hierarchy = binding.image.hierarchy binding.labelIcon.visibility = View.GONE if (width != 0f && height != 0f) { val picRatio = width / height if (isChangeRatio) { when { picRatio <= mMinRatio -> { params.height = (mFixdWidth / mMinRatio).toInt() if (binding.image.tag != url) { ImageUtils.display(binding.image, url, false, TopCutProcess(mMinRatio)) } } picRatio >= mMaxRatio -> { params.height = (mFixdWidth / mMaxRatio).toInt() ImageUtils.display(binding.image, url, false) } else -> { params.height = (mFixdWidth / picRatio).toInt() ImageUtils.display(binding.image, url, false) } } params.width = mFixdWidth.toInt() } else { params.width = mDefaultWidth.toInt() params.height = mDefaultWidth.toInt() if (width > height) { val loadImageWidth = width * (mDefaultWidth.toInt() / height) binding.image.setTag(ImageUtils.TAG_TARGET_WIDTH, loadImageWidth.toInt()) } ImageUtils.display(binding.image, url, false) } //长图 if (!isVideo && picRatio <= mLongPictureRatio) { binding.labelIcon.visibility = View.VISIBLE binding.labelIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_long_pic_label)) } } else { params.width = mDefaultWidth.toInt() params.height = mDefaultWidth.toInt() ImageUtils.display(binding.image, url, false) } if (url.endsWith(".gif")) { binding.gifBorder.visibility = View.VISIBLE binding.labelIcon.visibility = View.VISIBLE binding.labelIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_gif_label)) } binding.pendingView.run { when (mAnswerEntity?.status) { "pending" -> { visibility = View.VISIBLE text = R.string.pending_status.toResString() } "fail" -> { visibility = View.VISIBLE text = R.string.fail_status.toResString() } else -> { visibility = View.GONE } } } val imageCount = mAnswerEntity?.images?.size ?: 0 if (!isVideo && index == 2 && imageCount > 3) { binding.labelIcon.visibility = View.GONE binding.durationOrNumTv.visibility = View.VISIBLE binding.durationOrNumTv.text = "+${imageCount - 3}" } hierarchy.actualImageScaleType = ScalingUtils.ScaleType.CENTER_CROP if (index != 0) params.leftMargin = mItemSpace binding.root.layoutParams = params } }