【无标题】

package com.example.fluidcolorfulframe
import android.content.Contextimport android.graphics.Canvasimport android.graphics.drawable.Drawableimport android.util.AttributeSetimport androidx.appcompat.widget.AppCompatImageViewimport androidx.core.view.setPadding/** * * @author wangzhichao * @since 2022/9/4 /class MyImageView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null) : AppCompatImageView(context, attrs) { private val drawable = FluidColorfulFrameDrawable() init { setPadding(5.dp.toInt()) drawable.callback = this } override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { super.onSizeChanged(w, h, oldw, oldh) drawable.setBounds(0, 0, w, h) drawable.startFluid() } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) drawable.draw(canvas) } override fun onDetachedFromWindow() { super.onDetachedFromWindow() drawable.cancelFluid() } override fun invalidateDrawable(dr: Drawable) { super.invalidateDrawable(dr) if (dr === drawable) { invalidate() } }}package com.example.fluidcolorfulframeimport android.animation.ObjectAnimatorimport android.animation.ValueAnimatorimport android.graphics.import android.graphics.drawable.Drawableimport android.util.Logimport android.view.animation.LinearInterpolatorimport androidx.core.graphics.toColorInt/ * * @author wangzhichao * @since 2022/9/4 /private const val TAG = "FluidColorfulFrame"class FluidColorfulFrameDrawable : Drawable() { private val paint = Paint(Paint.ANTI_ALIAS_FLAG) private lateinit var bounds: RectF private val rectF = RectF() private val defaultRadius: Float = 10.dp private val defaultStrokeWidth: Float = 5.dp private val colors: IntArray private val positions: FloatArray private val mtx = Matrix() private var degree: Float = 0f set(value) { field = value Log.d(TAG, “degree setter called”) invalidateSelf() } init { paint.style = Paint.Style.STROKE paint.strokeWidth = defaultStrokeWidth colors = intArrayOf( “#FF0000FF”.toColorInt(), // 蓝 0f “#FF000000”.toColorInt(), // 黑 0.02f “#FF000000”.toColorInt(), // 黑 0.25f “#FFFF0000”.toColorInt(), // 红 0.27f “#FFFF0000”.toColorInt(), // 红 0.37f “#FF00FF00”.toColorInt(), // 绿 0.39f “#FF0000FF”.toColorInt(), // 蓝 0.49f “#FFFFFF00”.toColorInt(), // 黄 0.51f “#FF000000”.toColorInt(), // 黑 0.53f “#FF000000”.toColorInt(), // 黑 0.75f “#FFFF0000”.toColorInt(), // 红 0.77f “#FFFF0000”.toColorInt(), // 红 0.87f “#FFFFFF00”.toColorInt(), // 黄 0.91f “#FF0000FF”.toColorInt(), // 蓝 0.96f ) positions = floatArrayOf( 0f, 0.02f, 0.25f, 0.27f, 0.37f, 0.39f, 0.49f, 0.51f, 0.53f, 0.75f, 0.77f, 0.87f, 0.91f, 0.96f, ) } override fun setBounds(left: Int, top: Int, right: Int, bottom: Int) { super.setBounds(left, top, right, bottom) bounds = RectF(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat()) rectF.left = defaultStrokeWidth / 2 rectF.top = defaultStrokeWidth / 2 rectF.right = bounds.width() - defaultStrokeWidth / 2 rectF.bottom = bounds.height() - defaultStrokeWidth / 2 paint.shader = SweepGradient(bounds.centerX(), bounds.centerY(), colors, positions) } override fun draw(canvas: Canvas) { Log.d(TAG, "draw: ") mtx.reset() mtx.setRotate(degree, bounds.centerX(), bounds.centerY()) (paint.shader as SweepGradient).setLocalMatrix(mtx) canvas.drawRoundRect(rectF, defaultRadius, defaultRadius, paint) } override fun setAlpha(alpha: Int) { paint.alpha = alpha } override fun setColorFilter(colorFilter: ColorFilter?) { paint.colorFilter = colorFilter } override fun getOpacity(): Int { return PixelFormat.TRANSLUCENT } private var fluidAnim: ObjectAnimator? = null fun startFluid() { fluidAnim = ObjectAnimator.ofFloat(this, “degree”, 0f, 360f).apply { duration = 2000L interpolator = LinearInterpolator() repeatCount = ValueAnimator.INFINITE start() } } fun cancelFluid() { fluidAnim?.cancel() }}package com.example.fluidcolorfulframeimport android.content.res.Resourcesimport android.util.TypedValue/* * * @author wangzhichao * @since 2022/9/4 */val Float.dp get() = TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, this, Resources.getSystem().displayMetrics)val Int.dp get() = this.toFloat().dp
class VideoClipAdapter(private val videoClipList: List) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

companion object {
    const val VIEW_TYPE_ITEM = 0
    const val VIEW_TYPE_DATE_SEPARATOR = 1
    const val VIEW_TYPE_BUTTON = 2
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    return when (viewType) {
        VIEW_TYPE_ITEM -> {
            VideoClipViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_video_clip, parent, false))
        }
        VIEW_TYPE_DATE_SEPARATOR -> {
            DateSeparatorViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_date_separator, parent, false))
        }
        VIEW_TYPE_BUTTON -> {
            ButtonViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_button, parent, false))
        }
        else -> throw IllegalArgumentException("Unknown view type")
    }
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    val item = getItemList()[position]
    when (getItemViewType(position)) {
        VIEW_TYPE_ITEM -> {
            val videoClip = item as VideoClipWithTime
            holder as VideoClipViewHolder
            holder.bind(videoClip)
        }
        VIEW_TYPE_DATE_SEPARATOR -> {
            val videoClip = item as VideoClipWithTime
            holder as DateSeparatorViewHolder
            holder.bind(videoClip)
        }
        VIEW_TYPE_BUTTON -> {
            val buttonItem = item as ButtonItem
            holder as ButtonViewHolder
            holder.bind(buttonItem)
        }
    }
}

override fun getItemViewType(position: Int): Int {
    return when (val item = getItemList()[position]) {
        is VideoClipWithTime -> {
            if (item.type == ItemType.DATE_SEPARATOR) VIEW_TYPE_DATE_SEPARATOR else VIEW_TYPE_ITEM
        }
        is ButtonItem -> VIEW_TYPE_BUTTON
        else -> throw IllegalArgumentException("Unknown item type")
    }
}

override fun getItemCount(): Int {
    return getItemList().size
}

// 获取需要显示的所有项(考虑日期分隔符和按钮)
private fun getItemList(): List<Any> {
    val items = mutableListOf<Any>()
    val groupedItems = videoClipList.groupBy { it.dateText } // 按日期分组
    val visibleItemsMap = mutableMapOf<String, Int>()  // 每次获取列表时,使用局部的 visibleItemsMap

    groupedItems.forEach { (_, group) ->
        // 先添加日期分隔符
        items.add(VideoClipWithTime(ItemType.DATE_SEPARATOR, group[0].dateText, NormalItem("", "")))

        // 获取当前日期下的可见项数量
        var visibleCount = visibleItemsMap[group[0].dateText] ?: maxSingle
        val visibleItems = group.take(visibleCount)
        items.addAll(visibleItems)

        // 如果项数超过 `maxSingle`,则添加一个按钮
        if (group.size > visibleCount) {
            items.add(ButtonItem(group[0].dateText))
        }

        // 更新每组的可见项数量
        visibleItemsMap[group[0].dateText] = visibleCount
    }
    return items
}

// 增加更多项的逻辑
private fun expandItems(group: List<VideoClipWithTime>, dateText: String) {
    val visibleCount = maxSingle
    val newVisibleCount = (visibleCount + plusSingle).coerceAtMost(group.size)
    notifyDataSetChanged()
}

// ViewHolder for VideoClipWithTime (item)
inner class VideoClipViewHolder(view: View) : RecyclerView.ViewHolder(view) {
    private val nameTextView: TextView = view.findViewById(R.id.nameTextView)
    private val timeTextView: TextView = view.findViewById(R.id.timeTextView)

    fun bind(videoClip: VideoClipWithTime) {
        nameTextView.text = videoClip.bean.name
        timeTextView.text = videoClip.bean.time
    }
}

// ViewHolder for DateSeparator (item)
inner class DateSeparatorViewHolder(view: View) : RecyclerView.ViewHolder(view) {
    private val dateTextView: TextView = view.findViewById(R.id.dateTextView)

    fun bind(videoClip: VideoClipWithTime) {
        dateTextView.text = videoClip.dateText
    }
}

// ViewHolder for Button
inner class ButtonViewHolder(view: View) : RecyclerView.ViewHolder(view) {
    val button: Button = view.findViewById(R.id.expand_button)

    fun bind(buttonItem: ButtonItem) {
        button.text = buttonItem.text
        button.setOnClickListener {
            // 获取当前日期的所有项
            val group = videoClipList.filter { it.dateText == buttonItem.text }
            expandItems(group, buttonItem.text)
        }
    }
}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值