Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions src/Controls/src/Core/Entry/Entry.Mapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public partial class Entry
EntryHandler.Mapper.ReplaceMapping<Entry, IEntryHandler>(PlatformConfiguration.iOSSpecific.Entry.AdjustsFontSizeToFitWidthProperty.PropertyName, MapAdjustsFontSizeToFitWidth);
#endif
EntryHandler.Mapper.ReplaceMapping<Entry, IEntryHandler>(nameof(Text), MapText);
EntryHandler.Mapper.ReplaceMapping<Entry, IEntryHandler>(nameof(TextTransform), MapText);
EntryHandler.Mapper.ReplaceMapping<Entry, IEntryHandler>(nameof(TextTransform), MapTextTransform);

// Material3 Entry Handler mappings
#if ANDROID
Expand All @@ -42,5 +42,16 @@ public partial class Entry
EntryHandler.CommandMapper.PrependToMapping(nameof(IEntry.Focus), InputView.MapFocus);
#endif
}

static void MapTextTransform(IEntryHandler handler, Entry entry)
{
if (entry.IsConnectingHandler())
{
// If we're connecting the handler, we don't want to map the text multiple times.
return;
}

MapText(handler, entry);
}
}
}
}
11 changes: 9 additions & 2 deletions src/Controls/src/Core/Entry/Entry.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@ public static void MapAdjustsFontSizeToFitWidth(IEntryHandler handler, Entry ent
public static void MapText(IEntryHandler handler, Entry entry)
{
Platform.TextExtensions.UpdateText(handler.PlatformView, entry);
EntryHandler.MapFormatting(handler, entry);

if (!handler.IsConnectingHandler())
{
// If we're not connecting the handler, we need to update the text formatting
// This is because the text may have changed, and we need to ensure that
// any attributed string formatting is applied correctly.
EntryHandler.MapFormatting(handler, entry);
}
}

public static void MapCursorColor(EntryHandler handler, Entry entry) =>
Expand All @@ -28,4 +35,4 @@ public static void MapAdjustsFontSizeToFitWidth(EntryHandler handler, Entry entr
public static void MapText(EntryHandler handler, Entry entry) =>
MapText((IEntryHandler)handler, entry);
}
}
}
11 changes: 7 additions & 4 deletions src/Controls/src/Core/Label/Label.Mapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ static void MapTextTransform(ILabelHandler handler, Label label) =>
static void MapFormattedText(ILabelHandler handler, Label label)
{
if (label.IsConnectingHandler())
{
// If we're connecting the handler, we don't want to map the text multiple times.
return;
}

MapText(handler, label);
}
Expand Down Expand Up @@ -141,10 +144,10 @@ static void MapCharacterSpacing(ILabelHandler handler, Label label, Action<IElem

static void MapFont(ILabelHandler handler, Label label, Action<IElementHandler, IElement> baseMethod)
{
if (label.HasFormattedTextSpans)
// if there is formatted text,
// then we re-apply the whole formatted text
if (label.HasFormattedTextSpans && !handler.IsConnectingHandler())
{
// if there is formatted text,
// then we re-apply the whole formatted text
handler.UpdateValue(nameof(FormattedText));
}
else if (label.TextType == TextType.Text || !IsDefaultFont(label))
Expand Down Expand Up @@ -198,4 +201,4 @@ static bool IsDefaultFont(Label label)
return true;
}
}
}
}
7 changes: 5 additions & 2 deletions src/Controls/src/Core/Label/Label.iOS.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#nullable disable
using System;
using Microsoft.Maui.Controls.Platform;
using Microsoft.Maui.Graphics;
using UIKit;
Expand All @@ -23,7 +22,11 @@ public static void MapText(ILabelHandler handler, Label label)
{
Platform.LabelExtensions.UpdateText(handler.PlatformView, label);

MapFormatting(handler, label);
if (!handler.IsConnectingHandler())
{
// Any text update requires that we update any attributed string formatting
MapFormatting(handler, label);
}
}

public static void MapLineBreakMode(ILabelHandler handler, Label label)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,16 @@
label.LineBreakMode,
label.CharacterSpacing);

public static NSAttributedString ToNSAttributedString(

Check failure on line 35 in src/Controls/src/Core/Platform/iOS/Extensions/FormattedStringExtensions.cs

View check run for this annotation

Azure Pipelines / maui-pr-uitests (Build UITests Sample App Build Sample App)

src/Controls/src/Core/Platform/iOS/Extensions/FormattedStringExtensions.cs#L35

src/Controls/src/Core/Platform/iOS/Extensions/FormattedStringExtensions.cs(35,36): Error RS0016: Symbol 'static Microsoft.Maui.Controls.Platform.FormattedStringExtensions.ToNSAttributedString(this Microsoft.Maui.Controls.FormattedString! formattedString, Microsoft.Maui.IFontManager! fontManager, double defaultLineHeight = -1, Microsoft.Maui.TextAlignment defaultHorizontalAlignment = Microsoft.Maui.TextAlignment.Start, Microsoft.Maui.Font? defaultFont = null, Microsoft.Maui.Graphics.Color? defaultColor = null, Microsoft.Maui.TextTransform defaultTextTransform = Microsoft.Maui.TextTransform.Default, Microsoft.Maui.LineBreakMode defaultLineBreakMode = Microsoft.Maui.LineBreakMode.WordWrap) -> Foundation.NSAttributedString!' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md)

Check failure on line 35 in src/Controls/src/Core/Platform/iOS/Extensions/FormattedStringExtensions.cs

View check run for this annotation

Azure Pipelines / maui-pr-uitests (Build UITests Sample App Build Sample App)

src/Controls/src/Core/Platform/iOS/Extensions/FormattedStringExtensions.cs#L35

src/Controls/src/Core/Platform/iOS/Extensions/FormattedStringExtensions.cs(35,36): Error RS0016: Symbol 'static Microsoft.Maui.Controls.Platform.FormattedStringExtensions.ToNSAttributedString(this Microsoft.Maui.Controls.FormattedString! formattedString, Microsoft.Maui.IFontManager! fontManager, double defaultLineHeight = -1, Microsoft.Maui.TextAlignment defaultHorizontalAlignment = Microsoft.Maui.TextAlignment.Start, Microsoft.Maui.Font? defaultFont = null, Microsoft.Maui.Graphics.Color? defaultColor = null, Microsoft.Maui.TextTransform defaultTextTransform = Microsoft.Maui.TextTransform.Default, Microsoft.Maui.LineBreakMode defaultLineBreakMode = Microsoft.Maui.LineBreakMode.WordWrap) -> Foundation.NSAttributedString!' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md)
this FormattedString formattedString,
IFontManager fontManager,
double defaultLineHeight = -1,
TextAlignment defaultHorizontalAlignment = TextAlignment.Start,
Font? defaultFont = null,
Color? defaultColor = null,
TextTransform defaultTextTransform = TextTransform.Default)
=> formattedString.ToNSAttributedString(fontManager, defaultLineHeight, defaultHorizontalAlignment, defaultFont, defaultColor, defaultTextTransform, LineBreakMode.WordWrap, defaultCharacterSpacing: 0d);
TextTransform defaultTextTransform = TextTransform.Default,
LineBreakMode defaultLineBreakMode = LineBreakMode.WordWrap)
=> formattedString.ToNSAttributedString(fontManager, defaultLineHeight, defaultHorizontalAlignment, defaultFont, defaultColor, defaultTextTransform, defaultLineBreakMode, defaultCharacterSpacing: 0d);

internal static NSAttributedString ToNSAttributedString(
this FormattedString formattedString,
Expand Down Expand Up @@ -74,15 +75,16 @@
return attributed;
}

public static NSAttributedString ToNSAttributedString(

Check failure on line 78 in src/Controls/src/Core/Platform/iOS/Extensions/FormattedStringExtensions.cs

View check run for this annotation

Azure Pipelines / maui-pr-uitests (Build UITests Sample App Build Sample App)

src/Controls/src/Core/Platform/iOS/Extensions/FormattedStringExtensions.cs#L78

src/Controls/src/Core/Platform/iOS/Extensions/FormattedStringExtensions.cs(78,36): Error RS0016: Symbol 'static Microsoft.Maui.Controls.Platform.FormattedStringExtensions.ToNSAttributedString(this Microsoft.Maui.Controls.Span! span, Microsoft.Maui.IFontManager! fontManager, double defaultLineHeight = -1, Microsoft.Maui.TextAlignment defaultHorizontalAlignment = Microsoft.Maui.TextAlignment.Start, Microsoft.Maui.Font? defaultFont = null, Microsoft.Maui.Graphics.Color? defaultColor = null, Microsoft.Maui.TextTransform defaultTextTransform = Microsoft.Maui.TextTransform.Default, Microsoft.Maui.LineBreakMode defaultLineBreakMode = Microsoft.Maui.LineBreakMode.WordWrap) -> Foundation.NSAttributedString!' is not part of the declared public API (https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/PublicApiAnalyzers/PublicApiAnalyzers.Help.md)
this Span span,
IFontManager fontManager,
double defaultLineHeight = -1,
TextAlignment defaultHorizontalAlignment = TextAlignment.Start,
Font? defaultFont = null,
Color? defaultColor = null,
TextTransform defaultTextTransform = TextTransform.Default)
=> span.ToNSAttributedString(fontManager, defaultLineHeight, defaultHorizontalAlignment, defaultFont, defaultColor, defaultTextTransform, LineBreakMode.WordWrap, defaultCharacterSpacing: 0d);
TextTransform defaultTextTransform = TextTransform.Default,
LineBreakMode defaultLineBreakMode = LineBreakMode.WordWrap)
=> span.ToNSAttributedString(fontManager, defaultLineHeight, defaultHorizontalAlignment, defaultFont, defaultColor, defaultTextTransform, defaultLineBreakMode, defaultCharacterSpacing: 0d);

internal static NSAttributedString ToNSAttributedString(
this Span span,
Expand All @@ -92,7 +94,7 @@
Font? defaultFont,
Color? defaultColor,
TextTransform defaultTextTransform,
LineBreakMode lineBreakMode,
LineBreakMode defaultLineBreakMode,
double defaultCharacterSpacing = 0d)
{
var defaultFontSize = defaultFont?.Size ?? fontManager.DefaultFontSize;
Expand Down Expand Up @@ -123,16 +125,27 @@
_ => UITextAlignment.Left
};

style.LineBreakMode = lineBreakMode switch
#if !MACOS
style.LineBreakMode = defaultLineBreakMode switch
{
LineBreakMode.NoWrap => UILineBreakMode.Clip,
LineBreakMode.WordWrap => UILineBreakMode.WordWrap,
LineBreakMode.CharacterWrap => UILineBreakMode.CharacterWrap,
LineBreakMode.HeadTruncation => UILineBreakMode.HeadTruncation,
LineBreakMode.TailTruncation => UILineBreakMode.TailTruncation,
LineBreakMode.MiddleTruncation => UILineBreakMode.MiddleTruncation,
LineBreakMode.TailTruncation => UILineBreakMode.TailTruncation,
_ => UILineBreakMode.WordWrap
};
#else
style.LineBreakMode = defaultLineBreakMode switch
{
LineBreakMode.NoWrap => NSLineBreakMode.Clipping,
LineBreakMode.CharacterWrap => NSLineBreakMode.CharWrapping,
LineBreakMode.HeadTruncation => NSLineBreakMode.TruncatingHead,
LineBreakMode.MiddleTruncation => NSLineBreakMode.TruncatingMiddle,
LineBreakMode.TailTruncation => NSLineBreakMode.TruncatingTail,
_ => NSLineBreakMode.ByWordWrapping
};
#endif

var font = span.GetEffectiveFont(defaultFontSize, defaultFont);
var hasUnderline = false;
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,12 @@
</Button>

<Label Grid.Row="1"
Text="Clicked Event: "/>
Text="Clicked Event: "
AutomationId="MainLabel">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="MainLabel_Tapped"/>
</Label.GestureRecognizers>
</Label>
<Label Grid.Row="1"
Grid.Column="1"
x:Name="ClickedEventLabel"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using Microsoft.Maui.Controls.Internals;

namespace Maui.Controls.Sample;

public class ButtonControlPage : NavigationPage
Expand Down Expand Up @@ -52,4 +54,17 @@ public void OnButtonReleased(object sender, EventArgs e)
ReleasedEventLabel.Text = "Released Event Executed";
}
}

void MainLabel_Tapped(object sender, TappedEventArgs e)
{
// Recreate the page to verify initial mappers
ToolbarItems.Clear();
Content = new ContentView();
INameScope scope = this;
scope.UnregisterName("ClickedEventLabel");
scope.UnregisterName("ReleasedEventLabel");
scope.UnregisterName("PressedEventLabel");
scope.UnregisterName("ButtonShadow");
InitializeComponent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@
<VerticalStackLayout Padding="20"
Spacing="8">
<Label Text="Entry Control"
AutomationId="MainLabel"
FontSize="20"
Margin="0,0,0,50"
HorizontalOptions="Center"/>

HorizontalOptions="Center">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="MainLabel_Tapped"/>
</Label.GestureRecognizers>
</Label>
<local:UITestEntry x:Name="EntryControl"
IsCursorVisible="False"
Text="{Binding Text}"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.ComponentModel;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Internals;

namespace Maui.Controls.Sample;

Expand Down Expand Up @@ -130,4 +131,37 @@ private void EntryControl_Unfocused(object sender, FocusEventArgs e)
vm.UnfocusedText = eventInfo;
}
}

void MainLabel_Tapped(object sender, TappedEventArgs e)
{
// Recreate the page to verify initial mappers
ToolbarItems.Clear();
Content = new ContentView();
INameScope scope = this;
scope.UnregisterName("EntryControl");
scope.UnregisterName("TextChangedLabel");
scope.UnregisterName("SelectionLengthEntry");
scope.UnregisterName("CursorPositionEntry");
scope.UnregisterName("CompletedLabel");
scope.UnregisterName("FocusedLabel");
scope.UnregisterName("UnfocusedLabel");
scope.UnregisterName("grid");
InitializeComponent();

if (OperatingSystem.IsIOSVersionAtLeast(26))
{
grid.HeightRequest = 100;
}
else
{
grid.HeightRequest = 130;
}

// Reattach the PropertyChanged event handler after reinitialization
EntryControl.PropertyChanged += UpdateEntryControl;

// Update the entry fields to reflect current values
CursorPositionEntry.Text = EntryControl.CursorPosition.ToString();
SelectionLengthEntry.Text = EntryControl.SelectionLength.ToString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
Clicked="HorizontalAlignmentButton_Clicked"/>
<Button Text="End"
AutomationId="HEnd"
FontSize="10"
Clicked="HorizontalAlignmentButton_Clicked"/>
</HorizontalStackLayout>
<!-- Vertical Alignment -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,35 @@
Title="LabelControlPage">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Options"
Clicked="NavigateToOptionsPage_Clicked"
AutomationId="Options"/>
Clicked="NavigateToOptionsPage_Clicked"
AutomationId="Options"/>
</ContentPage.ToolbarItems>

<VerticalStackLayout>
<Label
HeightRequest="600"
Text="{Binding Text , Mode=TwoWay}"
CharacterSpacing="{Binding CharacterSpacing}"
FontAttributes="{Binding FontAttributes}"
FontAutoScalingEnabled="{Binding FontAutoScalingEnabled}"
FontFamily="{Binding FontFamily}"
FontSize="{Binding FontSize}"
FormattedText="{Binding FormattedText}"
HorizontalTextAlignment="{Binding HorizontalTextAlignment}"
LineBreakMode="{Binding LineBreakMode}"
LineHeight="{Binding LineHeight}"
MaxLines="{Binding MaxLines}"
Padding="{Binding Padding}"
TextColor="{Binding TextColor}"
TextDecorations="{Binding TextDecorations}"
TextTransform="{Binding TextTransform}"
TextType="{Binding TextType}"
VerticalTextAlignment="{Binding VerticalTextAlignment}"
BackgroundColor="LightGray"
AutomationId="MainLabel"/>
</VerticalStackLayout>
<VerticalStackLayout>
<Label
HeightRequest="600"
Text="{Binding Text , Mode=TwoWay}"
CharacterSpacing="{Binding CharacterSpacing}"
FontAttributes="{Binding FontAttributes}"
FontAutoScalingEnabled="{Binding FontAutoScalingEnabled}"
FontFamily="{Binding FontFamily}"
FontSize="{Binding FontSize}"
FormattedText="{Binding FormattedText}"
HorizontalTextAlignment="{Binding HorizontalTextAlignment}"
LineBreakMode="{Binding LineBreakMode}"
LineHeight="{Binding LineHeight}"
MaxLines="{Binding MaxLines}"
Padding="{Binding Padding}"
TextColor="{Binding TextColor}"
TextDecorations="{Binding TextDecorations}"
TextTransform="{Binding TextTransform}"
TextType="{Binding TextType}"
VerticalTextAlignment="{Binding VerticalTextAlignment}"
BackgroundColor="LightGray"
AutomationId="MainLabel">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="MainLabel_Tapped"/>
</Label.GestureRecognizers>
</Label>
</VerticalStackLayout>
</ContentPage>
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,16 @@ private async void NavigateToOptionsPage_Clicked(object sender, EventArgs e)
BindingContext = _viewModel = new LabelViewModel();
await Navigation.PushAsync(new LabelOptionsPage(_viewModel));
}

void MainLabel_Tapped(object sender, TappedEventArgs e)
{
// Recreate the page to verify initial mappers
// Clear BindingContext first so old Label properly detaches the FormattedString
// (triggers propertyChanging which unsubscribes events and calls RemoveSpans)
ToolbarItems.Clear();
BindingContext = null;
Content = new ContentView();
InitializeComponent();
BindingContext = _viewModel;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,13 @@
CheckedChanged="OnLineBreakModeChanged"
AutomationId="LineBreakModeTailTruncation"/>
</HorizontalStackLayout>
<HorizontalStackLayout>
<Label Text="Single Line Formatted Text"
VerticalOptions="Center"/>
<CheckBox x:Name="SimpleFormattedTextCheckBox"
CheckedChanged="SimpleFormattedTextCheckBox_CheckedChanged"
AutomationId="SimpleFormattedText"/>
</HorizontalStackLayout>
</VerticalStackLayout>
</Grid>
</VerticalStackLayout>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,4 +239,15 @@ private void OnFormattedTextChanged(object sender, CheckedChangedEventArgs e)
}
}

private void SimpleFormattedTextCheckBox_CheckedChanged(object sender, CheckedChangedEventArgs e)
{
if (e.Value)
{
_viewModel.FormattedText = new FormattedString
{
Spans = { new Span { Text = "This is a Basic Label" } }
};
_viewModel.Text = null;
}
}
}
Loading
Loading