笔者最近在做电子书开发,在开发过程中碰到一个比较抠细节的地方:对字体宽高进行计算,so:对影响字体宽高的因素进行了一波分析:
主要是对如下信息进行分析对比:文字(中英文标点符号,加粗,斜体,字体)
加粗和斜体为了保证所有系统都能运行都用的Typeface的常量进行控制。
字体主要是采用了四种:Sans、Serif、Mono、自定义(涉及到版权问题就不说了,自己放到asset文件夹下就可以了);
代码如下:
public class ShowTextViewextends View {
private PaintmPaint;
// public String string = "ap卡了ξτβбпшㄎㄊěǔぬも┰┠№@↓";
public Stringstring ="中国";
public ShowTextView(Context context) {
super(context);
}
public ShowTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ShowTextView(Context context,AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setPaint(Paint paint){
this.mPaint = paint;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawText(string, 0, 100, mPaint);
canvas.drawLine(0, 100, 1000, 100, mPaint);
Paint.FontMetrics m =mPaint.getFontMetrics();
canvas.drawLine(0, 100 + m.ascent ,1000, 100 + m.ascent, mPaint);
canvas.drawLine(0, 100 + m.descent ,1000, 100 + m.descent, mPaint);
}
}
activity代码:
public class FontSizeActivityextends AppCompatActivity {
public static final StringTAG ="FontSizeActivity";
@BindView(R.id.font_size_tv)
TextViewfontSizeTv;
@BindView(R.id.bold_check_box)
CheckBoxboldCheckBox;
@BindView(R.id.italic_check_box)
CheckBoxitalicCheckBox;
@BindView(R.id.font_family_rg)
RadioGroupfontFamilyRg;
@BindView(R.id.log_tv)
TextViewlogTv;
@BindView(R.id.show_text_view)
ShowTextViewshowTextView;
private boolean isBold =false;
private boolean isItalic =false;
private int fontSize =100;
private PaintmPaint =new Paint();
private Stringsigle_zh ="国";
private Stringdouble_zh ="中国";
private TypefacecurrentTypeface = Typeface.SANS_SERIF;
private TypefacecustomTypeface;
private CompoundButton.OnCheckedChangeListenercheckedChangeListener =new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
switch (buttonView.getId()) {
case R.id.bold_check_box:
isBold = isChecked;
break;
case R.id.italic_check_box:
isItalic = isChecked;
break;
}
updateTypeface();
measureStringSize();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_font_size);
ButterKnife.bind(this);
((CheckBox)findViewById(R.id.italic_check_box)).setOnCheckedChangeListener(checkedChangeListener);
((CheckBox)findViewById(R.id.bold_check_box)).setOnCheckedChangeListener
(checkedChangeListener);
fontFamilyRg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
switch (checkedId) {
case R.id.rbtn_serif:
currentTypeface = Typeface.SERIF;
break;
case R.id.rbtn_sans:
currentTypeface = Typeface.SANS_SERIF;
break;
case R.id.rbtn_monospace:
currentTypeface = Typeface.MONOSPACE;
break;
case R.id.rbtn_custom:
if (customTypeface ==null) {
customTypeface = Typeface.createFromAsset(getAssets(), "goodNight.ttf");
}
currentTypeface =customTypeface;
break;
}
updateTypeface();
measureStringSize();
}
});
fontSizeTv.setText("" +fontSize);
mPaint.setTextSize(fontSize);
showTextView.setPaint(mPaint);
}
private void updateTypeface() {
Typeface font;
if (isBold) {
font = Typeface.create(currentTypeface, isItalic ? Typeface.BOLD_ITALIC : Typeface.BOLD);
}else {
font = Typeface.create(currentTypeface, isItalic ? Typeface.ITALIC : Typeface.NORMAL);
}
mPaint.setTypeface(font);
}
@OnClick({R.id.font_size_big_btn, R.id.font_size_small_btn})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.font_size_big_btn:
fontSize +=2;
break;
case R.id.font_size_small_btn:
fontSize -=2;
break;
}
fontSizeTv.setText("" +fontSize);
mPaint.setTextSize(fontSize);
measureStringSize();
}
private void measureStringSize() {
showTextView.setPaint(mPaint);
showTextView.invalidate();
Paint.FontMetrics metrics =mPaint.getFontMetrics();
String metricsStr = String.format("metrics = ascent: %f, bottom: %f,descent: %f, leading:%f, top: %f",
metrics.ascent, metrics.bottom, metrics.descent, metrics.leading, metrics.top);
Log.d(TAG, metricsStr);
float sigleChineseW =mPaint.measureText(sigle_zh);
float doubleChineseW =mPaint.measureText(double_zh);
float thirdW =mPaint.measureText(showTextView.string);
Log.i(TAG, "width: 1th: " + sigleChineseW +", 2th : " + doubleChineseW +", 3th : " + thirdW);
}
}
经过调整可以得出以下结论:
1.字体的宽高与加粗、斜体无关;
2.如果不计算字间距的话,字符串的长度为每个字符长度之和
3.字符的高度是Paint.FontMetrics控制的,其与字体(Typeface),字体大小(fontsize)相关。字体大小(fontsize)改变,FontMetrics内的参数会按照比例变化。如果字体大小(fontsize)固定,改变字体(Typeface),会获得不同的参数。如果需要频繁获取字符高度,可以先将字体大小固定为100,获取不同的字体(Typeface)的FontMetrics参数,然后根据响应的参数与字体大小做比例换算。
4.字符的宽度与文字类型,字体大小相关。如果文字不改变,只改变字体大小(fontsize),字符宽度会成比例变化。改变不同的文字会对固定的字体大小(fontsize)的字符宽度产生不同的变化。
5.中文字是方块字(小学老师教的),所以你字体大小(fontsize)又多大,字符宽度就会是多大。