Tôi đã không tìm thấy một cách để làm điều này. Có khả thi không?
Tôi đã không tìm thấy một cách để làm điều này. Có khả thi không?
Câu trả lời:
Chà, tôi không thể tìm ra cách làm điều đó với các lớp học có sẵn nên tôi đã tự mình mở rộng lớp học TypefaceSpan
bây giờ nó phù hợp với tôi. Đây là những gì tôi đã làm:
package de.myproject.text.style;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.text.TextPaint;
import android.text.style.TypefaceSpan;
public class CustomTypefaceSpan extends TypefaceSpan {
private final Typeface newType;
public CustomTypefaceSpan(String family, Typeface type) {
super(family);
newType = type;
}
@Override
public void updateDrawState(TextPaint ds) {
applyCustomTypeFace(ds, newType);
}
@Override
public void updateMeasureState(TextPaint paint) {
applyCustomTypeFace(paint, newType);
}
private static void applyCustomTypeFace(Paint paint, Typeface tf) {
int oldStyle;
Typeface old = paint.getTypeface();
if (old == null) {
oldStyle = 0;
} else {
oldStyle = old.getStyle();
}
int fake = oldStyle & ~tf.getStyle();
if ((fake & Typeface.BOLD) != 0) {
paint.setFakeBoldText(true);
}
if ((fake & Typeface.ITALIC) != 0) {
paint.setTextSkewX(-0.25f);
}
paint.setTypeface(tf);
}
}
Trong khi notme về cơ bản có ý tưởng đúng, giải pháp được đưa ra hơi khó hiểu vì "gia đình" trở nên thừa. Nó cũng hơi không chính xác vì TypefaceSpan là một trong những nhịp đặc biệt mà Android biết đến và mong đợi một số hành vi nhất định đối với giao diện ParcelableSpan (mà lớp con của notme không đúng, cũng như không thể thực hiện).
Một giải pháp đơn giản và chính xác hơn sẽ là:
public class CustomTypefaceSpan extends MetricAffectingSpan
{
private final Typeface typeface;
public CustomTypefaceSpan(final Typeface typeface)
{
this.typeface = typeface;
}
@Override
public void updateDrawState(final TextPaint drawState)
{
apply(drawState);
}
@Override
public void updateMeasureState(final TextPaint paint)
{
apply(paint);
}
private void apply(final Paint paint)
{
final Typeface oldTypeface = paint.getTypeface();
final int oldStyle = oldTypeface != null ? oldTypeface.getStyle() : 0;
final int fakeStyle = oldStyle & ~typeface.getStyle();
if ((fakeStyle & Typeface.BOLD) != 0)
{
paint.setFakeBoldText(true);
}
if ((fakeStyle & Typeface.ITALIC) != 0)
{
paint.setTextSkewX(-0.25f);
}
paint.setTypeface(typeface);
}
}
TypefaceSpan
nhưng sau đó Marco đưa ra một ví dụ hoạt động chỉ sử dụng nó. Cái nào là đúng? Benjamin bạn đã thử nghiệm ví dụ của mình chưa?
TypefaceSpan
. Tôi chỉ thực sự khuyên bạn không nên . Làm như vậy vi phạm nguyên tắc thay thế của Liscov và là một hành vi cực kỳ xấu. Bạn đã phân loại phụ một lớp chỉ định phông chữ thông qua family
tên và có thể phân loại được; sau đó bạn đã ghi đè hoàn toàn hành vi đó và làm cho family
tham số trở nên khó hiểu và vô nghĩa, và Span
cũng không phải là giá trị.
Nếu ai đó quan tâm, đây là phiên bản C # Xamarin của mã Benjamin:
using System;
using Android.Graphics;
using Android.Text;
using Android.Text.Style;
namespace Utils
{
//https://stackoverflow.com/a/17961854/1996780
/// <summary>A text span which applies <see cref="Android.Graphics.Typeface"/> on text</summary>
internal class CustomFontSpan : MetricAffectingSpan
{
/// <summary>The typeface to apply</summary>
public Typeface Typeface { get; }
/// <summary>CTor - creates a new instance of the <see cref="CustomFontSpan"/> class</summary>
/// <param name="typeface">Typeface to apply</param>
/// <exception cref="ArgumentNullException"><paramref name="typeface"/> is null</exception>
public CustomFontSpan(Typeface typeface) =>
Typeface = typeface ?? throw new ArgumentNullException(nameof(typeface));
public override void UpdateDrawState(TextPaint drawState) => Apply(drawState);
public override void UpdateMeasureState(TextPaint paint) => Apply(paint);
/// <summary>Applies <see cref="Typeface"/></summary>
/// <param name="paint"><see cref="Paint"/> to apply <see cref="Typeface"/> on</param>
private void Apply(Paint paint)
{
Typeface oldTypeface = paint.Typeface;
var oldStyle = oldTypeface != null ? oldTypeface.Style : 0;
var fakeStyle = oldStyle & Typeface.Style;
if (fakeStyle.HasFlag(TypefaceStyle.Bold))
paint.FakeBoldText = true;
if (fakeStyle.HasFlag(TypefaceStyle.Italic))
paint.TextSkewX = -0.25f;
paint.SetTypeface(Typeface);
}
}
}
Và cách sử dụng: (trong hoạt động OnCreate)
var txwLogo = FindViewById<TextView>(Resource.Id.logo);
var font = Resources.GetFont(Resource.Font.myFont);
var wordtoSpan = new SpannableString(txwLogo.Text);
wordtoSpan.SetSpan(new CustomFontSpan(font), 6, 7, SpanTypes.InclusiveInclusive); //One caracter
txwLogo.TextFormatted = wordtoSpan;
Kiểu chữ có thể mở rộng: Để đặt kiểu chữ phông chữ khác cho một số phần của văn bản, có thể sử dụng TypefaceSpan tùy chỉnh, như được hiển thị trong ví dụ sau:
spannable.setSpan( new CustomTypefaceSpan("SFUIText-Bold.otf",fontBold), 0,
firstWord.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
spannable.setSpan( new CustomTypefaceSpan("SFUIText-Regular.otf",fontRegular),
firstWord.length(), firstWord.length() + lastWord.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
text.setText( spannable );
Tuy nhiên, để làm cho đoạn mã trên hoạt động, lớp CustomTypefaceSpan phải có nguồn gốc từ lớp TypefaceSpan. Điều này có thể được thực hiện như sau:
public class CustomTypefaceSpan extends TypefaceSpan {
private final Typeface newType;
public CustomTypefaceSpan(String family, Typeface type) {
super(family);
newType = type;
}
@Override
public void updateDrawState(TextPaint ds) {
applyCustomTypeFace(ds, newType);
}
@Override
public void updateMeasureState(TextPaint paint) {
applyCustomTypeFace(paint, newType);
}
private static void applyCustomTypeFace(Paint paint, Typeface tf) {
int oldStyle;
Typeface old = paint.getTypeface();
if (old == null) {
oldStyle = 0;
} else {
oldStyle = old.getStyle();
}
int fake = oldStyle & ~tf.getStyle();
if ((fake & Typeface.BOLD) != 0) {
paint.setFakeBoldText(true);
}
if ((fake & Typeface.ITALIC) != 0) {
paint.setTextSkewX(-0.25f);
}
paint.setTypeface(tf);
}
}