11

I just wanted to ask if there is any way to justify text in a Label. I am using Xamarin Forms Xaml.

Thanks.

UPDATE: As for now, it is not possible to justify text. Most of the answers were about centering the text, but it is not what I asked. One way could be to use Renderer as by Timothy.

ainer
  • 125
  • 1
  • 2
  • 8

11 Answers11

13

Though you can't stretch label's text to a full width using Xamarin.Forms features, it's easily achieved with a platform renderer.

Android text justification in Xamarin.Froms label

Most Xamarin platforms have the text justification feature available in corresponding native elements, and it's just a matter of setting a single attribute of a native element. I suppose the reason for not adding this feature to standard Xamarin.Forms label is lagging of platforms in that capability, e.g. Android had Android.Text.JustificationMode.InterWord flag added only in version 8.1

Below you can see Android renderer implementation:

using Android.Content;
using Saplin.CPDT.UICore.Controls;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(Saplin.CPDT.UICore.Controls.ExtendedLabel), typeof(Saplin.CPDT.Droid.ExtnededLabelRenderer))]
namespace Saplin.CPDT.Droid
{
    public class ExtnededLabelRenderer : Xamarin.Forms.Platform.Android.LabelRenderer
    {
        public ExtnededLabelRenderer(Context context) : base(context)
        {
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
        {
            base.OnElementChanged(e);

            var el = (Element as ExtendedLabel);

            if (el != null && el.JustifyText)
            {
                if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
                {
                    Control.JustificationMode = Android.Text.JustificationMode.InterWord;
                }

            }
        }
    }
}
  1. Your create renderer class in native project
  2. You add assembly: ExportRenderer attribute
  3. You set TextView's JustificationMode

In my example I used ExtenedLabel subclass of Xamarin.Forms.Label with extra property JustifyText to let setting the justification of the text. That's how the subclassed control can be declared:

using System;
using Xamarin.Forms;

namespace Saplin.CPDT.UICore.Controls
{
    public class ExtendedLabel : Label
    {
        public static readonly BindableProperty JustifyTextProperty =
            BindableProperty.Create(
                propertyName: nameof(JustifyText),
                returnType: typeof(Boolean),
                declaringType: typeof(ExtendedLabel),
                defaultValue: false,
                defaultBindingMode: BindingMode.OneWay
         );

        public bool JustifyText
        {
            get { return (Boolean)GetValue(JustifyTextProperty); }
            set { SetValue(JustifyTextProperty, value); }
        }
    }
}
  • Examples of platform renderers for WPF and macOS.
Maxim Saplin
  • 4,115
  • 38
  • 29
  • 1
    To complete your answer with more platforms: here is a sample project for Android/iOS/UWP: https://github.com/nguyenthanhliemfc/LabelJustify – Jonx Nov 26 '19 at 15:04
  • Thanks for the addition! – Maxim Saplin Nov 27 '19 at 13:42
  • 1
    For reasons I do not understand, this solution is working correctly on Android but on iOS, when using FormattedText and Spans, the text does not justify and to make it work you have to also duplicate this implementation in a OnElementPropertyChanged. Then it works for me on both iOS and Android. – Jonx Nov 28 '19 at 15:57
9

The current way to do this is by using HorizontalTextAlignment and the values for the TextAlignment enumeration are:

  • Center = Center-aligned text
  • Start = Left-aligned
  • End = Right-aligned

Center a label and its text example:

<Label x:Name="Description" HorizontalTextAlignment="Center" VerticalOptions="Center" HorizontalOptions="Center" />

Timothy Lee Russell
  • 3,719
  • 1
  • 35
  • 43
  • Thank you for your answer, but doesn't this just make the text centered? – ainer Jul 13 '16 at 09:11
  • 1
    Yes, now that you mention it. I suppose I should have framed my answer as, "That option is not available. Here are the available options." If you want to do "full justification" you would need to create a custom renderer for each platform you want to support. At that point, you are dependent on each platform's feature set. iOS lets you set an option for full justification [ NSTextAlignmentJustified ] and then on Android, you could probably use one of these projects as a starting place: https://github.com/bluejamesbond/TextJustify-Android / https://github.com/navabi/JustifiedTextView – Timothy Lee Russell Jul 13 '16 at 16:53
2

In xaml you can use html to justify your text.

<Label LineBreakMode="WordWrap" TextType="Html" TextColor="Black">
<Label.Text>&lt;p style=&quot;text-align:justify;&quot;&gt; 
Your text here
&lt;p&gt;</Label.Text>
Sandro Benevides
  • 581
  • 2
  • 14
1

Use the XAlign property

Label lbl = new Label();
lbl.Text = "I'm a Label!";
lbl.XAlign = TextAligntment.Start; // Start, Center, End are valid
Jason
  • 86,222
  • 15
  • 131
  • 146
  • I know about these options. I do not know about justifying the text - equal indentation from left and right for every line of text. It stretches gaps between words to fill the whole line. Just like in MS Word or other text editors. – ainer May 06 '15 at 17:34
  • ah, I see. As far as I know there isn't a way to do this. You could write a custom renderer that uses iOS's text justification feature, but I don't know if there is a corresponding way to it in Android. – Jason May 06 '15 at 18:41
1

As it can't be done directly within a label, a workaround is to use the new FlexLayout from Xamarin.Forms 3. The idea is to split the text at space character and insert corresponding label in the FlexLayout with JustifyContent set to SpaceBetween.

Example :

XAML

<Frame
    HorizontalOptions="Center"
    Margin="20,50,20,0"
    Padding="10"
    WidthRequest="300"
    HasShadow="true">
    <FlexLayout
        x:Name="TextContainer"
        Direction="Row"
        AlignItems="End"
        JustifyContent="SpaceBetween"
        Wrap="Wrap"/>
</Frame>

Code behind

var textparts = "This is a long text to be justified"
                .Split(' ', StringSplitOptions.RemoveEmptyEntries)
                .Select(x => new Label
                {
                    Text = x,
                    FontSize = 12,
                    TextColor = Color.FromHex("#555555"),
                    Margin = new Thickness(1, 0)
                });

            foreach (var textpart in textparts)
                TextContainer.Children.Add(textpart);
Mattes67
  • 11
  • 1
  • This sounds like a good solution, except won't it cause issues for the last line of text? Like if the last line is only two words, you'd have one word on the left and one word on the right, which is not how justify usually works. – morphinapg Nov 26 '19 at 02:53
  • For somebody who looks for a dirty hack to justify on Android below 8.1 - this works and I also add several " " words at the end so it looks fine – Anton Maiorov Dec 19 '20 at 22:14
0

What sort of container are you using to hold the text? Having a StackLayout with HorizontalOptions of FillAndExpand, along with the XAlign, might do it, but only if your text is only one line long per control.

Mathieson
  • 1,698
  • 2
  • 17
  • 19
  • I used StackLayout. I must go with @Jason on this. It seems it is not possible. I could only center the text, not justify it. – ainer Jun 08 '15 at 16:18
0

Try this:

<StackLayout HorizontalOptions="FillAndExpand" Padding="0, 10, 0, 10" Spacing="0">
      <Label Text="Test message" XAlign="Center"/>
      <Label FontSize="Small" Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." LineBreakMode="WordWrap"
XAlign="Center" />
</StackLayout>
Victor Madurga
  • 431
  • 4
  • 5
0

If you use the Label under relativeLayout you can justify the label..

The trick is you must fill the width & height as per parent..

So I use HeightConstraint,WidthConstraint with factor=1.. so it take full width & height of the parent..

  <RelativeLayout >

    <Label Text="My text"
           FontSize="20" 
           HorizontalOptions="Center" 
           VerticalOptions="Center"
           RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent,Property=Height,Factor=1,Constant=0}"
           RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent,Property=Width,Factor=1,Constant=0}" />
  </RelativeLayout>
Ranjithkumar
  • 16,071
  • 12
  • 120
  • 159
0

I've been able to successfully achieve this by using nested grids. Hope this helps someone!

<Grid HorizontalOptions="Fill" Padding="5,2">
             <Grid  Margin="8, 85,8,0" VerticalOptions="Center" RowSpacing="0" >

                                    <Label Grid.Row="0" x:Name="PostTitle" HorizontalTextAlignment="Center" VerticalTextAlignment="Center"
                                           Text="Display Text" Padding="10,10" LineHeight="20" BackgroundColor="Black" TextColor="WhiteSmoke" />

                                    <Label Grid.Row="1" x:Name="PostDate"  HorizontalTextAlignment="Center" VerticalTextAlignment="Center"
                                           Text="Your Text Here" FontSize="Micro" Padding="10,10" LineHeight="10" 
                                           BackgroundColor="Black" TextColor="WhiteSmoke" />

                                </Grid>

                            </Grid>
technified
  • 353
  • 1
  • 2
  • 15
0

To Justify Text in UITableViewCell TextLabel - Xamarin IOS

UIStringAttributes stringAttributes = new UIStringAttributes
{
    ParagraphStyle = new NSMutableParagraphStyle() { Alignment = UITextAlignment.Justified }
};

var attributedText = new NSMutableAttributedString(cell.TextLabel.Text);
attributedText.AddAttributes(stringAttributes, new NSRange(0, cell.TextLabel.Text.Length));
cell.TextLabel.AttributedText = attributedText;
0

Custom Label


using System;
using Xamarin.Forms;

namespace YourNameSpace.Controls
{
    public class CustomLabel : Label
    {
        public static readonly BindableProperty JustifyTextProperty =
      BindableProperty.Create(nameof(JustifyText), typeof(bool), typeof(CustomLabel), false, BindingMode.TwoWay);

        public bool JustifyText
        {
            get { return (bool)GetValue(JustifyTextProperty); }
            set
            {

                SetValue(JustifyTextProperty, value);
            }
        }

        public CustomLabel()
        {
        }
    }
}

iOS Custom Label Renderers

using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using YourNameSpace.Controls;
using YourNameSpace.iOS.Renderers;

[assembly: ExportRenderer(typeof(CustomLabel), typeof(CustomLabelRenderer))]
namespace YourNameSpace.iOS.Renderers
{
    public class CustomLabelRenderer : Xamarin.Forms.Platform.iOS.LabelRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
        {
            base.OnElementChanged(e);

            if (Control == null || this.Element == null) return;

            Control.TextAlignment = UITextAlignment.Justified;

        }
    }
}

Android Custom Label Renderers

using Android.Content;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using YourNameSpace.Controls;
using YourNameSpace.Droid.Renderers;

[assembly: ExportRenderer(typeof(CustomLabel), typeof(CustomLabelRenderer))]
namespace YourNameSpace.Droid.Renderers
{
    public class CustomLabelRenderer : Xamarin.Forms.Platform.Android.LabelRenderer
    {
        public CustomLabelRenderer(Context context) : base(context)
        {
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
        {
            base.OnElementChanged(e);

            var element = (Element as CustomLabel);

            if (element != null && element.JustifyText)
            {
                if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
                {
                    Control.JustificationMode = Android.Text.JustificationMode.InterWord;
                }
            }
        }
    }
}