自定义字体适用于格式化的字符串吗? [英] Do custom fonts work for formatted string?

查看:71
本文介绍了自定义字体适用于格式化的字符串吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在此处遵循了Sven的自定义字体格式字符串的示例: https://github.com/smstuebe/xamarin-forms-formattedtext

I have followed Sven's example for custom font for formattedstrings here: https://github.com/smstuebe/xamarin-forms-formattedtext

但是,我遇到了一个奇怪的问题,即如果我实现UIFormattedStringLabel(),则视图上的轻击手势不起作用. 这真是太奇怪了,因为如果我使用不使用提供的自定义渲染器的常规标签,就会检测到手势,并显示格式化的字符串(只是字体是默认字体),并且一切都会正确加载.

However, I'm running into a strange issue where the tap gestures on my view don't work if I implement the UIFormattedStringLabel(). This is super strange because if I use a regular label that does not use the custom renderer provided, the gestures are detected, the formatted string is displayed (just the fonts are default) and everything loads correctly.

因此,我认为在上面设置渲染器存在问题,因为问题似乎源于此.也许,我在尝试做的事情上错过了一步.

So, I think there's an issue with setting up the renderer above as the problem seems to stem from that. Perhaps, I am missing a step for what I am trying to do.

using Android.Graphics;
using Android.Text;
using Android.Text.Style;
using Android.Util;
using Android.Widget;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

namespace Proj.Droid.CustomRenderer
{
    public class CustomTypefaceSpan : MetricAffectingSpan
    {
        private readonly Typeface _typeFace;
        private readonly TextView _textView;
        private Font _font;

        public CustomTypefaceSpan(TextView textView, Label label, Font font)
        {
            _textView = textView;
            _font = font;
            _typeFace = Typeface.CreateFromAsset(Forms.Context.Assets, GetFontName(_font.FontFamily ?? label.FontFamily, _font.FontAttributes));
        }

        private static string GetFontName(string fontFamily, FontAttributes fontAttributes)
        {
            var postfix = "Regular";
            var bold = fontAttributes.HasFlag(FontAttributes.Bold);
            var italic = fontAttributes.HasFlag(FontAttributes.Italic);
            if (bold && italic) { postfix = "BoldItalic"; }
            else if (bold) { postfix = "Bold"; }
            else if (italic) { postfix = "Italic"; }

            return $"{fontFamily}-{postfix}.otf";
        }

        public override void UpdateDrawState(TextPaint paint)
        {
            ApplyCustomTypeFace(paint);
        }

        public override void UpdateMeasureState(TextPaint paint)
        {
            ApplyCustomTypeFace(paint);
        }

        private void ApplyCustomTypeFace(Paint paint)
        {
            paint.SetTypeface(_typeFace);
            paint.TextSize = TypedValue.ApplyDimension(ComplexUnitType.Sp, _font.ToScaledPixel(), _textView.Resources.DisplayMetrics);
        }
    }
}

using System.ComponentModel;
using System.Reflection;
using Android.Graphics;
using Android.Text;
using Java.Lang;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Proj.Droid.CustomRenderer;
using Proj.Core.UI.XamarinForms.Controls;
using System;

[assembly: ExportRenderer(typeof(UIFormattedStringLabel), typeof(FormattedLabelRenderer))]
namespace Proj.Droid.CustomRenderer
{
    public class SimpleLabelRenderer : LabelRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
        {
            base.OnElementChanged(e);
            if (Control != null)
            {
                Control.Typeface = Typeface.CreateFromAsset(Forms.Context.Assets, GetFontName(Element.FontFamily, Element.FontAttributes));
            }
        }

        private static string GetFontName(string fontFamily, FontAttributes fontAttributes)
        {
            var postfix = "Regular";
            var bold = fontAttributes.HasFlag(FontAttributes.Bold);
            var italic = fontAttributes.HasFlag(FontAttributes.Italic);
            if (bold && italic) { postfix = "BoldItalic"; }
            else if (bold) { postfix = "Bold"; }
            else if (italic) { postfix = "Italic"; }

            return $"{fontFamily}-{postfix}.otf";
        }
    }



     public class FormattedLabelRenderer : SimpleLabelRenderer
        {
            protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
            {
                base.OnElementChanged(e);
                UpdateFormattedText();
            }

            private void UpdateFormattedText()
            {
                if (Element?.FormattedText == null)
                    return;

                var extensionType = typeof(FormattedStringExtensions);
                var type = extensionType.GetNestedType("FontSpan", BindingFlags.NonPublic);
                var ss = new SpannableString(Control.TextFormatted);
                var spans = ss.GetSpans(0, ss.ToString().Length, Class.FromType(type));
                foreach (var span in spans)
                {
                    var start = ss.GetSpanStart(span);
                    var end = ss.GetSpanEnd(span);
                    var flags = ss.GetSpanFlags(span);
                    var font = (Font)type.GetProperty("Font").GetValue(span, null);
                    ss.RemoveSpan(span);
                    var newSpan = new CustomTypefaceSpan(Control, Element, font);
                    ss.SetSpan(newSpan, start, end, flags);
                }
                Control.TextFormatted = ss;
            }

            protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                base.OnElementPropertyChanged(sender, e);

                if (e.PropertyName == Label.FormattedTextProperty.PropertyName ||
                    e.PropertyName == Label.TextProperty.PropertyName ||
                    e.PropertyName == Label.FontAttributesProperty.PropertyName ||
                    e.PropertyName == Label.FontProperty.PropertyName ||
                    e.PropertyName == Label.FontSizeProperty.PropertyName ||
                    e.PropertyName == Label.FontFamilyProperty.PropertyName ||
                    e.PropertyName == Label.TextColorProperty.PropertyName)
                {
                    UpdateFormattedText();
                }
            }
        }
    }

using System;
using Xamarin.Forms;
using XLabs.Forms.Controls;

namespace Proj.Core.UI.XamarinForms.Controls
{

    public class UIFormattedStringLabel : Label
    {
        public UIFormattedStringLabel()
        {

        }
    }
}

标签代码:

var formatString = new FormattedString();

formatString.Spans.Add(new Span { Text = Time.Text + "\n", FontAttributes = FontAttributes.Bold, ForegroundColor = ColorHelper.FromHex(CoreTheme.COLOR_DARK_GREY)});
formatString.Spans.Add(new Span { Text = TimeRemaining.Text, FontAttributes = FontAttributes.Bold,ForegroundColor = ColorHelper.FromHex(CoreTheme.COLOR_DEFAULT_BLACK)});

labelTime = new UIFormattedStringLabel(); 
labelTime.ClassId = offerid.ToString();
labelTime.WidthRequest = (DeviceDisplaySettings.defaultwidth / buttonsToShow) - 10;
labelTime.HeightRequest = 40;
labelTime.VerticalTextAlignment = TextAlignment.Center;
labelTime.BackgroundColor = ColorHelper.FromHex(CoreTheme.COLOR_LIGHT_GREY);
labelTime.FormattedText = formatString; 

推荐答案

如我的博客文章所述,渲染器并不完美.如果您LabelFontFamily为空,而SpanFontFamily为空,它将崩溃.

As mentioned in my blogpost, the Renderer isn't perfect. In your case it will crash, if the FontFamily of the Label is null and the FontFamily of the Span is null.

我为此添加了一些修复程序到存储库中. https://github.com/smstuebe/xamarin-forms-formattedtext/commit/d3b9e1954e

I added some fixes for this to the repository. https://github.com/smstuebe/xamarin-forms-formattedtext/commit/d3b9eab7f588917f1e4417188a12e66f97cf1081

UpdateFormattedText

只有设置了字体,我们才替换跨度.

We only replace the span, if we have a font set.

private void UpdateFormattedText()
{
    if (Element?.FormattedText == null)
        return;

    var extensionType = typeof(FormattedStringExtensions);
    var type = extensionType.GetNestedType("FontSpan", BindingFlags.NonPublic);
    var ss = new SpannableString(Control.TextFormatted);
    var spans = ss.GetSpans(0, ss.ToString().Length, Class.FromType(type));
    foreach (var span in spans)
    {
        var font = (Font)type.GetProperty("Font").GetValue(span, null);
        if ((font.FontFamily ?? Element.FontFamily) != null)
        {
            var start = ss.GetSpanStart(span);
            var end = ss.GetSpanEnd(span);
            var flags = ss.GetSpanFlags(span);
            ss.RemoveSpan(span);
            var newSpan = new CustomTypefaceSpan(Control, Element, font);
            ss.SetSpan(newSpan, start, end, flags);
        }
    }
    Control.TextFormatted = ss;
}

我不会在CustomTypefaceSpan.ApplyCustomTypeFace(Paint paint)中检查是否为空,因为它会向您显示字体未正确加载,并且您必须仔细检查名称和资产.

I don't check for null in CustomTypefaceSpan.ApplyCustomTypeFace(Paint paint), because it will show you that your font got not loaded correctly, and you have to double check the names and the assets.

这篇关于自定义字体适用于格式化的字符串吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆