-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
[iOS] Fix for Shell custom FlyoutIcon display problem #26016
base: main
Are you sure you want to change the base?
[iOS] Fix for Shell custom FlyoutIcon display problem #26016
Conversation
/azp run |
This comment was marked as outdated.
This comment was marked as outdated.
@@ -336,7 +336,7 @@ void UpdateLeftToolbarItems() | |||
|
|||
if (image != null) | |||
{ | |||
icon = result?.Value; | |||
icon = ResizeImage(result?.Value, new CGSize(23f, 23f)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is iOS the only one that doesn't resize?
Is this size correct under all the screen options? (@2x etc) https://developer.apple.com/design/human-interface-guidelines/toolbars
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is iOS the only one that doesn't resize? Is this size correct under all the screen options? (@2x etc) https://developer.apple.com/design/human-interface-guidelines/toolbars
@jsuarezruiz, I have tested the icon under all device screen options, and it works properly on all devices. The size I am using for the custom icon is based on the default Hamburger icon size. Please refer to the code below for your reference
Reference for icon size:
maui/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellPageRendererTracker.cs
Line 495 in c363191
var rect = new CGRect(0, 0, 23f, 23f); |
@@ -0,0 +1,27 @@ | |||
#if !WINDOWS | |||
// In Windows, the foreground color is not applied to the custom icon, | |||
// so as of now, the test is not applicable for Windows. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Windows is the only one having a different behavior, right?
Could you open a new issue and include the link in the comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Windows is the only one having a different behavior, right? Could you open a new issue and include the link in the comment.
@jsuarezruiz, the new issue for the Windows platform has been logged and I have added a comment. Could you please check and provide your concerns if any?
// https://github.com/dotnet/maui/issues/26148 |
Azure Pipelines successfully started running 3 pipeline(s). |
} | ||
} | ||
} | ||
UIImage ResizeImage(UIImage sourceImage, CGSize targetSize) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This creates a new image with new data, and potentially wastes memory. I feel like we have this problem solved somewhere before that just scales the image. Let me see...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This place:
maui/src/Controls/src/Core/Button/Button.iOS.cs
Lines 433 to 449 in af94a22
static UIImage ResizeImageSource(UIImage sourceImage, nfloat maxWidth, nfloat maxHeight, CGSize originalImageSize, bool shouldScaleUp = false) | |
{ | |
if (sourceImage is null || sourceImage.CGImage is null) | |
return null; | |
maxWidth = (nfloat)Math.Min(maxWidth, originalImageSize.Width); | |
maxHeight = (nfloat)Math.Min(maxHeight, originalImageSize.Height); | |
var sourceSize = sourceImage.Size; | |
float maxResizeFactor = (float)Math.Min(maxWidth / sourceSize.Width, maxHeight / sourceSize.Height); | |
if (maxResizeFactor > 1 && !shouldScaleUp) | |
return sourceImage; | |
return UIImage.FromImage(sourceImage.CGImage, sourceImage.CurrentScale / maxResizeFactor, sourceImage.Orientation); | |
} |
I think we can maybe extract this into some helper class, maybe an extension for UIImage?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, we probably want to preserve aspect ratio, the code sourceImage.Draw(new CGRect(0, 0, targetSize.Width, targetSize.Height));
will stretch in this PR. So the scaling way we have in button is probably safer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mattleibow, Thank you for the suggestion. I have moved the ResizeImageSource method from Button.iOS to the UIImageExtensions class. I applied the same logic in the ShellPageRendererTracker for the custom FlyoutIcon and also updated the button related code. Could you please review these changes and let me know if you have any concerns?
/azp run |
Azure Pipelines successfully started running 3 pipeline(s). |
/azp run |
Azure Pipelines successfully started running 3 pipeline(s). |
/azp run |
Azure Pipelines successfully started running 3 pipeline(s). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you split the android change out from this PR?
I think the resizing parts of this for the iOS Icon is going to need a little bit deeper of an analysis.
Like, I'm curious if users have an icon that's 30x30, or just slightly bigger than 40x40 if we want to resize.
Playing with the sandbox here's a few sizes
I don't know if we can force an opinion here on the size of that icon for users. If this is an issue in our template we should generate an image at the size it should be
Hi @PureWeen , I have created a separate PR 27502 for Android changes. Please review it and share your concerns. |
/azp run |
Azure Pipelines successfully started running 3 pipeline(s). |
/azp run |
Azure Pipelines successfully started running 3 pipeline(s). |
@@ -25,6 +26,24 @@ public static UIImage ScaleImage(this UIImage target, float maxWidth, float maxH | |||
return ScaleImage(target, new CGSize(targetWidth, targetHeight), disposeOriginal); | |||
} | |||
|
|||
internal static UIImage ResizeImageSource(this UIImage sourceImage, nfloat maxWidth, nfloat maxHeight, CGSize originalImageSize, bool shouldScaleUp = false) | |||
{ | |||
if (sourceImage is null || sourceImage.CGImage is null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can use the null-conditional operator to simplify the check:
if (sourceImage?.CGImage is null)
if (maxResizeFactor > 1 && !shouldScaleUp) | ||
return sourceImage; | ||
|
||
return UIImage.FromImage(sourceImage.CGImage, sourceImage.CurrentScale / maxResizeFactor, sourceImage.Orientation); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UIImage.FromImage
creates a new instance of UIImage with the specified parameters. Could modify the implementation to just transform the current one?
internal static UIImage ResizeImageSource(this UIImage sourceImage, nfloat maxWidth, nfloat maxHeight, CGSize originalImageSize, bool shouldScaleUp = false)
{
if (sourceImage?.CGImage is null)
return null;
maxWidth = (nfloat)Math.Min(maxWidth, originalImageSize.Width);
maxHeight = (nfloat)Math.Min(maxHeight, originalImageSize.Height);
var sourceSize = sourceImage.Size;
var maxResizeFactor = (nfloat)Math.Min(maxWidth / sourceSize.Width, maxHeight / sourceSize.Height);
if (maxResizeFactor > 1 && !shouldScaleUp)
return sourceImage;
var newSize = new CGSize(sourceSize.Width * maxResizeFactor, sourceSize.Height * maxResizeFactor);
UIGraphics.BeginImageContextWithOptions(newSize, false, 0.0f);
sourceImage.Draw(new CGRect(0, 0, newSize.Width, newSize.Height));
var resizedImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return resizedImage;
}
This approach uses the image context to resize the image, should be more efficient than creating a new instance.
Issue: The flyout icon is aligned to the center instead of the left, causing the title to extend beyond the view.
Root Cause of the issue
Description of Change
Reference for icon size: https://github.com/dotnet/maui/blob/main/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellPageRendererTracker.cs#L450
Issues Fixed
Fixes #25920
Tested the behaviour in the following platforms
Screenshot
iOS