Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)

if (Content.VirtualView.Handler is IPlatformViewHandler pvh)
{
var widthSpec = Context.CreateMeasureSpec(targetWidth,
var (widthSpec, _, _) = Context.CreateMeasureSpec(targetWidth,
double.IsInfinity(targetWidth) ? double.NaN : targetWidth
, minimumSize: double.NaN, maximumSize: targetWidth);

var heightSpec = Context.CreateMeasureSpec(targetHeight, double.IsInfinity(targetHeight) ? double.NaN : targetHeight
var (heightSpec, _, _) = Context.CreateMeasureSpec(targetHeight, double.IsInfinity(targetHeight) ? double.NaN : targetHeight
, minimumSize: double.NaN, maximumSize: targetHeight);

var size = pvh.MeasureVirtualView(widthSpec, heightSpec);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import android.util.AttributeSet;
import android.view.ViewGroup;

public abstract class PlatformContentViewGroup extends ViewGroup {
public abstract class PlatformContentViewGroup extends PlatformViewGroup {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@rmarinho is this a change doable during .NET10 SRs cycle or should I prepare a PR to do this now?

I think this is feasible even later... PlatformViewGroup is a ViewGroup so I'm not causing any API change.

An all PlatformViewGroup members will be internal.


public PlatformContentViewGroup(Context context) {
super(context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@
import android.view.ViewGroup;

public abstract class PlatformViewGroup extends ViewGroup {
boolean needsMeasure;
boolean nativeMeasure = true;

// We use a bit on each packed measured size to indicate the need for cross platform measure
// See also https://developer.android.com/reference/android/view/View#MEASURED_SIZE_MASK
public static final long NEEDS_MEASURE = 0x0800000008000000L;

public PlatformViewGroup(Context context) {
super(context);
}
Expand All @@ -22,4 +29,38 @@ public PlatformViewGroup(Context context, AttributeSet attrs, int defStyle) {
public PlatformViewGroup(Context context, AttributeSet attrs, int defStyle, int defStyleRes) {
super(context, attrs, defStyle, defStyleRes);
}

public long measureAndGetWidthAndHeight(int widthMeasureSpec, int heightMeasureSpec) {
this.needsMeasure = false;
this.nativeMeasure = false;
this.measure(widthMeasureSpec, heightMeasureSpec);
this.nativeMeasure = true;

if (this.needsMeasure) {
return NEEDS_MEASURE;
}

int width = this.getMeasuredWidth();
int height = this.getMeasuredHeight();
long measure = ((long)width << 32) | (height & 0xffffffffL);
return measure;
}

public void overrideMeasuredDimension(int width, int height) {
setMeasuredDimension(width, height);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (nativeMeasure) {
doMeasure(widthMeasureSpec, heightMeasureSpec);
} else {
this.needsMeasure = true;
setMeasuredDimension(0, 0);
}
}

protected void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public void invalidate() {
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
protected void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (getChildCount() == 0) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
Expand All @@ -140,6 +140,34 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(child.getMeasuredWidth(), child.getMeasuredHeight());
}

@Override
public long measureAndGetWidthAndHeight(int widthMeasureSpec, int heightMeasureSpec) {
if (getChildCount() == 0 || !(getChildAt(0) instanceof PlatformViewGroup)) {
this.measure(widthMeasureSpec, heightMeasureSpec);
int width = this.getMeasuredWidth();
int height = this.getMeasuredHeight();
long measure = ((long)width << 32) | (height & 0xffffffffL);
return measure;
} else {
PlatformViewGroup child = (PlatformViewGroup)getChildAt(0);
long measure = super.measureAndGetWidthAndHeight(widthMeasureSpec, heightMeasureSpec);
child.measureAndGetWidthAndHeight(widthMeasureSpec, heightMeasureSpec);
return measure;
}
}

@Override
public void overrideMeasuredDimension(int width, int height) {
setMeasuredDimension(width, height);

if (getChildCount() == 0 || !(getChildAt(0) instanceof PlatformViewGroup)) {
return;
}

PlatformViewGroup child = (PlatformViewGroup)getChildAt(0);
child.overrideMeasuredDimension(width, height);
}

@Override
protected void dispatchDraw(Canvas canvas) {
if (paintType != PlatformPaintType.NONE) {
Expand Down
4 changes: 2 additions & 2 deletions src/Core/src/Handlers/ScrollView/ScrollViewHandler.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ public override Size GetDesiredSize(double widthConstraint, double heightConstra
}

// Create a spec to handle the native measure
var widthSpec = Context.CreateMeasureSpec(widthConstraint, virtualView.Width, virtualView.MinimumWidth, virtualView.MaximumWidth);
var heightSpec = Context.CreateMeasureSpec(heightConstraint, virtualView.Height, virtualView.MinimumHeight, virtualView.MaximumHeight);
var (widthSpec, _, _) = Context.CreateMeasureSpec(widthConstraint, virtualView.Width, virtualView.MinimumWidth, virtualView.MaximumWidth);
var (heightSpec, _, _) = Context.CreateMeasureSpec(heightConstraint, virtualView.Height, virtualView.MinimumHeight, virtualView.MaximumHeight);

if (platformView.FillViewport)
{
Expand Down
65 changes: 60 additions & 5 deletions src/Core/src/Handlers/ViewHandlerExtensions.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,68 @@ internal static Size GetDesiredSizeFromHandler(this IViewHandler viewHandler, do
}

// Create a spec to handle the native measure
var widthSpec = context.CreateMeasureSpec(widthConstraint, virtualView.Width, virtualView.MinimumWidth, virtualView.MaximumWidth);
var heightSpec = context.CreateMeasureSpec(heightConstraint, virtualView.Height, virtualView.MinimumHeight, virtualView.MaximumHeight);
var (widthSpec, widthDp, widthExact) = context.CreateMeasureSpec(widthConstraint, virtualView.Width, virtualView.MinimumWidth, virtualView.MaximumWidth);
var (heightSpec, heightDp, heightExact) = context.CreateMeasureSpec(heightConstraint, virtualView.Height, virtualView.MinimumHeight, virtualView.MaximumHeight);

var packed = PlatformInterop.MeasureAndGetWidthAndHeight(platformView, widthSpec, heightSpec);
var measuredWidth = (int)(packed >> 32);
var measuredHeight = (int)(packed & 0xffffffffL);
if (platformView is PlatformViewGroup platformViewGroup)
{
return GetDesiredSizeFromPlatformViewGroup(context, platformViewGroup, widthSpec, heightSpec, widthDp, heightDp, widthExact, heightExact);
}

var packedValue = PlatformInterop.MeasureAndGetWidthAndHeight(platformView, widthSpec, heightSpec);

var measuredWidth = (int)(packedValue >> 32);
var measuredHeight = (int)(packedValue & 0xffffffffL);
// Convert back to xplat sizes for the return value
return context.FromPixels(measuredWidth, measuredHeight);
}

static Size GetDesiredSizeFromPlatformViewGroup(Context context, PlatformViewGroup platformViewGroup, int widthSpec, int heightSpec, double widthDp, double heightDp,
bool widthExact, bool heightExact)
{
int measuredWidth;
int measuredHeight;

// If it's a WrapperView we need to check the wrapped view instead
var unwrappedView = ((platformViewGroup as WrapperView)?.WrappedView ?? platformViewGroup) as PlatformViewGroup;
var crossPlatformLayout = (unwrappedView as ICrossPlatformLayoutBacking)?.CrossPlatformLayout;

// This instance of PlatformViewGroup is not backed by a crossPlatformLayout, so we need to go through the default measure method
if (crossPlatformLayout is null)
{
var nativePacked = PlatformInterop.MeasureAndGetWidthAndHeight(platformViewGroup, widthSpec, heightSpec);

var nativeWidth = (int)(nativePacked >> 32);
var nativeHeight = (int)(nativePacked & 0xffffffffL);
// Convert back to xplat sizes for the return value
return context.FromPixels(nativeWidth, nativeHeight);
}

var packed = platformViewGroup.MeasureAndGetWidthAndHeight(widthSpec, heightSpec);
if (packed != PlatformViewGroup.NeedsMeasure)
{
measuredWidth = (int)(packed >> 32);
measuredHeight = (int)(packed & 0xffffffffL);
// Convert back to xplat sizes for the return value
return context.FromPixels(measuredWidth, measuredHeight);
}

var measure = crossPlatformLayout.CrossPlatformMeasure(widthDp, heightDp);

// If the measure spec was exact, we should return the explicit size value, even if the content
// measure came out to a different size
var measuredWidthDp = widthExact ? widthDp : measure.Width;
var measuredHeightDp = heightExact ? heightDp : measure.Height;

measuredWidth = (int)context.ToPixels(measuredWidthDp);
measuredHeight = (int)context.ToPixels(measuredHeightDp);

// Minimum values win over everything
measuredWidth = Math.Max(platformViewGroup.MinimumWidth, measuredWidth);
measuredHeight = Math.Max(platformViewGroup.MinimumHeight, measuredHeight);

platformViewGroup.OverrideMeasuredDimension(measuredWidth, measuredHeight);

// Convert back to xplat sizes for the return value
return context.FromPixels(measuredWidth, measuredHeight);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Core/src/Platform/Android/ContentViewGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ Graphics.Size CrossPlatformArrange(Graphics.Rect bounds)
{
return CrossPlatformLayout?.CrossPlatformArrange(bounds) ?? Graphics.Size.Zero;
}

protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
internal override void DoMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
if (CrossPlatformLayout is null)
{
Expand Down
10 changes: 8 additions & 2 deletions src/Core/src/Platform/Android/ContextExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -415,14 +415,17 @@ internal static int GetNavigationBarHeight(this Context context)
return _navigationBarHeight ?? 0;
}

internal static int CreateMeasureSpec(this Context context, double constraint, double explicitSize, double minimumSize, double maximumSize)
internal static (int MeasureSpec, double CrossPlatformConstraint, bool Exact) CreateMeasureSpec(this Context context, double constraint, double explicitSize, double minimumSize, double maximumSize)
{
var mode = MeasureSpecMode.AtMost;
var exact = false;
var crossPlatformConstraint = constraint;

if (IsExplicitSet(explicitSize))
{
// We have a set value (i.e., a Width or Height)
mode = MeasureSpecMode.Exactly;
exact = true;

// Since the mode is "Exactly", we have to return the exact final value clamped to the minimum/maximum.
constraint = Math.Max(explicitSize, ResolveMinimum(minimumSize));
Expand All @@ -431,11 +434,14 @@ internal static int CreateMeasureSpec(this Context context, double constraint, d
{
constraint = Math.Min(constraint, maximumSize);
}

crossPlatformConstraint = constraint;
}
else if (IsMaximumSet(maximumSize) && maximumSize < constraint)
{
mode = MeasureSpecMode.AtMost;
constraint = maximumSize;
crossPlatformConstraint = constraint;
}
else if (double.IsInfinity(constraint))
{
Expand All @@ -447,7 +453,7 @@ internal static int CreateMeasureSpec(this Context context, double constraint, d
// Convert to a platform size to create the spec for measuring
var deviceConstraint = (int)context.ToPixels(constraint);

return mode.MakeMeasureSpec(deviceConstraint);
return (mode.MakeMeasureSpec(deviceConstraint), crossPlatformConstraint, exact);
}

public static float GetDisplayDensity(this Context? context)
Expand Down
4 changes: 2 additions & 2 deletions src/Core/src/Platform/Android/LayoutViewGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ Graphics.Size CrossPlatformArrange(Graphics.Rect bounds)
{
return CrossPlatformLayout?.CrossPlatformArrange(bounds) ?? Graphics.Size.Zero;
}

// TODO: Possibly reconcile this code with ViewHandlerExtensions.MeasureVirtualView
// If you make changes here please review if those changes should also
// apply to ViewHandlerExtensions.MeasureVirtualView
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
internal override void DoMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
if (CrossPlatformMeasure == null)
{
Expand Down
2 changes: 2 additions & 0 deletions src/Core/src/Platform/Android/WrapperView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public partial class WrapperView : PlatformWrapperView

public bool InputTransparent { get; set; }

internal AView WrappedView => ChildCount > 0 ? GetChildAt(0) : null;

public WrapperView(Context context)
: base(context)
{
Expand Down
2 changes: 2 additions & 0 deletions src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ Microsoft.Maui.PlatformViewGroup.PlatformViewGroup(Android.Content.Context? cont
Microsoft.Maui.PlatformViewGroup.PlatformViewGroup(Android.Content.Context? context, Android.Util.IAttributeSet? attrs) -> void
Microsoft.Maui.PlatformViewGroup.PlatformViewGroup(Android.Content.Context? context, Android.Util.IAttributeSet? attrs, int defStyle) -> void
Microsoft.Maui.PlatformViewGroup.PlatformViewGroup(Android.Content.Context? context, Android.Util.IAttributeSet? attrs, int defStyle, int defStyleRes) -> void
*REMOVED*override Microsoft.Maui.Platform.ContentViewGroup.OnMeasure(int widthMeasureSpec, int heightMeasureSpec) -> void
*REMOVED*override Microsoft.Maui.Platform.LayoutViewGroup.OnMeasure(int widthMeasureSpec, int heightMeasureSpec) -> void
Microsoft.Maui.Hosting.MauiHostEnvironment
Microsoft.Maui.Hosting.MauiHostEnvironment.ApplicationName.get -> string!
Microsoft.Maui.Hosting.MauiHostEnvironment.ApplicationName.set -> void
Expand Down
4 changes: 4 additions & 0 deletions src/Core/src/Transforms/Metadata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
<attr path="//class[@name='PlatformAppCompatTextView']/method" name="visibility">internal</attr>
<attr path="//class[@name='PlatformAppCompatTextView']/constructor" name="visibility">internal</attr>
<attr path="//class[@name='PlatformWrapperView']/method[@name='updateShadow']" name="visibility">internal</attr>
<attr path="//class[@name='PlatformViewGroup']/method[@name='measureAndGetWidthAndHeight']" name="visibility">internal</attr>
<attr path="//class[@name='PlatformViewGroup']/method[@name='overrideMeasuredDimension']" name="visibility">internal</attr>
<attr path="//class[@name='PlatformViewGroup']/method[@name='doMeasure']" name="visibility">internal</attr>
<attr path="//class[@name='PlatformViewGroup']/field[@name='NEEDS_MEASURE']" name="visibility">internal</attr>

<remove-node path="//package[@name='com.bumptech.glide']" />
<remove-node path="//package[@name='com.microsoft.maui.glide']" />
Expand Down