Skip to content

[Android] Fixed the Label Width related issues #29620

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

Ahamed-Ali
Copy link
Contributor

@Ahamed-Ali Ahamed-Ali commented May 22, 2025

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Root Cause of the issue

  • When using the label inside the collectionview , on orientation change of device cause the Layout.Width not properly measured, due to the small width , clipping issue occurred.

Description of Change

  • Instead of relying on the Layout property , we can use the StaticLayout from the TextLayoutUtils Extensions and working fine properly

Issues Fixed

Fixes #29542

Tested the behaviour in the following platforms

  • Android
  • Windows
  • iOS
  • Mac

Screenshot

Before Issue Fix After Issue Fix
CollectionViewLabelIssue.mov
CollectionViewLabelFix.mov

Copy link
Contributor

Hey there @@Ahamed-Ali! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

@dotnet-policy-service dotnet-policy-service bot added community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration labels May 22, 2025
@jsuarezruiz jsuarezruiz added the area-controls-label Label, Span label May 22, 2025
@jsuarezruiz
Copy link
Contributor

/azp run MAUI-UITests-public

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@Ahamed-Ali Ahamed-Ali marked this pull request as ready for review May 23, 2025 11:40
@Copilot Copilot AI review requested due to automatic review settings May 23, 2025 11:40
@Ahamed-Ali Ahamed-Ali requested a review from a team as a code owner May 23, 2025 11:40
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes label clipping issues on Android when rotating devices by switching to a static layout measurement and adds automated UI tests to verify correct sizing in a CollectionView scenario.

  • Replaces reliance on Layout with TextLayoutUtils.CreateLayout in MauiTextView.OnMeasure
  • Introduces a UI test (Issue29542) to ensure labels size properly after orientation changes
  • Adds a HostApp reproduction page for the issue with a CollectionView and test automation IDs

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

File Description
src/Core/src/Platform/Android/MauiTextView.cs Use StaticLayout from TextLayoutUtils for width measurement instead of the native Layout logic
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue29542.cs Added a UI test that rotates the emulator and verifies label sizing in a CollectionView
src/Controls/tests/TestCases.HostApp/Issues/Issue29542.cs Provided a sample page with a CollectionView and navigation button to reproduce the clipping bug
Comments suppressed due to low confidence (1)

src/Core/src/Platform/Android/MauiTextView.cs:28

  • [nitpick] The local variable layout shadows the Layout property from the base class; consider renaming it to something more descriptive like staticLayout to avoid confusion.
var layout = TextLayoutUtils.CreateLayout(Text, Paint, availableWidth - totalPadding, Android.Text.Layout.Alignment.AlignNormal);

Comment on lines 22 to 29
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
if (MeasureSpec.GetMode(widthMeasureSpec) == MeasureSpecMode.AtMost && Layout is not null)
if (MeasureSpec.GetMode(widthMeasureSpec) == MeasureSpecMode.AtMost && !string.IsNullOrEmpty(Text))
{
// Ensure the Layout is valid and measured before reading LineCount or GetLineWidth(i) to avoid unnecessary calculations.
if (Layout.Width > 0)
{
// Calculate the total width needed based on text content plus padding
int contentWidth = (int)Math.Ceiling(GetMaxLineWidth(Layout));
int totalPadding = CompoundPaddingLeft + CompoundPaddingRight;
int requiredWidth = contentWidth + totalPadding;

// Constrain to maximum available width from original spec
int availableWidth = MeasureSpec.GetSize(widthMeasureSpec);
int desiredWidth = Math.Min(requiredWidth, availableWidth);
widthMeasureSpec = MeasureSpec.MakeMeasureSpec(desiredWidth, MeasureSpecMode.AtMost);
}
int availableWidth = MeasureSpec.GetSize(widthMeasureSpec);
int totalPadding = CompoundPaddingLeft + CompoundPaddingRight;
var layout = TextLayoutUtils.CreateLayout(Text, Paint, availableWidth - totalPadding, Android.Text.Layout.Alignment.AlignNormal);
int contentWidth = (int)Math.Ceiling(GetMaxLineWidth(layout));
Copy link
Preview

Copilot AI May 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating a new StaticLayout on every measure may be expensive; consider caching the layout when the text or width changes to avoid redundant allocations.

Copilot uses AI. Check for mistakes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of creating a new layout every time OnMeasure is called, caching the layout if the text and width haven’t changed might improve performance

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have created a new layout only when necessary to improve performance. @jsuarezruiz

@@ -0,0 +1,25 @@
#if TEST_FAILS_ON_CATALYST && TEST_FAILS_ON_WINDOWS //The test fails on Windows and MacCatalyst because the SetOrientation method, which is intended to change the device orientation, is only supported on mobile platforms iOS and Android.
Copy link
Preview

Copilot AI May 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The preprocessor directive uses && which means the test will only compile when both macros are defined; likely you intended || so it’s excluded on either platform where it fails.

Suggested change
#if TEST_FAILS_ON_CATALYST && TEST_FAILS_ON_WINDOWS //The test fails on Windows and MacCatalyst because the SetOrientation method, which is intended to change the device orientation, is only supported on mobile platforms iOS and Android.
#if TEST_FAILS_ON_CATALYST || TEST_FAILS_ON_WINDOWS //The test fails on Windows and MacCatalyst because the SetOrientation method, which is intended to change the device orientation, is only supported on mobile platforms iOS and Android.

Copilot uses AI. Check for mistakes.

@jsuarezruiz
Copy link
Contributor

/azp run MAUI-UITests-public

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@@ -20,21 +21,16 @@ internal override void OnLayoutFormatted(bool changed, int l, int t, int r, int
}
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
if (MeasureSpec.GetMode(widthMeasureSpec) == MeasureSpecMode.AtMost && Layout is not null)
if (MeasureSpec.GetMode(widthMeasureSpec) == MeasureSpecMode.AtMost && !string.IsNullOrEmpty(Text))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You check !string.IsNullOrEmpty(Text), but if Text is empty later, will the component resize correctly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have verified this by dynamically setting the text to an empty string (string.Empty); it resizes correctly, just as it did before the fix.

Comment on lines 22 to 29
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
if (MeasureSpec.GetMode(widthMeasureSpec) == MeasureSpecMode.AtMost && Layout is not null)
if (MeasureSpec.GetMode(widthMeasureSpec) == MeasureSpecMode.AtMost && !string.IsNullOrEmpty(Text))
{
// Ensure the Layout is valid and measured before reading LineCount or GetLineWidth(i) to avoid unnecessary calculations.
if (Layout.Width > 0)
{
// Calculate the total width needed based on text content plus padding
int contentWidth = (int)Math.Ceiling(GetMaxLineWidth(Layout));
int totalPadding = CompoundPaddingLeft + CompoundPaddingRight;
int requiredWidth = contentWidth + totalPadding;

// Constrain to maximum available width from original spec
int availableWidth = MeasureSpec.GetSize(widthMeasureSpec);
int desiredWidth = Math.Min(requiredWidth, availableWidth);
widthMeasureSpec = MeasureSpec.MakeMeasureSpec(desiredWidth, MeasureSpecMode.AtMost);
}
int availableWidth = MeasureSpec.GetSize(widthMeasureSpec);
int totalPadding = CompoundPaddingLeft + CompoundPaddingRight;
var layout = TextLayoutUtils.CreateLayout(Text, Paint, availableWidth - totalPadding, Android.Text.Layout.Alignment.AlignNormal);
int contentWidth = (int)Math.Ceiling(GetMaxLineWidth(layout));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of creating a new layout every time OnMeasure is called, caching the layout if the text and width haven’t changed might improve performance

// Calculate the required width based on the content and padding
int requiredWidth = contentWidth + totalPadding;
int desiredWidth = Math.Min(requiredWidth, availableWidth);
widthMeasureSpec = MeasureSpec.MakeMeasureSpec(desiredWidth, MeasureSpecMode.AtMost);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assumes that desiredWidth is always valid. If padding is larger than available width, does this result in unexpected behavior?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested with a higher padding value, and it behaves the same as before the fix.
However, I have restricted the creation of a new layout if the padding exceeds the available width, as base.Measure can handle this scenario. @jsuarezruiz

@jsuarezruiz
Copy link
Contributor

/azp run MAUI-UITests-public

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-controls-label Label, Span community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration platform/android
Projects
None yet
Development

Successfully merging this pull request may close these issues.

I1_Vertical_list_for_Multiple_Rows - Rotating the emulator would cause clipping on the description text.
4 participants