美文网首页
TriangleLabelView

TriangleLabelView

作者: CentForever | 来源:发表于2020-12-30 23:57 被阅读0次


import android.annotation.TargetApi
import android.content.Context
import android.graphics.*
import android.os.Build
import android.util.AttributeSet
import android.view.View
import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import androidx.annotation.IntDef
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
import com.tencent.wemeet.sdk.R
import kotlin.math.sqrt

class TriangleLabelView : View {
    private class PaintHolder {
        var text = ""
        var paint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
        var color = 0
        var size = 0f
        var height = 0f
        var width = 0f
        @PrimaryTextStyle
        var style = NORMAL
        fun initPaint() {
            paint.color = color
            paint.textAlign = Paint.Align.CENTER
            paint.textSize = size
            when (style) {
                SANS_SERIF -> {
                    paint.typeface = Typeface.SANS_SERIF
                }
                DEFAULT_BOLD -> {
                    paint.typeface = Typeface.DEFAULT_BOLD
                }
                else -> {
                    paint.typeface = Typeface.MONOSPACE
                }
            }
        }

        fun resetStatus() {
            val rectText = Rect()
            paint.getTextBounds(text, 0, text.length, rectText)
            width = rectText.width().toFloat()
            height = rectText.height().toFloat()
        }
    }

    private val primary = PaintHolder()
    private val secondary = PaintHolder()
    private var topPadding = 0f
    private var bottomPadding = 0f
    private var centerPadding = 0f
    private var trianglePaint: Paint? = null
    var triangleBackGroundColor = 0
        private set
    private var width = 0f
    private var height = 0f
    private var corner: Corner? = null

    enum class Corner(private val type: Int) {
        TOP_LEFT(1), TOP_RIGHT(2), BOTTOM_LEFT(3), BOTTOM_RIGHT(4);

        fun top(): Boolean {
            return this == TOP_LEFT || this == TOP_RIGHT
        }

        fun left(): Boolean {
            return this == TOP_LEFT || this == BOTTOM_LEFT
        }

        companion object {
            fun from(type: Int): Corner {
                for (c in values()) {
                    if (c.type == type) return c
                }
                return TOP_LEFT
            }
        }
    }

    @JvmOverloads
    constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : super(context, attrs, defStyleAttr) {
        init(context, attrs)
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
        init(context, attrs)
    }

    private fun init(context: Context, attrs: AttributeSet?) {
        val ta = context.obtainStyledAttributes(attrs, R.styleable.TriangleLabelView)
        topPadding = ta.getDimension(R.styleable.TriangleLabelView_labelTopPadding, dp2px(7f).toFloat())
        centerPadding = ta.getDimension(R.styleable.TriangleLabelView_labelCenterPadding, dp2px(3f).toFloat())
        bottomPadding = ta.getDimension(R.styleable.TriangleLabelView_labelBottomPadding, dp2px(3f).toFloat())
        triangleBackGroundColor = ta.getColor(R.styleable.TriangleLabelView_backgroundColor, Color.parseColor("#66000000"))
        primary.color = ta.getColor(R.styleable.TriangleLabelView_primaryTextColor, Color.WHITE)
        secondary.color = ta.getColor(R.styleable.TriangleLabelView_secondaryTextColor, Color.WHITE)
        primary.size = ta.getDimension(R.styleable.TriangleLabelView_primaryTextSize, sp2px(11f))
        secondary.size = ta.getDimension(R.styleable.TriangleLabelView_secondaryTextSize, sp2px(8f))
        val primary = ta.getString(R.styleable.TriangleLabelView_primaryText)
        if (primary != null) {
            this.primary.text = primary
        }
        val secondary = ta.getString(R.styleable.TriangleLabelView_secondaryText)
        if (secondary != null) {
            this.secondary.text = secondary
        }
        this.primary.style = ta.getInt(R.styleable.TriangleLabelView_primaryTextStyle, 2)
        this.secondary.style = ta.getInt(R.styleable.TriangleLabelView_secondaryTextStyle, 0)
        corner = Corner.from(ta.getInt(R.styleable.TriangleLabelView_corner, 1))
        ta.recycle()
        this.primary.initPaint()
        this.secondary.initPaint()
        trianglePaint = Paint(Paint.ANTI_ALIAS_FLAG)
        trianglePaint?.color = triangleBackGroundColor
        this.primary.resetStatus()
        this.secondary.resetStatus()
    }

    var labelTopPadding: Float
        get() = topPadding
        set(dp) {
            topPadding = dp2px(dp).toFloat()
        }

    var labelCenterPadding: Float
        get() = centerPadding
        set(dp) {
            centerPadding = dp2px(dp).toFloat()
            relayout()
        }

    var labelBottomPadding: Float
        get() = bottomPadding
        set(dp) {
            bottomPadding = dp2px(dp).toFloat()
            relayout()
        }

    fun setPrimaryText(@StringRes textRes: Int) {
        primary.text = context.getString(textRes)
        primary.resetStatus()
        relayout()
    }

    var primaryText: String
        get() = primary.text
        set(text) {
            primary.text = text
            primary.resetStatus()
            relayout()
        }

    fun setSecondaryText(@StringRes textRes: Int) {
        secondary.text = context.getString(textRes)
        secondary.resetStatus()
        relayout()
    }

    var secondaryText: String
        get() = secondary.text
        set(smallText) {
            secondary.text = smallText
            secondary.resetStatus()
            relayout()
        }

    fun setPrimaryTextColor(@ColorInt color: Int) {
        primary.color = color
        primary.initPaint()
        primary.resetStatus()
        relayout()
    }

    fun setPrimaryTextColorResource(@ColorRes colorResource: Int) {
        primary.color = ContextCompat.getColor(context, colorResource)
        primary.initPaint()
        primary.resetStatus()
        relayout()
    }

    fun setSecondaryTextColor(@ColorInt color: Int) {
        secondary.color = color
        secondary.initPaint()
        secondary.resetStatus()
        relayout()
    }

    fun setSecondaryTextColorResource(@ColorRes colorResource: Int) {
        secondary.color = ContextCompat.getColor(context, colorResource)
        secondary.initPaint()
        secondary.resetStatus()
        relayout()
    }

    var primaryTextSize: Float
        get() = primary.size
        set(sp) {
            primary.size = sp2px(sp)
            relayout()
        }

    var secondaryTextSize: Float
        get() = secondary.size
        set(sp) {
            secondary.size = sp2px(sp)
            relayout()
        }

    fun setTriangleBackgroundColor(@ColorInt color: Int) {
        triangleBackGroundColor = color
        trianglePaint?.color = triangleBackGroundColor
        relayout()
    }

    fun setTriangleBackgroundColorResource(@ColorRes colorResource: Int) {
        triangleBackGroundColor = ContextCompat.getColor(context, colorResource)
        trianglePaint?.color = triangleBackGroundColor
        relayout()
    }

    fun setCorner(corner: Corner?) {
        this.corner = corner
        relayout()
    }

    fun getCorner(): Corner? {
        return corner
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        canvas.save()

        // translate
        if (corner?.top() == true) {
            canvas.translate(0f, (height * sqrt(2.0) - height).toFloat())
        }

        // rotate
        if (corner?.top() == true) {
            if (corner?.left() == true) {
                canvas.rotate(DEGREES_LEFT.toFloat(), 0f, height.toFloat())
            } else {
                canvas.rotate(DEGREES_RIGHT.toFloat(), width.toFloat(), height.toFloat())
            }
        } else {
            if (corner?.left() == true) {
                canvas.rotate(DEGREES_RIGHT.toFloat(), 0f, 0f)
            } else {
                canvas.rotate(DEGREES_LEFT.toFloat(), width.toFloat(), 0f)
            }
        }

        // draw triangle
        val path = Path()
        if (corner?.top() == true) {
            path.moveTo(0f, height.toFloat())
            path.lineTo(width / 2.toFloat(), 0f)
            path.lineTo(width.toFloat(), height.toFloat())
        } else {
            path.moveTo(0f, 0f)
            path.lineTo(width / 2.toFloat(), height.toFloat())
            path.lineTo(width.toFloat(), 0f)
        }
        path.close()
        if (trianglePaint != null) {
            canvas.drawPath(path, trianglePaint!!)
        }

        // draw secondaryText
        if (corner?.top() == true) {
            canvas.drawText(secondary.text, width / 2.toFloat(), topPadding + secondary.height, secondary.paint)
            canvas.drawText(primary.text, width / 2.toFloat(), topPadding + secondary.height + centerPadding + primary.height, primary.paint)
        } else {
            canvas.drawText(secondary.text, width / 2.toFloat(), bottomPadding + secondary.height + centerPadding + primary.height, secondary.paint)
            canvas.drawText(primary.text, width / 2.toFloat(), bottomPadding + primary.height, primary.paint)
        }
        canvas.restore()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        height = (topPadding + centerPadding + bottomPadding + secondary.height + primary.height).toInt().toFloat()
        width = 2 * height
        val realHeight = (height * sqrt(2.0)).toInt()
        setMeasuredDimension(width.toInt(), realHeight)
    }

    fun dp2px(dpValue: Float): Int {
        val scale = context.resources.displayMetrics.density
        return (dpValue * scale + 0.5f).toInt()
    }

    fun sp2px(spValue: Float): Float {
        val scale = context.resources.displayMetrics.scaledDensity
        return spValue * scale
    }

    /**
     * Should be called whenever what we're displaying could have changed.
     */
    private fun relayout() {
        invalidate()
        requestLayout()
    }

    companion object {
        private val TAG = TriangleLabelView::class.java.simpleName
        private const val DEGREES_LEFT = -45
        private const val DEGREES_RIGHT = 45

        const val NORMAL = 0
        const val SANS_SERIF = 1
        const val DEFAULT_BOLD = 2
    }

    @IntDef(NORMAL, SANS_SERIF, DEFAULT_BOLD)
    annotation class PrimaryTextStyle
}

<declare-styleable name="TriangleLabelView">
        <attr name="backgroundColor" format="color" />
        <attr name="primaryTextColor" format="color" />
        <attr name="secondaryTextColor" format="color" />
        <attr name="primaryText" format="string" />
        <attr name="secondaryText" format="string" />
        <attr name="primaryTextSize" format="dimension" />
        <attr name="secondaryTextSize" format="dimension" />
        <attr name="labelTopPadding" format="dimension" />
        <attr name="labelCenterPadding" format="dimension" />
        <attr name="labelBottomPadding" format="dimension" />
        <attr name="primaryTextStyle">
            <enum name="normal" value="0" />
            <enum name="italic" value="1" />
            <enum name="bold" value="2" />
        </attr>
        <attr name="secondaryTextStyle">
            <enum name="normal" value="0" />
            <enum name="italic" value="1" />
            <enum name="bold" value="2" />
        </attr>
        <attr name="corner">
            <enum name="leftTop" value="1" />
            <enum name="rightTop" value="2" />
            <enum name="leftBottom" value="3" />
            <enum name="rightBottom" value="4" />
        </attr>
    </declare-styleable>

相关文章

网友评论

      本文标题:TriangleLabelView

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