maui
maui copied to clipboard
[Spec] Separate Text Wrapping and Overflow in Core
The Problem
When dealing with text in an application, we have to answer a few questions:
- Is this text allowed to wrap to multiple lines?
- If so, how should that wrapping be done?
- If the text is longer than the allotted space, how should the overflow be handled?
Xamarin.Forms attempted to encompass the answers in 2 properties: LineBreakMode and MaxLines.
Unfortunately, this leads to problems:
MaxLinesis only available on Label; other controls which might want to use multi-line text (e.g., a Button) have no way of limiting the number of lines of textLineBreakModeconflates text overflow with line wrapping; because of this, situations such as multi-line word-wrapped text truncated at the start/end of the text are impossible on some platforms.
We can't avoid pulling the current behavior/members forward into Maui.Controls (because migration), but we can avoid pushing all these problems onto everyone else. And we can set ourselves up for better things in the future.
I'm proposing that for Maui.Core, we effectively split this functionality into separate enums and interfaces: TextOverflowMode, TextWrapMode, and IMultilineText.
API
Proposed Interfaces Changes for Core
interface IText
{
// ... adding this to the existing interface with a default implemenation
TextOverFlowMode { get; }
}
interface IMultilineText : IText
{
int MaximumLines { get; }
TextWrapMode Wrap { get; }
}
enum TextWrapMode
{
None, // Text does not wrap, regardless of number of lines allowed
Word, // Text wraps at word boundaries
Character // Text wraps at character boundaries (possibly mid-word)
}
enum TextOverflowMode
{
Truncate, // Text is cut off
EllipsizeEnd, // Text is cut off at the end with ...
EllipsizeStart, // Text is cut off at the start with ...
EllipsizeMiddle, // Text is spliced in the middle with ...
}
Other Interface Changes
ILabel : IMultilineText // Labels add support for multi-line text
IButton : IMultilineText // Buttons add support for multi-line text
There may be others (e.g., Editor) where this also makes sense.
Controls Implementation
All of these changes are in the Core layer, and will be remapped in Controls (at least for the first stable release) to preserve the old behavior.
Developer Experience
Forms migration should be seamless, as nothing is actually changing from Forms to Controls. Users who want the new experience can disable the remapping in Controls.
The new experience will provide options such as limited multiline text in Buttons, the ability to end ellipsize multiline text on Android (currently impossible), and a generally more flexible API.
Backward Compatibility
For Controls, nothing changes from Forms.
@hartez I'm currently porting Fabulous from XF to Maui by providing my own implementation for all the interfaces (ILabel, IButton, etc) without relying on Maui.Controls.
(I must admit it is very hard to understand what's expected and when with close to no documentation... A lot of reverse engineering is required)
Unfortunately, https://github.com/dotnet/maui/pull/5936 removed the MaxLines / LineBreakMode properties from ILabel and gave no alternative except "we will do better in the future".
This breaks layout in iOS because UILabel has Lines = 1 by default and won't auto-wrap.

This sample follows the Hello World template of dotnet new maui
Right now, it's a blocking issue for any 3rd party frameworks trying to plug into Maui. Something as basic as a Label isn't working correctly which make it a showstopper.
I seem to understand based on the spec here and some of your other messages on GitHub that this specification is set to be done "long term" / "in the future".
Given the blocking nature of this issue, could you please either:
- Proritize this specification
- Rollback #5936 until a better design is found
For anyone interested, I managed to do a quick workaround that makes the Label always auto-wrap on iOS:
#if __IOS__
public class CustomLabelHandler: Microsoft.Maui.Handlers.LabelHandler
{
protected override MauiLabel CreatePlatformView()
{
var label = base.CreatePlatformView();
label.Lines = 0;
return label;
}
}
// Shadow Microsoft.Maui.Handlers.LabelHandler with CustomLabelHandler
using LabelHandler = CustomLabelHandler;
#else
using LabelHandler = Microsoft.Maui.Handlers.LabelHandler;
#endif
public class FabulousLabel: ILabel { ... }
var label = FabulousLabel();
label.Handler = LabelHandler();
We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.
Wouldn't it make sense to care about those who help building the ecosystem, and not randomly break their efforts and 'consider fixing this later' 🙄
@TimLariviere I spent some time getting this implementation started - #10279.
Hopefully I'll be able to do some testing and finishing up next week. I'm not sure when we'll be able to get this released, though, because it does involve some API changes.
Oh, also, there's another (admittedly poorly-documented) option that might help for this particular problem - the handlers for each control type allow you to specify an alternate factory method for the platform view without having to subclass the handler. It'd look something like this (in your startup configuration):
#if __IOS__
Microsoft.Maui.Handlers.LabelHandler.PlatformViewFactory = (handler) => {
return new UILabel { Lines = 0 };
};
#endif