WavTextView 波形文字

289 阅读1分钟

波形文字

代码kotlin


class WavTextView @JvmOverloads constructor(
    context: Context?,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) :
    View(context, attrs, defStyleAttr) {
    private var mBaseline: Int = 0
    private var mCenterY: Float = 0F
    private var mCenterX: Float = 0F
    private var mR: Float = 0F
    private var mPath: Path = Path()
    private var mPath2: Path = Path()
    private var mRectF: RectF = RectF()
    private var mPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)

    init {
        mPaint.textAlign = Paint.Align.CENTER
        mPaint.color = Color.BLUE
        mPaint.style = Paint.Style.FILL
        mPaint.strokeWidth = 0F
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        mCenterX = measuredWidth / 2F
        mCenterY = measuredHeight / 2F
        mR = min(mCenterX, mCenterY) / 2F
        mRectF.left = (mCenterX - mR)
        mRectF.right = (mCenterX + mR)
        mRectF.top = (mCenterY - mR)
        mRectF.bottom = (mCenterY + mR)
        mPath2.addCircle(mCenterX, mCenterY, mR, Path.Direction.CW)
        mPaint.textSize = mR * 1.5F
        val fontMetrics = mPaint.fontMetricsInt
        mBaseline = (fontMetrics.bottom + fontMetrics.top) / 2
        removeCallbacks(runnable)
        post(runnable)
    }

    var controlPercent = 0.4F
    var controlOffset = 0F

    private val runnable = object : Runnable {
        override fun run() {
            controlOffset += (Math.random() * mR * 0.12F).toFloat()
            if (controlOffset >= mR * 2) {
                controlOffset = 0F
            }
            invalidate()
            postDelayed(this, 10)
        }
    }

    var text: String = ""
    var bottomColor: Int = Color.WHITE
    var topColor: Int = Color.CYAN
    var wavColor: Int = Color.BLUE

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
//        canvas?.clipPath(mPath2)
        mPaint.color = topColor
        canvas?.drawText(text, mCenterX, mCenterY - mBaseline, mPaint)
        mPath.reset()
        mPaint.color = wavColor
        mPath.moveTo(controlOffset - mR * 2, mCenterY)
        repeat((mCenterX / mR).toInt() + 2) {
            mPath.rQuadTo(mR / 2, -mR * controlPercent, mR, 0F)
            mPath.rQuadTo(mR / 2, mR * controlPercent, mR, 0F)
        }
        mPath.rLineTo(0F, mR * 2)
        mPath.lineTo(controlOffset - mR * 2, mCenterY * 2)
        mPath.rLineTo(0F, -mR * 2)
        mPath.close()
        canvas?.drawPath(mPath, mPaint)
        canvas?.clipPath(mPath)
        mPaint.color = bottomColor
        canvas?.drawText(text, mCenterX, mCenterY - mBaseline, mPaint)
    }

}

使用

xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="#000">

    <com.zmp.pagedemo.view.WavTextView
        android:id="@+id/wtv1"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <com.zmp.pagedemo.view.WavTextView
        android:id="@+id/wtv2"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <com.zmp.pagedemo.view.WavTextView
        android:id="@+id/wtv3"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <com.zmp.pagedemo.view.WavTextView
        android:id="@+id/wtv4"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />
</LinearLayout>

Activity

private fun initView() {
        wtv1.text = "锲而不舍"
        wtv1.topColor = Color.MAGENTA
        wtv1.bottomColor = Color.WHITE
        wtv2.text = "舍身取义"
        wtv2.topColor = Color.RED
        wtv2.bottomColor = Color.GREEN
        wtv3.text = "义不容辞"
        wtv3.topColor = Color.MAGENTA
        wtv4.text = "辞富居贫"
        wtv4.bottomColor = Color.RED
    }
``