Xamarin支持团队给我写信:
该团队已经意识到这个问题,并正在努力优化UI初始化代码。您可能会在即将推出的版本中看到一些改进。
更新:七个月的空闲后,Xamarin将错误报告状态更改为“CONFIRMED”。
好消息是我们需要耐心等待。幸运的是,Xamarin论坛的Sean McKay建议覆盖所有布局代码以提高性能:https://forums.xamarin.com/discussion/comment/87393#Comment_87393
但他的建议也意味着我们必须重新编写完整的标签代码。以下是FixedLabel版本,它不执行昂贵的布局循环,并具有用于文本和颜色的可绑定属性等一些功能。使用它而不是Label
可以根据标签数和位置提高80%及以上的性能。
public class FixedLabel : View
{
public static readonly BindableProperty TextProperty = BindableProperty.Create<FixedLabel,string>(p => p.Text, "");
public static readonly BindableProperty TextColorProperty = BindableProperty.Create<FixedLabel,Color>(p => p.TextColor, Style.TextColor);
public readonly double FixedWidth;
public readonly double FixedHeight;
public Font Font;
public LineBreakMode LineBreakMode = LineBreakMode.WordWrap;
public TextAlignment XAlign;
public TextAlignment YAlign;
public FixedLabel(string text, double width, double height)
{
SetValue(TextProperty, text);
FixedWidth = width;
FixedHeight = height;
}
public Color TextColor {
get {
return (Color)GetValue(TextColorProperty);
}
set {
if (TextColor != value)
return;
SetValue(TextColorProperty, value);
OnPropertyChanged("TextColor");
}
}
public string Text {
get {
return (string)GetValue(TextProperty);
}
set {
if (Text != value)
return;
SetValue(TextProperty, value);
OnPropertyChanged("Text");
}
}
protected override SizeRequest OnSizeRequest(double widthConstraint, double heightConstraint)
{
return new SizeRequest(new Size(FixedWidth, FixedHeight));
}
}
Android渲染器长这样:
public class FixedLabelRenderer : ViewRenderer
{
public TextView TextView;
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.View> e)
{
base.OnElementChanged(e);
var label = Element as FixedLabel;
TextView = new TextView(Context);
TextView.Text = label.Text;
TextView.TextSize = (float)label.Font.FontSize;
TextView.Gravity = ConvertXAlignment(label.XAlign) | ConvertYAlignment(label.YAlign);
TextView.SetSingleLine(label.LineBreakMode != LineBreakMode.WordWrap);
if (label.LineBreakMode == LineBreakMode.TailTruncation)
TextView.Ellipsize = Android.Text.TextUtils.TruncateAt.End;
SetNativeControl(TextView);
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Text")
TextView.Text = (Element as FixedLabel).Text;
base.OnElementPropertyChanged(sender, e);
}
static GravityFlags ConvertXAlignment(Xamarin.Forms.TextAlignment xAlign)
{
switch (xAlign) {
case Xamarin.Forms.TextAlignment.Center:
return GravityFlags.CenterHorizontal;
case Xamarin.Forms.TextAlignment.End:
return GravityFlags.End;
default:
return GravityFlags.Start;
}
}
static GravityFlags ConvertYAlignment(Xamarin.Forms.TextAlignment yAlign)
{
switch (yAlign) {
case Xamarin.Forms.TextAlignment.Center:
return GravityFlags.CenterVertical;
case Xamarin.Forms.TextAlignment.End:
return GravityFlags.Bottom;
default:
return GravityFlags.Top;
}
}
}
这里是iOS渲染:
public class FixedLabelRenderer : ViewRenderer<FixedLabel, UILabel>
{
protected override void OnElementChanged(ElementChangedEventArgs<FixedLabel> e)
{
base.OnElementChanged(e);
SetNativeControl(new UILabel(RectangleF.Empty) {
BackgroundColor = Element.BackgroundColor.ToUIColor(),
AttributedText = ((FormattedString)Element.Text).ToAttributed(Element.Font, Element.TextColor),
LineBreakMode = ConvertLineBreakMode(Element.LineBreakMode),
TextAlignment = ConvertAlignment(Element.XAlign),
Lines = 0,
});
BackgroundColor = Element.BackgroundColor.ToUIColor();
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Text")
Control.AttributedText = ((FormattedString)Element.Text).ToAttributed(Element.Font, Element.TextColor);
base.OnElementPropertyChanged(sender, e);
}
public override void LayoutSubviews()
{
base.LayoutSubviews();
if (Control == null)
return;
Control.SizeToFit();
var num = Math.Min(Bounds.Height, Control.Bounds.Height);
var y = 0f;
switch (Element.YAlign) {
case TextAlignment.Start:
y = 0;
break;
case TextAlignment.Center:
y = (float)(Element.FixedHeight / 2 - (double)(num / 2));
break;
case TextAlignment.End:
y = (float)(Element.FixedHeight - (double)num);
break;
}
Control.Frame = new RectangleF(0, y, (float)Element.FixedWidth, num);
}
static UILineBreakMode ConvertLineBreakMode(LineBreakMode lineBreakMode)
{
switch (lineBreakMode) {
case LineBreakMode.TailTruncation:
return UILineBreakMode.TailTruncation;
case LineBreakMode.WordWrap:
return UILineBreakMode.WordWrap;
default:
return UILineBreakMode.Clip;
}
}
static UITextAlignment ConvertAlignment(TextAlignment xAlign)
{
switch (xAlign) {
case TextAlignment.Start:
return UITextAlignment.Left;
case TextAlignment.End:
return UITextAlignment.Right;
default:
return UITextAlignment.Center;
}
}
}