Files
assistant-android/app/src/main/java/com/gh/common/view/ImageContainerView.kt

311 lines
13 KiB
Kotlin

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<SimpleDraweeView>()
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<String>, 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
}
}