Xamarin Forms 动态向 ScrollView 添加自定义字体标签非常缓慢。

3
我有一个水平滚动视图,我试图在用户执行特定操作时动态填充。我将投入视图的项目都包含4个使用自定义字体的标签。当我尝试添加大约10个这些项时,在安卓上会有1.5秒的延迟,在IOS上为1秒。如果我去掉自定义字体,则在每个平台上都是1秒左右。如果我删除3个标签,只显示一个标签,则几乎瞬间完成。有没有已知的原因导致延迟?是否有任何解决方法可以让我仍然使用自定义字体而没有巨大的延迟?
下面是我制作的一个快速示例,它基本上做了我在我的应用程序中要做的事情。但是,我的应用程序还有更多的内容,所以这里的延迟不太严重,但仍然非常明显。
public class App : Application
{
    public int count;
    public ScrollView scroll, scroll2, scroll3;
    public App ()
    {
        count = 1;
        scroll = new ScrollView {
            VerticalOptions = LayoutOptions.Center,
            Orientation = ScrollOrientation.Horizontal
        };
        scroll2 = new ScrollView {
            VerticalOptions = LayoutOptions.Center,
            Orientation = ScrollOrientation.Horizontal
        };
        Button button = new Button(){
            Text = "click",
        };
        button.Clicked += (sender, e) => AddStuff();
        Button button2 = new Button(){
            Text = "click",
        };
        button2.Clicked += (sender, e) => AddStuff2();
        MainPage = new ContentPage {
            BackgroundColor = Color.White,
            Content = new StackLayout{
                Children={
                    button,
                    scroll,
                    button2,
                    scroll2
                }
            }
        };
    }
    //this one is instantaneous
    public void AddStuff()
    {
        StackLayout stack = new StackLayout () {
            Orientation = StackOrientation.Horizontal,
            HorizontalOptions = LayoutOptions.FillAndExpand,
            HeightRequest = 200,
        };
        for (int i = 0; i < 11; i++)
            stack.Children.Add (
                new StackLayout(){
                    Children = {
                        new Label (){TextColor = Color.Blue, Text = "Size: ", WidthRequest = 100 },
                    }
                }
            );
        scroll.Content = stack;
        count++;
    }
    //this one takes forever
    public void AddStuff2()
    {
        StackLayout stack = new StackLayout () {
            Orientation = StackOrientation.Horizontal,
            HorizontalOptions = LayoutOptions.FillAndExpand,
            HeightRequest = 200,
        };
        for (int i = 0; i < 11; i++)
            stack.Children.Add (
                new StackLayout(){
                    Children = {
                        new Label (){TextColor = Color.Blue, Text = "Size: ", WidthRequest = 100 },
                        new Label (){TextColor = Color.Blue, Text ="" + count*i, WidthRequest = 100 },
                        new Label (){TextColor = Color.Blue, Text = "Size: ", WidthRequest = 100 },
                        new Label (){TextColor = Color.Blue, Text ="" + count*i, WidthRequest = 100 }
                    }
                }
            );
        scroll2.Content = stack;
        count++;
    }
}
和自定义字体标签
[assembly: ExportRenderer (typeof (Label), typeof (CustomFontLabel_Droid))]
    namespace df.Droid
    {
        public class CustomFontLabel_Droid:LabelRenderer
        {
            protected override void OnElementChanged (ElementChangedEventArgs<Xamarin.Forms.Label> e) {
                base.OnElementChanged (e);
                var label = (TextView)Control;
                Typeface font = Typeface.CreateFromAsset (Forms.Context.Assets, "SourceSansPro-Semibold.otf");
                label.Typeface = font;
            }
        }
    }

我使用了这个工具来使用自定义字体,效果非常好。 - InitLipton
你声称对于10个元素很慢,但是你正在将55个元素添加到一个新的堆栈,然后将该堆栈添加到滚动视图中。XF中StackLayout的实现非常慢,几个月前我提交了一个错误报告(https://bugzilla.xamarin.com/show_bug.cgi?id=25621),因为我也遇到了StackLayout的问题,他们标记为已解决,但只是进行了改进。根本原因是渲染引擎没有缓存元素大小,因此当整个ScrollView需要刷新时,它会重新计算太多后代元素的大小。尽可能使用ListView,并避免使用具有可调整大小的动态StackLayouts。 - Sten Petrov
抱歉,当我说10个项目时,我指的是每个项目都由多个元素组成。感谢您提供有关StackLayouts和Xamarin的信息。非常有启发性。 - WMartin
1个回答

2

如果有其他人遇到类似问题,这里有一个提示:如果你在Android的MainActivity创建一个静态Typeface属性而不是每次在Label.OnElementChanged函数中调用createFromAsset,则可以消除Android上的额外延迟。

CustomFontLabel_Droid.cs

[assembly: ExportRenderer (typeof (Label), typeof (CustomFontLabel_Droid))]
namespace df.Droid
{
    public class CustomFontLabel_Droid:LabelRenderer
    {
        protected override void OnElementChanged (ElementChangedEventArgs<Xamarin.Forms.Label> e) {
            base.OnElementChanged (e);
            var label = (TextView)Control;
            // this guy slows things down-> Typeface font = Typeface.CreateFromAsset (Forms.Context.Assets, "SourceSansPro-Semibold.otf");
            label.Typeface = MainActivity.semiBoldFont;
        }
    }
}

MainActivity.cs

public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
    {
        public static Typeface semiBoldFont = null;
        protected override void OnCreate (Bundle bundle)
        {
            base.OnCreate (bundle);
            global::Xamarin.Forms.Forms.Init (this, bundle);
            LoadApplication (new App ());
            semiBoldFont = Typeface.CreateFromAsset (Forms.Context.Assets, "SourceSansPro-Semibold.otf");
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接