自定义上下滑动itemtab选项卡

attrs.xml定义view的属性


    <declare-styleable name="ItemTabView">
        <attr name="selectedColor" format="color" />
        <attr name="normalColor" format="color" />
        <attr name="gradientStartColor" format="color" />
        <attr name="gradientCenterColor" format="color" />
        <attr name="gradientEndColor" format="color" />
        <!-- 统一的文字大小 -->
        <attr name="itemTextSize" format="dimension" />
        <!-- 统一的文字颜色 -->
        <attr name="itemTextColor" format="color" />
        <!-- 统一的文字样式 -->
        <attr name="itemTextStyle" format="enum">
            <enum name="normal" value="0" />
            <enum name="bold" value="1" />
            <enum name="italic" value="2" />
            <enum name="boldItalic" value="3" />
        </attr>
        <!-- 选中状态下的文字颜色 -->
        <attr name="selectedTextColor" format="color" />
        <!-- 未选中状态下的文字颜色 -->
        <attr name="normalTextColor" format="color" />
        <!-- 定义每个item之间距离 -->
        <attr name="itemSpacing" format="dimension" />
    </declare-styleable>

新建ItemTabView


class ItemTabView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    private var items = listOf("1", "2", "3")
    private var selectedIndex = 1
    private var lastY = 0f
    private var scrollOffset = 0f
    private val itemHeight = 100f
    private val textSize = 30f
    private var selectedColor = Color.BLUE
    private var normalColor = Color.WHITE
    private val gradientPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    private var gradientStartColor = Color.parseColor("#80FFFFFF")
    private var gradientCenterColor = Color.parseColor("#FFFFFFFF")
    private var gradientEndColor = Color.parseColor("#80FFFFFF")
    private var itemTextSize = 30f
    private var itemTextColor = Color.WHITE
    private var itemTextStyle = Typeface.NORMAL
    private var selectedTextColor = Color.BLUE
    private var normalTextColor = Color.WHITE
    private var itemSpacing = 0f // 默认间距为 0
    init {
        paint.textSize = textSize
        paint.textAlign = Paint.Align.CENTER
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ItemTabView, defStyleAttr, 0)
        selectedColor = typedArray.getColor(R.styleable.ItemTabView_selectedColor, selectedColor)
        normalColor = typedArray.getColor(R.styleable.ItemTabView_normalColor, normalColor)
        gradientStartColor = typedArray.getColor(R.styleable.ItemTabView_gradientStartColor, gradientStartColor)
        gradientCenterColor = typedArray.getColor(R.styleable.ItemTabView_gradientCenterColor, gradientCenterColor)
        gradientEndColor = typedArray.getColor(R.styleable.ItemTabView_gradientEndColor, gradientEndColor)
        itemTextSize = typedArray.getDimension(R.styleable.ItemTabView_itemTextSize, 30f)
        itemTextColor = typedArray.getColor(R.styleable.ItemTabView_itemTextColor, Color.WHITE)
        itemTextStyle = typedArray.getInt(R.styleable.ItemTabView_itemTextStyle, Typeface.NORMAL)
        selectedTextColor = typedArray.getColor(R.styleable.ItemTabView_selectedTextColor, Color.BLUE)
        normalTextColor = typedArray.getColor(R.styleable.ItemTabView_normalTextColor, Color.WHITE)
        itemSpacing = typedArray.getDimension(R.styleable.ItemTabView_itemSpacing, 0f) // 解析间距属性
        paint.textSize = itemTextSize
        paint.color = itemTextColor
        paint.typeface = Typeface.create(paint.typeface, itemTextStyle)
        typedArray.recycle()
    }

    fun setItems(newItems: List<String>) {
        items = newItems
        selectedIndex = items.size / 2
        scrollOffset = 0f
        invalidate()
    }
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val centerY = height / 2f
        val fontMetrics = paint.fontMetrics

        for (i in items.indices) {
            // 计算每个 item 的位置,加入 itemSpacing
            val y = centerY + (i - selectedIndex) * (itemHeight + itemSpacing) + scrollOffset
            paint.color = if (i == selectedIndex) selectedTextColor else normalTextColor

            if (i == selectedIndex) {
                val backgroundCenterY = y + itemHeight / 2
                val startX = 0f
                val endX = width.toFloat()
                val startY = backgroundCenterY - itemHeight / 2
                val endY = backgroundCenterY + itemHeight / 2
                val gradient = LinearGradient(
                    startX,
                    startY,
                    endX,
                    endY,
                    intArrayOf(gradientStartColor, gradientCenterColor, gradientEndColor),
                    floatArrayOf(0f, 0.5f, 1f),
                    Shader.TileMode.CLAMP
                )
                gradientPaint.shader = gradient
                canvas.drawRect(startX, startY, endX, endY, gradientPaint)
            }

            val textHeight = fontMetrics.descent - fontMetrics.ascent
            val textOffset = (textHeight / 2) - fontMetrics.descent
            val textY = y + itemHeight / 2 + textOffset
            canvas.drawText(items[i], width / 2f, textY, paint)
        }
    }
    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> lastY = event.y
            MotionEvent.ACTION_MOVE -> {
                val dy = event.y - lastY
                scrollOffset += dy
                lastY = event.y

                // 调整滚动逻辑,支持 itemSpacing
                if (abs(scrollOffset) >= itemHeight + itemSpacing) {
                    if (scrollOffset > 0) {
                        if (selectedIndex > 0) selectedIndex--
                    } else {
                        if (selectedIndex < items.size - 1) selectedIndex++
                    }
                    scrollOffset %= itemHeight + itemSpacing
                }
                invalidate()
            }
            MotionEvent.ACTION_UP -> {
                // 调整抬起时的逻辑,支持 itemSpacing
                if (scrollOffset > (itemHeight + itemSpacing) / 2) {
                    if (selectedIndex > 0) selectedIndex--
                } else if (scrollOffset < -(itemHeight + itemSpacing) / 2) {
                    if (selectedIndex < items.size - 1) selectedIndex++
                }
                scrollOffset = 0f
                invalidate()
            }
        }
        return true
    }

    fun getSelectedItem(): String {
        return items[selectedIndex]
    }

    fun getSelectedIndex(): Int {
        return selectedIndex
    }
    fun setItemSpacing(spacing: Float) {
        itemSpacing = spacing
        invalidate() // 刷新视图
    }
}

使用此view


                <你的view路径.ItemTabView
                    android:id="@+id/right2Item"
                    android:layout_width="200dp"
                    android:layout_height="200dp"
                    app:selectedColor="@color/blue"
                    app:normalColor="@color/white"
                    app:gradientStartColor="@color/gradient_start"
                    app:gradientCenterColor="@color/gradient_center"
                    app:gradientEndColor="@color/gradient_end"
                    app:itemSpacing="6dp"
                    app:itemTextSize="25sp"
                    app:itemTextStyle="bold"
                    app:selectedTextColor="@color/blue"
                    app:normalTextColor="@color/white"/>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值