Есть ли способ сделать ярлык заполнить пространство слева направо?

Вот код, который у меня есть:

<StackLayout>
   <Label x:Name="emptyLabel1" FontSize="18" XAlign="Start" TextColor="Gray" />
   <Label x:Name="emptyLabel2" FontSize="18" XAlign="Center" TextColor="Gray" />
   <Label x:Name="emptyLabel3" FontSize="18" XAlign="Center" TextColor="Gray" />
</StackLayout>

Первая многострочная метка начинается слева, но имеет пробелы в некоторых строках справа. 2-я и 3-я многострочные метки центрированы и имеют пробелы как слева, так и справа.

Есть ли способ, чтобы все строки ярлыков полностью заполняли строки, полностью заполняли слева направо o, чтобы первый символ каждой строки всегда выстраивался слева и последний символ последнего слова каждого строка всегда выравнивается справа? Обратите внимание, что это потребует от некоторых слов в каждой строке иметь разные промежутки между ними.

Ответы

Ответ 1

Немного сложно реализовать метку с поддержкой выравнивания выравнивания, но это возможно с помощью рендеринга (-ов) платформы.

Первым шагом будет объявление пользовательского элемента управления в проекте forms.

public class JustifiedLabel : Label { }

Следующий шаг - определить и зарегистрировать средство рендеринга платформы в iOS. Это просто, поскольку мы просто объединяем форматированную строку с абзацем-стилем, чтобы получить то, что хотим.

[assembly: ExportRenderer(typeof(JustifiedLabel), typeof(JustifiedLabelRenderer))]
namespace SomeAppNamespace.iOS
{   
    public class JustifiedLabelRenderer : LabelRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
        {
            base.OnElementChanged(e);

            //if we have a new forms element, we want to update text with font style (as specified in forms-pcl) on native control
            if (e.NewElement != null)
                UpdateTextOnControl();
        }

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

            //if there is change in text or font-style, trigger update to redraw control
            if(e.PropertyName == nameof(Label.Text) 
               || e.PropertyName == nameof(Label.FontFamily) 
               || e.PropertyName == nameof(Label.FontSize)
               || e.PropertyName == nameof(Label.TextColor)
               || e.PropertyName == nameof(Label.FontAttributes))
            {
                UpdateTextOnControl();
            }
        }

        void UpdateTextOnControl()
        {
            if (Control == null)
                return;

            //define paragraph-style
            var style = new NSMutableParagraphStyle()
            {
                Alignment = UITextAlignment.Justified,
                FirstLineHeadIndent = 0.001f,
            };

            //define attributes that use both paragraph-style, and font-style 
            var uiAttr = new UIStringAttributes()
            {
                ParagraphStyle = style,
                BaselineOffset = 0,

                Font = Control.Font
            };

            //define frame to ensure justify alignment is applied
            Control.Frame = new RectangleF(0, 0, (float)Element.Width, (float)Element.Height);

            //set new text with ui-style-attributes to native control (UILabel)
            var stringToJustify = Control.Text ?? string.Empty;
            var attributedString = new Foundation.NSAttributedString(stringToJustify, uiAttr.Dictionary);
            Control.AttributedText = attributedString;
            Control.Lines = 0;
        }
    }
}

В платформе Android немного сложнее - поскольку андроид не поддерживает выравнивание выравнивания для TextView - поэтому нам нужно будет использовать WebView, чтобы заставить его визуализировать текст.

( Примечание: Вы также можете использовать библиотеку android и использовать его вместо WebView)

[assembly: ExportRenderer(typeof(JustifiedLabel), typeof(JustifiedLabelRenderer))]
namespace SomeAppNamespace.Droid
{
    //We don't extend from LabelRenderer on purpose as we want to set 
    // our own native control (which is not TextView)
    public class JustifiedLabelRenderer : ViewRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<View> e)
        {
            base.OnElementChanged(e);

            //if we have a new forms element, we want to update text with font style (as specified in forms-pcl) on native control
            if (e.NewElement != null)
            {
                if (Control == null)
                {
                    //register webview as native control
                    var webView = new Android.Webkit.WebView(Context);
                    webView.VerticalScrollBarEnabled = false;
                    webView.HorizontalScrollBarEnabled = false;

                    webView.LoadData("<html><body>&nbsp;</body></html>", "text/html; charset=utf-8", "utf-8");
                    SetNativeControl(webView);
                }

                //if we have a new forms element, we want to update text with font style (as specified in forms-pcl) on native control
                UpdateTextOnControl();
            }   
        }

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

            //if there is change in text or font-style, trigger update to redraw control
            if (e.PropertyName == nameof(Label.Text)
               || e.PropertyName == nameof(Label.FontFamily)
               || e.PropertyName == nameof(Label.FontSize)
               || e.PropertyName == nameof(Label.TextColor)
               || e.PropertyName == nameof(Label.FontAttributes))
            {
                UpdateTextOnControl();
            }
        }

        void UpdateTextOnControl()
        {
            var webView = Control as Android.Webkit.WebView; 
            var formsLabel = Element as Label;

            // create css style from font-style as specified
            var cssStyle = $"margin: 0px; padding: 0px; text-align: justify; color: {ToHexColor(formsLabel.TextColor)}; background-color: {ToHexColor(formsLabel.BackgroundColor)}; font-family: {formsLabel.FontFamily}; font-size: {formsLabel.FontSize}; font-weight: {formsLabel.FontAttributes}";

            // apply that to text 
            var strData =
                $"<html><body style=\"{cssStyle}\">{formsLabel?.Text}</body></html>";

            // and, refresh webview
            webView.LoadData(strData, "text/html; charset=utf-8", "utf-8");
            webView.Reload();
        }

        // helper method to convert forms-color to css-color
        string ToHexColor(Color color)
        {
            var red = (int)(color.R * 255);
            var green = (int)(color.G * 255);
            var blue = (int)(color.B * 255);
            var alpha = (int)(color.A * 255);
            var hex = $"#{red:X2}{green:X2}{blue:X2}";

            return hex;
        }
    }
}

Использование образца

<StackLayout Margin="20">
    <Entry x:Name="InputEntry" />

    <Label Margin="0,10,0,0" BackgroundColor="Navy" TextColor="White" Text="Normal Text Label" FontSize="15" HorizontalOptions="CenterAndExpand" />
    <Label 
            FontSize="20" 
            FontAttributes="Bold"  
            Text="{Binding Text, Source={x:Reference InputEntry}}" />

    <Label Margin="0,10,0,0" BackgroundColor="Navy" TextColor="White" Text="Justified Text Label" FontSize="15" HorizontalOptions="CenterAndExpand" />
    <local:JustifiedLabel 
            FontSize="20" 
            FontAttributes="Bold" 
            Text="{Binding Text, Source={x:Reference InputEntry}}"
            TextColor="Green"
            BackgroundColor="Yellow"
            VerticalOptions="FillAndExpand"
            HorizontalOptions="FillAndExpand" />

</StackLayout>

введите описание изображения здесь введите описание изображения здесь

Ответ 2

Я думаю, вы можете попробовать с

HorizontalOptions=LayoutOptions.FillAndExpand

HorizontalOptions

Ответ 3

Я никогда не видел простого решения для этого, только обходные пути, такие как упомянутый здесь.

Вам нужно использовать компонент или создать собственное решение для каждой платформы.

Ответ 4

Я удивлен, что никто еще не поднял это...

Очень простой способ добиться того же эффекта - заключить метку в собственный StackLayout, например:

<StackLayout  Orientation="Vertical" >
    <Label Text="My Label" />
</StackLayout>