一、常见的汽车仪表
我们今天实现的是第二种,代码如下
public class ArcMeterView extends View implements ValueAnimator.AnimatorUpdateListener {
private static final int ARC_STRONG_COLOR = 0xff555771;
private static final int ARC_THIN_COLOR = 0xff7b7c8f;
private static final int TAG_BACKGROUND_COLOR = 0xFF3B3C57;
private static final int SCALE_MARK_CLOE = 0xFFA4A4B2;
private TextPaint mArcPaint;
private TextPaint mScaleMarkPaint;
private TextPaint mScaleTextPaint;
private TextPaint mTagTextPaint;
private TextPaint mTextPaint; //仪表盘文字
private DisplayMetrics mDM;
private int mWidth;
private int mHeight;
private float strongArcWidth;
private float thinArcWidth;
private String mTagText = "";
private Pair<TextBlock, TextBlock> mTextBoxPair;
private ValueAnimator mAngleAnimator;
private ScaleText[] mScaleTextArray = null;
private final float OFFSET_ARC_ANGLE = 5F;
private float currentArcAngle = 0f;
private int currentArcColor = Color.TRANSPARENT;
private float targetArcAngle = 0f;
private int targetArcColor = 0xFFFE5561;
private int fromArcColor = Color.TRANSPARENT;
private float mScalePerDegree = 180;
private int DEFAULT_ARC_COLOR = 0xFF25C384;
private float textBoxPadding = 0;
public ArcMeterView(Context context) {
this(context, null);
}
public ArcMeterView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public ArcMeterView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mDM = getResources().getDisplayMetrics();
initPaint();
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
}
private void initPaint() {
// 实例化画笔并打开抗锯齿
mArcPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
mArcPaint.setAntiAlias(true);
mArcPaint.setStyle(Paint.Style.STROKE);
mArcPaint.setStrokeCap(Paint.Cap.ROUND);
mScaleMarkPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
mScaleMarkPaint.setAntiAlias(true);
mScaleMarkPaint.setStyle(Paint.Style.STROKE);
mScaleMarkPaint.setStrokeCap(Paint.Cap.SQUARE);
mScaleTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
mScaleTextPaint.setAntiAlias(true);
mScaleTextPaint.setStyle(Paint.Style.FILL);
mScaleTextPaint.setStrokeCap(Paint.Cap.SQUARE);
mTagTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
mTagTextPaint.setAntiAlias(true);
mTagTextPaint.setStyle(Paint.Style.FILL);
mTagTextPaint.setStrokeCap(Paint.Cap.SQUARE);
mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setAntiAlias(true);
mTextPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mTextPaint.setStrokeCap(Paint.Cap.SQUARE);
// Typeface textFont = TypefaceManager.get(R.string.font_cm_main_percent);
// mTextPaint.setTypeface(textFont);
strongArcWidth = dp2px(16);
thinArcWidth = dp2px(1);
textBoxPadding = dp2px(15);
if (isInEditMode()) {
ScaleText[] scaleTextArray = new ScaleText[]{
ScaleText.build(3.0f, 0xffFE5561),
ScaleText.build(2.0f, 0xFFF8A115),
ScaleText.build(1.0f, 0xFF25C384),
ScaleText.build(0f, 0xFF25C384)};
initScaleTexts(scaleTextArray);
TextBlock before = new TextBlock(2.2f, "度", "温度");
before.setMarkTextColor(0xffFE5561 );
before.setTextColor(0xFF25C384);
TextBlock after = new TextBlock(0.2f, "KPa", "压强");
setTextBlocks("负载稳定", 1.9f, before, after);
}
}
private boolean isDebug() {
return true;
}
public float dp2px(float dp) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mDM);
}
public float sp2px(float dp) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, dp, mDM);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
if (widthMode != MeasureSpec.EXACTLY) {
widthSize = mDM.widthPixels / 2;
}
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (heightMode != MeasureSpec.EXACTLY) {
heightSize = widthSize / 2;
}
setMeasuredDimension(widthSize, heightSize);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;
mHeight = (int) (h - dp2px(14));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float strokeWidth = mArcPaint.getStrokeWidth();
if (Math.min(mWidth, mHeight) < strokeWidth * 2) {
return;
}
float strongArcOffsetR = dp2px(10);
drawArcMeter(canvas, strongArcWidth, strongArcWidth, ARC_STRONG_COLOR, strongArcOffsetR);
float radiusThinArcOffset = strongArcWidth * 3 + dp2px(5);
drawArcMeter(canvas, thinArcWidth, strongArcWidth, ARC_THIN_COLOR, radiusThinArcOffset);
drawArcMeter(canvas, strongArcWidth, strongArcWidth, strongArcOffsetR, currentArcAngle, currentArcColor);
drawMeterScale(canvas, strongArcWidth,dp2px(5));
drawTag(canvas, strongArcWidth, radiusThinArcOffset);
drawTextBlock(canvas);
}
private void drawTextBlock(Canvas canvas) {
if (mTextBoxPair == null || mTextBoxPair.first == null) return;
float centerX = mWidth / 2.0f;
int count = canvas.save();
canvas.translate(centerX, mHeight - strongArcWidth / 2);
float textPadding = dp2px(3);
if (mTextBoxPair.first != null && mTextBoxPair.second != null) {
int minTextBoxHeight = Integer.MAX_VALUE;
TextBlock[] textBoxes = {mTextBoxPair.first, mTextBoxPair.second};
for (int i = 0; i < 2; i++) {
float mark = (float) Math.cos(Math.toRadians(180 + i * 90));
float markAxis = (float) Math.cos(Math.toRadians(-180 + 180 * i));
TextBlock textBox = textBoxes[i];
float textWidth = measureTextWidth(mTextPaint, textBox.textSize, textBox.text);
float topTextWidth = textWidth + textPadding + measureTextWidth(mTextPaint, textBox.markTextSize, textBox.markText);
float bottomTextWidth = measureTextWidth(mTextPaint, textBox.subTextSize, textBox.subText);
float maxTextWidth = Math.max(topTextWidth, bottomTextWidth);
float textOffsetHeight = 0;
float textHeight = 0;
mTextPaint.setTextSize(sp2px(textBox.subTextSize));
mTextPaint.setColor(textBox.subTextColor);
mTextPaint.setFakeBoldText(false);
canvas.drawText(textBox.subText, bottomTextWidth * mark + (maxTextWidth - bottomTextWidth) / 2 * markAxis + textBoxPadding * markAxis, -getTextPaintBaseline(mTextPaint), mTextPaint);
textOffsetHeight += getTextHeight(mTextPaint);
mTextPaint.setTextSize(sp2px(textBox.textSize));
mTextPaint.setColor(textBox.textColor);
mTextPaint.setFakeBoldText(true);
canvas.drawText(textBox.text, topTextWidth * mark + textBoxPadding * markAxis, -getTextPaintBaseline(mTextPaint) - textOffsetHeight, mTextPaint);
textOffsetHeight += getTextPaintBaseline(mTextPaint);
textHeight = getTextHeight(mTextPaint);
mTextPaint.setTextSize(sp2px(textBox.markTextSize));
mTextPaint.setColor(textBox.markTextColor);
mTextPaint.setFakeBoldText(false);
canvas.drawText(textBox.markText, topTextWidth * mark + textWidth + textPadding + textBoxPadding * markAxis, -textOffsetHeight, mTextPaint);
minTextBoxHeight = (int) Math.min(textOffsetHeight + textHeight, minTextBoxHeight);
}
float lineWidth = dp2px(1f);
float offsetlineTop = dp2px(5);
canvas.drawLine(-lineWidth / 2, -minTextBoxHeight / 3 + offsetlineTop, lineWidth / 2, -minTextBoxHeight * 2 / 3 + offsetlineTop, mScaleMarkPaint);
} else {
TextBlock textBox = mTextBoxPair.first;
float textWidth = measureTextWidth(mTextPaint, textBox.textSize, textBox.text);
float topTextWidth = textWidth + textPadding + measureTextWidth(mTextPaint, textBox.markTextSize, textBox.markText);
float bottomTextWidth = measureTextWidth(mTextPaint, textBox.subTextSize, textBox.subText);
float textHeight = 0;
mTextPaint.setFakeBoldText(false);
mTextPaint.setTextSize(sp2px(textBox.subTextSize));
mTextPaint.setColor(textBox.subTextColor);
canvas.drawText(textBox.subText, -bottomTextWidth / 2, -getTextPaintBaseline(mTextPaint), mTextPaint);
textHeight += getTextHeight(mTextPaint);
mTextPaint.setFakeBoldText(true);
mTextPaint.setTextSize(sp2px(textBox.textSize));
mTextPaint.setColor(textBox.textColor);
canvas.drawText(textBox.text, -topTextWidth / 2, -getTextPaintBaseline(mTextPaint) - textHeight, mTextPaint);
textHeight += getTextPaintBaseline(mTextPaint);
mTextPaint.setFakeBoldText(false);
mTextPaint.setTextSize(sp2px(textBox.markTextSize));
mTextPaint.setColor(textBox.markTextColor);
canvas.drawText(textBox.markText, -topTextWidth / 2 + textWidth + textPadding, -textHeight, mTextPaint);
}
canvas.restoreToCount(count);
}
private float measureTextWidth(TextPaint textPaint, int textSize, String text) {
textPaint.setTextSize(sp2px(textSize));
return textPaint.measureText(text);
}
private void drawTag(Canvas canvas, float offsetTop, float offset) {
if (TextUtils.isEmpty(mTagText)) {
return;
}
int count = canvas.save();
float minSize = getMinSize();
mTagTextPaint.setColor(Color.WHITE);
mTagTextPaint.setTextSize(sp2px(12));
float centerX = mWidth / 2.0f;
canvas.translate(centerX, mHeight - offsetTop);
float textPadding = dp2px(11);
float textHeight = getTextHeight(mTagTextPaint) + textPadding;
float baseline = getTextPaintBaseline(mTagTextPaint);
float textWidth = mTagTextPaint.measureText(mTagText);
RectF rectF = new RectF();
rectF.left = -textWidth / 2 - textPadding;
rectF.right = textWidth / 2 + textPadding;
int R = (int) ((minSize - mTagTextPaint.getStrokeWidth() - offset) * 4 / 5);
rectF.top = -R;
rectF.bottom = -R + textHeight;
Paint paint = new Paint();
paint.setColor(TAG_BACKGROUND_COLOR);
paint.setStyle(Paint.Style.FILL);
canvas.drawRoundRect(rectF, textHeight, textHeight, paint);
canvas.drawText(mTagText, rectF.centerX() - textWidth / 2, rectF.centerY() + baseline, mTagTextPaint);
canvas.restoreToCount(count);
}
private float getMinSize() {
float minSize = Math.min(mWidth, mHeight);
if (minSize > mWidth / 2f) {
minSize = mWidth / 2f;
}
return minSize;
}
public void initScaleTexts(ScaleText[] scaleTextArray) {
this.mScaleTextArray = scaleTextArray;
if (mScaleTextArray == null || mScaleTextArray.length == 0) {
mScalePerDegree = 180f;
return;
}
int textCount = mScaleTextArray.length;
ScaleText[] scaleTexts = mScaleTextArray;
if (textCount == 1) {
scaleTexts = new ScaleText[]{ScaleText.build(""), mScaleTextArray[0]};
}
for (int i = 0; i < scaleTexts.length; i++) {
int h = i;
for (int j = h + 1; j < scaleTexts.length; j++) {
if (scaleTexts[h].fraction > scaleTexts[j].fraction) {
h = j;
}
}
if (h == i) continue;
ScaleText swap = scaleTexts[i];
scaleTexts[i] = scaleTexts[h];
scaleTexts[h] = swap;
}
float minScaleFraction = scaleTexts[0].fraction;
float maxScaleFraction = scaleTexts[scaleTexts.length - 1].fraction;
if (minScaleFraction < 0) {
throw new IllegalArgumentException("the start scale point should be positive number");
}
if (maxScaleFraction == minScaleFraction) {
throw new IllegalArgumentException("don't allow the start scale point equals the scale end point");
}
DEFAULT_ARC_COLOR = scaleTexts[0].scaleColor;
targetArcColor = DEFAULT_ARC_COLOR;
mScaleTextArray = scaleTexts;
mScalePerDegree = (180f / (maxScaleFraction));
}
//真实宽度 + 笔画上下两侧间隙(符合文本绘制基线)
private static int getTextHeight(Paint paint) {
Paint.FontMetricsInt fm = paint.getFontMetricsInt();
int textHeight = ~fm.top - (~fm.top - ~fm.ascent) - (fm.bottom - fm.descent);
return textHeight;
}
/**
* 基线到中线的距离=(Descent+Ascent)/2-Descent
* 注意,实际获取到的Ascent是负数。公式推导过程如下:
* 中线到BOTTOM的距离是(Descent+Ascent)/2,这个距离又等于Descent+中线到基线的距离,即(Descent+Ascent)/2=基线到中线的距离+Descent。
*/
public static float getTextPaintBaseline(Paint p) {
Paint.FontMetrics fontMetrics = p.getFontMetrics();
return (fontMetrics.descent - fontMetrics.ascent) / 2 - fontMetrics.descent;
}
private float drawArcMeter(Canvas canvas, float lineWidthPixels, float offsetTop, int color, float offsetR) {
int count = canvas.save();
mArcPaint.setStrokeWidth(lineWidthPixels);
mArcPaint.setColor(color);
float minSize = getMinSize();
float R = (minSize - lineWidthPixels * 2 - offsetR);
RectF oval = new RectF();//注意,该矩形区域需要保证为正方形,否则可能导致圆弧夹角过大
oval.left = -R;
oval.top = -R;
oval.bottom = R;
oval.right = R;
float centerX = mWidth / 2.0f;
canvas.translate(centerX, mHeight - offsetTop);
canvas.drawArc(oval, 180 - OFFSET_ARC_ANGLE, 180 + OFFSET_ARC_ANGLE * 2, false, mArcPaint);
canvas.restoreToCount(count);
return R;
}
private void drawArcMeter(Canvas canvas, float arcWidth, float offsetTop, float offsetR, float sweepAngle, int color) {
int count = canvas.save();
mArcPaint.setStrokeWidth(arcWidth);
mArcPaint.setColor(color);
float minSize = getMinSize();
int R = (int) (minSize - arcWidth * 2 - offsetR);
RectF oval = new RectF();
oval.left = -R;
oval.top = -R;
oval.bottom = R;
oval.right = R;
float centerX = mWidth / 2.0f;
canvas.translate(centerX, mHeight - offsetTop);
canvas.drawArc(oval, 180 - OFFSET_ARC_ANGLE, sweepAngle, false, mArcPaint);
canvas.restoreToCount(count);
}
/**
* 本方法绘制刻度,注意,这里绘制刻度只是简单计算,实际上应该计算刻度高度+文字高度
* @param canvas
* @param offsetTop
* @param offsetR
*/
private void drawMeterScale(Canvas canvas, float offsetTop,float offsetR) {
if (mScaleTextArray == null || mScaleTextArray.length == 0) {
return;
}
ScaleText[] scaleTexts = mScaleTextArray;
int count = canvas.save();
mScaleMarkPaint.setStrokeWidth(thinArcWidth);
mScaleMarkPaint.setColor(SCALE_MARK_CLOE);
float centerX = mWidth / 2.0f;
canvas.translate(centerX, mHeight - offsetTop);
float minSize = getMinSize();
int R = (int) (minSize - strongArcWidth * 2-offsetR/3);
int OR = (int) (R + offsetR);
for (int i = 0; i < scaleTexts.length; i++) {
ScaleText scaleText = scaleTexts[i];
double radian = Math.toRadians(180f + mScalePerDegree * scaleText.fraction);
float startX = (float) (Math.cos(radian) * R);
float startY = (float) (Math.sin(radian) * R);
float endX = (float) (Math.cos(radian) * OR);
float endY = (float) (Math.sin(radian) * OR);
canvas.drawLine(startX, startY, endX, endY, mScaleMarkPaint);
String text = scaleText.text;
mScaleTextPaint.setTextSize(sp2px(scaleText.textSize));
mScaleTextPaint.setColor(scaleText.textColor);
float baseline = getTextPaintBaseline(mScaleTextPaint);
float textWidth = mScaleTextPaint.measureText(text);
float textHeight = getTextHeight(mScaleTextPaint);
RectF rectF = new RectF();
rectF.right = endX;
rectF.bottom = endY;
rectF.left = (float) (Math.cos(radian) * (OR + textWidth + dp2px(3)));
rectF.top = (float) (Math.sin(radian) * (OR + textHeight + dp2px(3)));
canvas.drawText(text, rectF.centerX() - textWidth / 2, rectF.centerY() + baseline, mScaleTextPaint);
}
canvas.restoreToCount(count);
}
//设置仪表盘数据
public void setTextBlocks(String tagText, float fraction, TextBlock leftBoost, TextBlock rightBoost) {
mTagText = tagText;
mTextBoxPair = new Pair<>(leftBoost, rightBoost);
float arcAngle = OFFSET_ARC_ANGLE + fraction * mScalePerDegree;
fromArcColor = targetArcColor;
targetArcColor = computeScaleColor(fraction);
if (targetArcAngle == arcAngle) {
fromArcColor = targetArcColor;
postInvalidate();
return;
}
if(isInEditMode()){
currentArcColor = targetArcColor;
currentArcAngle = arcAngle;
}else{
startAngleAnimation(targetArcAngle, arcAngle);
}
}
public int computeScaleColor(float fraction) {
int textCount = mScaleTextArray.length;
for (int i = textCount - 1; i >= 0; i--) {
ScaleText scaleText = mScaleTextArray[i];
if (fraction >= scaleText.fraction) {
int color = scaleText.scaleColor;
return color;
}
}
return DEFAULT_ARC_COLOR;
}
private void startAngleAnimation(float from, float to) {
targetArcAngle = to;
if (mAngleAnimator != null) {
mAngleAnimator.cancel();
}
mAngleAnimator = ValueAnimator.ofFloat(from, to);
mAngleAnimator.setStartDelay(300);
mAngleAnimator.setDuration(500);
mAngleAnimator.setInterpolator(new AccelerateInterpolator());
mAngleAnimator.addUpdateListener(this);
mAngleAnimator.start();
}
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentArcAngle = (float) animation.getAnimatedValue();
float f = animation.getAnimatedFraction();
int alpha = (int) (f * Color.alpha(targetArcColor) + (1 - f) * Color.alpha(fromArcColor));
int red = (int) (f * Color.red(targetArcColor) + (1 - f) * Color.red(fromArcColor));
int green = (int) (f * Color.green(targetArcColor) + (1 - f) * Color.green(fromArcColor));
int blue = (int) (f * Color.blue(targetArcColor) + (1 - f) * Color.blue(fromArcColor));
currentArcColor = argb(alpha, red, green, blue);
invalidate();
}
public static int argb(
int alpha,
int red,
int green,
int blue) {
return (alpha << 24) | (red << 16) | (green << 8) | blue;
}
public static class TextBlock {
private String text;
private String markText;
private String subText;
private float scaleFraction;
private int textColor = 0xffF8A115;
private int markTextColor = 0xffF8A115;
private int subTextColor = 0xffffffff;
private int textSize = 40;
private int markTextSize = 14;
private int subTextSize = 16;
public TextBlock(float value, String markText, String subText) {
this.text = String.format("%.1f", value);
this.scaleFraction = value;
this.markText = markText;
this.subText = subText;
}
public TextBlock(float value, String text, String markText, String subText) {
this.text = text;
this.scaleFraction = value;
this.markText = markText;
this.subText = subText;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getMarkText() {
return markText;
}
public void setMarkText(String markText) {
this.markText = markText;
}
public String getSubText() {
return subText;
}
public void setSubText(String subText) {
this.subText = subText;
}
public int getTextColor() {
return textColor;
}
public void setTextColor(int textColor) {
this.textColor = textColor;
}
public int getMarkTextColor() {
return markTextColor;
}
public void setMarkTextColor(int markTextColor) {
this.markTextColor = markTextColor;
}
public int getSubTextColor() {
return subTextColor;
}
public void setSubTextColor(int subTextColor) {
this.subTextColor = subTextColor;
}
public int getTextSize() {
return textSize;
}
public void setTextSize(int textSize) {
this.textSize = textSize;
}
public int getMarkTextSize() {
return markTextSize;
}
public void setMarkTextSize(int markTextSize) {
this.markTextSize = markTextSize;
}
public int getSubTextSize() {
return subTextSize;
}
public void setSubTextSize(int subTextSize) {
this.subTextSize = subTextSize;
}
}
public static class ScaleText {
private String text;
private int textColor = 0xFFA4A4B2;
private int textSize = 12;
private int scaleColor = 0xFFFE5561;
private float fraction;
public static ScaleText build(float fraction, String text, int scaleColor) {
ScaleText st = new ScaleText();
st.text = text;
st.fraction = fraction;
st.scaleColor = scaleColor;
return st;
}
public static ScaleText build(float fraction, int scaleColor) {
ScaleText st = new ScaleText();
st.text = String.format("%.1f", fraction);
st.fraction = fraction;
st.scaleColor = scaleColor;
return st;
}
public static ScaleText build(String text) {
ScaleText st = new ScaleText();
st.text = text;
st.fraction = 0;
return st;
}
public static ScaleText build(float fraction, String text, int color, int textSize, int scaleColor) {
ScaleText st = new ScaleText();
st.text = text;
st.fraction = fraction;
st.textColor = color;
st.textSize = textSize;
st.scaleColor = scaleColor;
return st;
}
public static ScaleText build(float fraction, int color, int textSize, int scaleColor) {
ScaleText st = new ScaleText();
st.text = String.format("%.1f", fraction);
st.fraction = fraction;
st.textColor = color;
st.textSize = textSize;
st.scaleColor = scaleColor;
return st;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public int getTextColor() {
return textColor;
}
public void setTextColor(int textColor) {
this.textColor = textColor;
}
public int getTextSize() {
return textSize;
}
public void setTextSize(int textSize) {
this.textSize = textSize;
}
public int getScaleColor() {
return scaleColor;
}
public void setScaleColor(int scaleColor) {
this.scaleColor = scaleColor;
}
}
}
三、使用方法
mArcMeterView = findViewById(R.id.arcMeterView);
mArcMeterView.initScaleTexts(new ArcMeterView.ScaleText[]{
ArcMeterView.ScaleText.build(0f,0xFF25C384),
ArcMeterView.ScaleText.build(1.0f,0xFFF8A115),
ArcMeterView.ScaleText.build(2.0f,0xffFE5561),
ArcMeterView.ScaleText.build(3.0f,0xffFE5561)
});
ArcMeterView.TextBlock ITextBlock = new ArcMeterView.TextBlock(0.9f,"mAh","电流");
ITextBlock.setTextColor(0xFF25C384);
ITextBlock.setMarkTextColor(0xFF25C384);
ArcMeterView.TextBlock UTextBlock = new ArcMeterView.TextBlock(2,"V","电压");
UTextBlock.setTextColor(0xffFE5561);
UTextBlock.setMarkTextColor(0xffFE5561);
mArcMeterView.setTextBlocks("负载正常",0.9f,ITextBlock,UTextBlock);