Android 自定义View——字体渐变

Android 自定义View(二)——字体渐变

目录

Android 自定义View(二)——字体闪烁

1、创建自定义属性

2、创建自定义VIew

3、设置布局

4、MainActivity


示例图

1、创建自定义属性

        values创建attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="ColorTrackTextView">
        <attr name="originColor" format="color"/>
        <attr name="changeColor" format="color"/>
    </declare-styleable>
</resources>

2、创建自定义VIew

public class ColorTrackTextView extends AppCompatTextView {

    // 绘制不变色字体的画笔
    private Paint mOriginPaint;
    // 绘制变色字体的画笔
    private Paint mChangePaint;
    // 当前变色的进度
    private float mCurrentProgress = 0.5f;

    // 实现不同朝向
    private Direction mDirection;
    public enum Direction {
        LEFT_TO_RIGHT, RIGHT_TO_LEFT
    }

    public ColorTrackTextView(@NonNull Context context) {
        this(context, null);
    }

    public ColorTrackTextView(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ColorTrackTextView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        initPaint(context, attrs);
    }

    private void initPaint(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ColorTrackTextView);

        int originColor = typedArray.getColor(R.styleable.ColorTrackTextView_originColor, getTextColors().getDefaultColor());
        int changeColor = typedArray.getColor(R.styleable.ColorTrackTextView_changeColor, getTextColors().getDefaultColor());

        // 回收
        typedArray.recycle();

        // 不变色的画笔
        mOriginPaint = getPaintByColor(originColor);
        // 变色的画笔
        mChangePaint = getPaintByColor(changeColor);
    }

    /**
     * 根据颜色获取画笔
     */
    private Paint getPaintByColor(int color) {
        Paint paint = new Paint();
        // 设置颜色
        paint.setColor(color);
        // 设置抗锯齿
        paint.setAntiAlias(true);
        // 防抖动
        paint.setDither(true);
        // 设置字体的大小
        paint.setTextSize(getTextSize());
        return paint;
    }

    @Override
    protected void onDraw(Canvas canvas) {

        int currentPoint = (int) (mCurrentProgress * getWidth());

        // 从左边到右边变色
        if (mDirection == Direction.LEFT_TO_RIGHT) {
            // 绘制变色的部分 -- 开始 currentPoint = 0;结束 currentPoint = getWidth
            drawText(canvas, mChangePaint, 0, currentPoint);
            // 绘制不变色的部分
            drawText(canvas, mOriginPaint, currentPoint, getWidth());
        } else {
            // 绘制变色的部分 -- 开始 currentPoint = getWidth;结束 currentPoint = 0
            drawText(canvas, mChangePaint, getWidth() - currentPoint, getWidth());
            // 绘制不变色的部分
            drawText(canvas, mOriginPaint, 0, getWidth() - currentPoint);
        }
    }


    private void drawText(Canvas canvas, Paint paint, int start, int end) {
        // 此时要保存这个图层,进行操作
        canvas.save();
        Rect rect = new Rect(start, 0, end, getHeight());
        // 用于裁剪绘图区域
        canvas.clipRect(rect);

        String text = getText().toString();
        // 判空
        if (TextUtils.isEmpty(text)) return;

        // 获取文字的区域
        Rect bounds = new Rect();
        paint.getTextBounds(text, 0, text.length(), bounds);
        // 获取x坐标
        int dx = getWidth() / 2 - bounds.width() / 2;
        // 获取基线  baseLine
        Paint.FontMetricsInt fontMetricsInt = mChangePaint.getFontMetricsInt();
        int dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;
        int baseLine = getHeight() / 2 + dy;

        // 绘制文字
        canvas.drawText(text, dx, baseLine, paint);

        // 绘制为 未操作的图层。
        canvas.restore();
    }

    public void setCurrentProgress(float currentProgress) {
        this.mCurrentProgress = currentProgress;
        invalidate();
    }

    public void setDirection(Direction direction) {
        this.mDirection = direction;
    }

}

        注意:首先文字宽高是不能直接获取的,需要获取,这里首先调用getTextBounds()把文字框起来了,这样就有一个宽高的样子。计算文字宽高需要一个baseline

baseline图参数含义

  • FontMetricInt.top:这是一个负数,顶部到baseline的距离,一般文字到达不了,为什么需要有这个呢,因为国际化的原因。
  • FontMetricInt.ascent:是文字当前顶部的位置。
  • FontMetricInt.descent:是文字当前底部的位置。
  • FontMetricInt.bottom:这是一个正数,底部到baseline的距离,一般文字到达不了,为什么需要有这个呢,因为国际化的原因。
Paint.FontMetricsInt fontMetricsInt = mChangePaint.getFontMetricsInt();
int dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;
// baselin的高度
int baseLine = getHeight() / 2 + dy;

       根据上例代码,看图中的绿色字 baseline,这个需要求的。FontMetricInt.bottom 正数 - FontMetricInt.top 负数,就得到整个文字的整个高度。然后需要 /2 得到文字正中间,减去 fontMetricsInt.bottom,就得到了baseline那空隙的高度。然后和view的高度 /2 + dy空隙高度,就是baseLine高度。(如下图)

3、设置布局

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <com.dfg.colortracktextview.ColorTrackTextView
        android:id="@+id/color_track_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World"
        android:textSize="20sp"
        app:changeColor="#FF8A80"
        app:originColor="#EA80FC"/>

    <Button
        android:id="@+id/left_to_right"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="从左往右"/>

    <Button
        android:id="@+id/right_to_left"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="从右往左"/>
</LinearLayout>

4、MainActivity

class MainActivity : AppCompatActivity() {

    lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.rightToLeft.setOnClickListener {
            setAnimation(ColorTrackTextView.Direction.RIGHT_TO_LEFT);
        }

        binding.leftToRight.setOnClickListener {
            setAnimation(ColorTrackTextView.Direction.LEFT_TO_RIGHT);
        }
    }

    fun setAnimation(direction: ColorTrackTextView.Direction?) {
        binding.colorTrackTv.setDirection(direction)
        val valueAnimator = ObjectAnimator.ofFloat(0f, 1f)
        valueAnimator.duration = 2000
        valueAnimator.addUpdateListener { animation ->
            val currentProgress = animation.animatedValue as Float
            binding.colorTrackTv.setCurrentProgress(currentProgress)
        }
        valueAnimator.start()
    }
}

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值