Android自定义控件入门 05 仿TabLayout字体根据滑动变色

118 阅读2分钟

1.效果展示和思路分析

画笔Paint的使用

  • TextView可行?系统提供的只能够显示一种颜色,需要自定View
  • 自定义View继承自谁extends View:onMeasure() onDraw()
  • extends TextView :onMeasure()不需要实现textColor颜色 textSize字体大小 会少很多逻辑
  1. 一个文字两种颜色 两个画笔画
  2. 能够从左到右,从右到左
  3. 整合到ViewPager
  4. 自定义属性:不变化的颜色 originColor 变化的颜色 changeColor

2.一个文字两种颜色

两个画笔画,用的是裁剪canvas.#clipRect()

3.实现不同朝向

左边是不变色右边是变色的,左边是不变色的右边是变色

4.自定义属性

<declare-styleable name="ColorTextTrackView">  
    <attr name="originColor" format="reference|color" />  
    <attr name="changeColor" format="reference|color" />  
</declare-styleable>

5.自定义TextView

class ColorTextTrackView @JvmOverloads constructor(  
    context: Context,  
    attributeSet: AttributeSet? = null,  
    defStyleAttr: Int = 0  
) : AppCompatTextView(context, attributeSet, defStyleAttr) {  
    private val originColor: Int  
    private val changeColor: Int  
    private val originPaint: Paint  
    private val changePaint: Paint  
    private var direction: Direction = Direction.LEFT_TO_RIGHT  

    /**  
    * 根据进度把中间值算出来  
    * */  
    private var currentProgress = 0.0F  


    /**  
    * 实现不同功效  
    * */  
    enum class Direction {  
        LEFT_TO_RIGHT, RIGHT_TO_LEFT  
    }  
  
    init {  
        context.obtainStyledAttributes(attributeSet, R.styleable.ColorTextTrackView).apply {  
            originColor = getColor(R.styleable.ColorTextTrackView_originColor, Color.BLACK)  
            changeColor = getColor(R.styleable.ColorTextTrackView_changeColor, Color.RED)  
            recycle()  
        }  
        originPaint = getPaintColor(originColor)  
        changePaint = getPaintColor(changeColor)  
    }  

    private fun getPaintColor(color: Int) = Paint().apply {  
        setColor(color)  
        //设置抗锯齿  
        isAntiAlias = true  
        //防抖动  
        isDither = true  
        this.textSize = this@ColorTextTrackView.textSize  
    }  
  
    private val zero = 0F  

    override fun onDraw(canvas: Canvas) {  
        val middle = currentProgress * width  

        if (direction == Direction.LEFT_TO_RIGHT) {  
            //绘制不变色:left到middle  
            canvas.drawText(originPaint, middle, width.toFloat())  
            //绘制变色:middle到getWidth()  
            canvas.drawText(changePaint, zero, middle)  
        } else {  
            //右边是红色,左边是黑色  
            canvas.drawText(originPaint, zero, width - middle)  
            canvas.drawText(changePaint, width - middle, width.toFloat())  
        }  
    }  
  
  
    private fun Canvas.drawText(paint: Paint, start: Float, end: Float) {  
        val content = text.toString().trim()  
        paint.getTextBounds(content, zero.toInt(), content.length, textRect)  
        val x = (width / 2 - textRect.width() / 2).toFloat()  
        val dy = with(paint.fontMetricsInt) {  
            (bottom - top) / 2 - bottom  
        }  
        val baseLine = (height / 2).toFloat() + dy  
        save()  
        clipRect(start, zero, end, height.toFloat())  
        drawText(content, x, baseLine, paint)  
        restore()  
    }  
  
    private val textRect by lazy { Rect() }  

    fun refreshDirection(direction: Direction) {  
        this.direction = direction  
    }  

    fun refreshCurrentProgress(progress: Float) {  
        this.currentProgress = progress  
        invalidate()  
    }  

    fun refreshOriginColor(originColor: Int) {  
        originPaint.color = originColor  
    }  

    fun refreshChangeColor(changeColor: Int) {  
        changePaint.color = changeColor  
    }  
}

6.UI

class ViewPagerActivity : AppCompatActivity() {  
    private val itemArray by lazy { mutableListOf("直播", "推荐", "视频", "图片", "段子", "精华") }  
    private val fragmentArray by lazy {  
        with(mutableListOf<Fragment>()) {  
        itemArray.forEach {  
                add(ItemFragment.newInstance(it))  
            }  
            this  
        }  
    }  
    private val indicatorList = mutableListOf<ColorTextTrackView>()  

    override fun onCreate(savedInstanceState: Bundle?) {  
    super.onCreate(savedInstanceState)  
    setContentView(R.layout.activity_view_pager)  
    val trackGroup = findViewById<LinearLayout>(R.id.track_group).apply {  
        //代码动态添加ColorTextTrackView  
        itemArray.forEach {  
            val view = ColorTextTrackView(this@ViewPagerActivity).let { v ->  
                val wrap = LayoutParams.WRAP_CONTENT  
                v.text = it  
                v.textSize = 20F  
                v.refreshChangeColor(Color.RED)  
                v.layoutParams = LayoutParams(wrap, wrap, 1F)  
                v  
            }  
            indicatorList.add(view)  
            addView(view)  
        }  
    }  
        val trackPager = findViewById<ViewPager2>(R.id.track_pager)  
        trackPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {  
            override fun onPageScrolled(  
                position: Int,  
                positionOffset: Float,  
                positionOffsetPixels: Int  
            ) {  
                super.onPageScrolled(position, positionOffset, positionOffsetPixels)  
                /**  
                * positionOffset  
                * 从右往左滑,变大  
                * 从左往右滑,变小  
                * */  
                //1.左边,位置 position  
                val left = indicatorList[position].apply {  
                    refreshDirection(ColorTextTrackView.Direction.RIGHT_TO_LEFT)  
                    refreshCurrentProgress(1 - positionOffset)  
                }  
                if ((position) < indicatorList.size - 1) {  
                    val right = indicatorList[position + 1].apply {  
                        refreshDirection(ColorTextTrackView.Direction.LEFT_TO_RIGHT)  
                        refreshCurrentProgress(positionOffset)  
                }  
            }  
        }  
        })  
        trackPager.adapter = object : FragmentStateAdapter(this) {  
            override fun getItemCount(): Int = fragmentArray.size  

            override fun createFragment(position: Int): Fragment = fragmentArray[position]  

        }  
    }  
}