Xamarin.Forms 如何使用样式和动态资源正确更新控件的字体大小?

How to correctly update font size of controls using styles and dynamic resources in Xamarin.Forms?

我正在尝试在运行时更新控件的字体大小。

为此,我将样式作为动态资源应用于我的控件。当点击一个按钮时,我在应用程序中找到字体大小为 setter 的样式资源,修改字体大小值,并将整个样式写回到找到该样式的资源字典中。

控件示例:

<Label Text="Welcome to Xamarin.Forms!" 
               HorizontalOptions="CenterAndExpand"
               Style="{DynamicResource DynamicLabel}"/>

样式示例:

<Style x:Key="DynamicLabel" TargetType="Label">
        <Setter Property="TextColor" Value="Red" />
        <Setter Property="HorizontalTextAlignment" Value="Center" />
        <Setter Property="VerticalTextAlignment" Value="Center" />
        <Setter Property="FontSize" Value="23" />
</Style>

正在调用以更新样式的代码:

private void ApplyScale(ResourceDictionary dictionary, double scaleFactor)
    {
        foreach (var resourceDictionary in dictionary.MergedDictionaries)
        {
            ApplyScale(resourceDictionary, scaleFactor);
        }

        Dictionary<string, Style> stylesToAdd = new Dictionary<string, Style>();

        foreach (KeyValuePair<string, object> resource in dictionary)
        {
            if (resource.Value is Style style)
            {
                foreach (var styleSetter in style.Setters)
                {
                    if (styleSetter.Property.PropertyName == nameof(Font.FontSize))
                    {
                        if (styleSetter.Value is OnPlatform<int> platformSetter)
                        {
                            foreach (var platform in platformSetter.Platforms)
                            {
                                var onPlatformFontSize = int.Parse(platform.Value.ToString());
                                styleSetter.Value = (int) Math.Round(onPlatformFontSize * scaleFactor);
                            }
                        }
                        else
                        {
                            var fontSize = int.Parse(styleSetter.Value.ToString());
                            styleSetter.Value = (int)Math.Round(fontSize * scaleFactor);
                        }
                        stylesToAdd.Add(resource.Key, style);
                    }
                }
            }
        }

        foreach (var style in stylesToAdd)
        {
            dictionary[style.Key] = style.Value;
        }
    }

我创建了一个测试应用程序来演示该问题:https://github.com/King-Xero/XF-DynamicStyleFontSizeTest

应用了样式的控件的外观不反映对这些样式所做的更改。控件肯定在使用样式,因为样式中的颜色出现在控件上。通过断点检查时,样式肯定会更新。但是控件的行为就好像它们应用了 StaticResource 而不是 DynamicResource。我不确定这是我的应用程序中的问题,还是 Xamarin.Forms.

中的问题

在 GitHub 的 Xamarin.Forms 存储库中,有一个 Issue 于 19 天前打开,它仍在分类中,但解决方法将强制 ResourceStyle 更新如下:

代码隐藏:

    private void IncreaseFont_OnClicked(object sender, EventArgs e)
    {
        Device.BeginInvokeOnMainThread(() =>
        {
            var savedstyle = MyLabel.Style;
            MyLabel.Style = null;
            _fontScaler.IncreaseFontScaling();
            MyLabel.Style = savedstyle;
        });
    }

Xaml:

    <Label x:Name="MyLabel"
           Text="Welcome to Xamarin.Forms!" 
           HorizontalOptions="CenterAndExpand"
           Style="{DynamicResource DynamicLabel}"/>

这不是解决问题的方法,请继续关注 GitHub 问题的更新。