一、今日头条效果
二、自定义实现效果
三、源码实现
1、自定义View
package com.haiheng.myskindemo;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import androidx.annotation.Nullable;
public class MyTextView extends View {
private static final String TAG = "MyTextView";
private String text = "你好,世界";
private Paint mPaint;
private float percent ;
public float getPercent() {
return percent;
}
public void setPercent(float percent) {
this.percent = percent;
invalidate();
}
public MyTextView(Context context) {
super(context);
init();
}
public MyTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public MyTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
Log.e(TAG, "init: ");
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setTextSize(40);
// mPaint.setColor(Color.parseColor("#FF0000"));
}
/**
* 绘制
*
* @param canvas
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.e(TAG, "onDraw: " + canvas);
//画两条中线
// canvas.drawLine(0, (float) getHeight() / 2, (float) getWidth(), (float) getHeight() / 2, mPaint);
//canvas.drawLine(getWidth() / 2, 0, getWidth() / 2, (float) getHeight(), mPaint);
/**
* 绘制第一层文字
*/
drawCenterTextView(canvas);
//再画一层文字
drawCenterTextView2(canvas);
}
private void drawCenterTextView2(Canvas canvas) {
//保存一个画布
canvas.save();
mPaint.setColor(Color.parseColor("#FF0000"));
float height = getHeight();
float width = getWidth();
Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
float ascent = fontMetrics.ascent;
float descent = fontMetrics.descent;
/**
* 测量文字的宽
*/
float textWidth = mPaint.measureText(text) ;
/**
* 中点的横座标
*/
float x = width / 2 - textWidth/2;
/**
* 基准线
*/
float baseLine = height / 2 + (descent - ascent) / 2 - descent;
//裁剪
float left = width/2-textWidth/2;
float top = 0;
float right = left+textWidth*percent;
float bottom =getHeight();
// canvas.drawLine(left,0,left,(int)getHeight(),mPaint);
// canvas.drawLine(right,0,right,(int)getHeight(),mPaint);
Rect rect = new Rect((int)left,(int)top,(int)right,(int)bottom);
canvas.clipRect(rect);
//简单的绘制一个文字
canvas.drawText(text, x, baseLine, mPaint);
canvas.restore();
}
/**
* 绘制在中间
*/
private void drawCenterTextView(Canvas canvas) {
//保存一个画布
canvas.save();
mPaint.setColor(Color.parseColor("#000000"));
float height = getHeight();
float width = getWidth();
Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
float ascent = fontMetrics.ascent;
float descent = fontMetrics.descent;
/**
* 测量文字的宽
*/
float textWidth = mPaint.measureText(text) ;
/**
* 中点的横座标
*/
float x = width / 2 - textWidth/2;
/**
* 基准线
*/
float baseLine = height / 2 + (descent - ascent) / 2 - descent;
//裁剪
float left = (width/2-textWidth/2)+textWidth*percent;
float top = 0;
float right = width/2+textWidth/2;
float bottom =getHeight();
// canvas.drawLine(left,0,left,(int)getHeight(),mPaint);
//canvas.drawLine(right,0,right,(int)getHeight(),mPaint);
Rect rect = new Rect((int)left,(int)top,(int)right,(int)bottom);
canvas.clipRect(rect);
//简单的绘制一个文字
canvas.drawText(text, x, baseLine, mPaint);
canvas.restore();
}
}
2、通过属性动画演示效果
package com.haiheng.myskindemo
import android.animation.ObjectAnimator
import android.os.Bundle
import android.os.Handler
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_text)
val textView = findViewById<MyTextView>(R.id.myTextView)
//属性动画
val arrays = floatArrayOf(0.0f,1.0f)
Handler().postDelayed({
Log.e("MainActivity", "1S开启动画")
ObjectAnimator.ofFloat(textView, "percent", *arrays).setDuration(4000).start()
}, 1000)
}
}
四、小结
- 通过drawText实现文字绘制
- 画布是可以由多层组成的,通过绘制两层文字,并通过裁剪的方式实现
- save和restore结合使用表示保存当前一层画布