protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (_child?.Element == null) { SetMeasuredDimension(0, 0); return; } VisualElement element = _child.Element; Context ctx = Context; var width = (int)ctx.FromPixels(MeasureSpecFactory.GetSize(widthMeasureSpec)); SizeRequest request = element.Measure(width, double.PositiveInfinity, MeasureFlags.IncludeMargins); Microsoft.Maui.Controls.Compatibility.Layout.LayoutChildIntoBoundingRegion(element, new Rectangle(0, 0, width, request.Request.Height)); int widthSpec = MeasureSpecFactory.MakeMeasureSpec((int)ctx.ToPixels(width), MeasureSpecMode.Exactly); int heightSpec = MeasureSpecFactory.MakeMeasureSpec((int)ctx.ToPixels(request.Request.Height), MeasureSpecMode.Exactly); _child.View.Measure(widthMeasureSpec, heightMeasureSpec); SetMeasuredDimension(widthSpec, heightSpec); }
public void UpdateLayout() { Performance.Start(out string reference); VisualElement view = _renderer.Element; AView aview = _renderer.View; var headlessOffset = CompressedLayout.GetHeadlessOffset(view); var x = (int)_context.ToPixels(view.X + headlessOffset.X); var y = (int)_context.ToPixels(view.Y + headlessOffset.Y); var width = Math.Max(0, (int)_context.ToPixels(view.Width)); var height = Math.Max(0, (int)_context.ToPixels(view.Height)); var formsViewGroup = aview as Controls.Android.FormsViewGroup; if (formsViewGroup == null) { Performance.Start(reference, "Measure"); aview.Measure(MeasureSpecFactory.MakeMeasureSpec(width, MeasureSpecMode.Exactly), MeasureSpecFactory.MakeMeasureSpec(height, MeasureSpecMode.Exactly)); Performance.Stop(reference, "Measure"); Performance.Start(reference, "Layout"); aview.Layout(x, y, x + width, y + height); Performance.Stop(reference, "Layout"); } else { Performance.Start(reference, "MeasureAndLayout"); formsViewGroup.MeasureAndLayout(MeasureSpecFactory.MakeMeasureSpec(width, MeasureSpecMode.Exactly), MeasureSpecFactory.MakeMeasureSpec(height, MeasureSpecMode.Exactly), x, y, x + width, y + height); Performance.Stop(reference, "MeasureAndLayout"); } // If we're running sufficiently new Android, we have to make sure to update the ClipBounds to // match the new size of the ViewGroup if ((int)Forms.SdkInt >= 18) { UpdateClipToBounds(); } UpdateClip(); Performance.Stop(reference); //On Width or Height changes, the anchors needs to be updated UpdateAnchorX(); UpdateAnchorY(); }
void OnScrollToRequested(object sender, ScrollToRequestedEventArgs e) { if (!_isAttached) { _pendingScrollTo = e; return; } Cell cell; int scrollPosition; var scrollArgs = (ITemplatedItemsListScrollToRequestedEventArgs)e; var templatedItems = TemplatedItemsView.TemplatedItems; if (Element.IsGroupingEnabled) { var results = templatedItems.GetGroupAndIndexOfItem(scrollArgs.Group, scrollArgs.Item); int indexOfGroup = results.Item1; int indexOfItem = results.Item2; if (indexOfGroup == -1) { return; } int itemIndex = indexOfItem == -1 ? 0 : indexOfItem; var group = templatedItems.GetGroup(indexOfGroup); if (group.Count == 0) { cell = group.HeaderContent; } else { cell = group[itemIndex]; } //Increment Scroll Position by 1 when Grouping is enabled. Android offsets position of cells when using header. scrollPosition = templatedItems.GetGlobalIndexForGroup(group) + itemIndex + 1; } else { scrollPosition = templatedItems.GetGlobalIndexOfItem(scrollArgs.Item); if (scrollPosition == -1) { return; } cell = templatedItems[scrollPosition]; } //Android offsets position of cells when using header int realPositionWithHeader = scrollPosition + 1; if (e.Position == ScrollToPosition.MakeVisible) { if (e.ShouldAnimate) { Control.SmoothScrollToPosition(realPositionWithHeader); } else { Control.SetSelection(realPositionWithHeader); } return; } int height = Control.Height; var cellHeight = (int)cell.RenderHeight; if (cellHeight == -1) { int first = Control.FirstVisiblePosition; if (first <= scrollPosition && scrollPosition <= Control.LastVisiblePosition) { cellHeight = Control.GetChildAt(scrollPosition - first).Height; } else { AView view = _adapter.GetView(scrollPosition, null, null); view.Measure(MeasureSpecFactory.MakeMeasureSpec(Control.Width, MeasureSpecMode.AtMost), MeasureSpecFactory.MakeMeasureSpec(0, MeasureSpecMode.Unspecified)); cellHeight = view.MeasuredHeight; } } var y = 0; if (e.Position == ScrollToPosition.Center) { y = height / 2 - cellHeight / 2; } else if (e.Position == ScrollToPosition.End) { y = height - cellHeight; } if (e.ShouldAnimate) { Control.SmoothScrollToPositionFromTop(realPositionWithHeader, y); } else { Control.SetSelectionFromTop(realPositionWithHeader, y); } }
public void LayoutView(double x, double y, double width, double height, double?maxWidth = null, double?maxHeight = null) { if (width == -1) { width = double.PositiveInfinity; } if (height == -1) { height = double.PositiveInfinity; } Width = width; Height = height; MaxWidth = maxWidth; MaxHeight = maxHeight; X = x; Y = y; Context context; if (Renderer == null || !(_context.TryGetTarget(out context)) || !Renderer.View.IsAlive()) { return; } if (View == null) { var empty = MeasureSpecFactory.GetSize(0); Renderer.View.Measure(empty, empty); return; } var request = View.Measure(width, height, MeasureFlags.None); var layoutParams = NativeView.LayoutParameters; if (double.IsInfinity(height)) { height = request.Request.Height; } if (double.IsInfinity(width)) { width = request.Request.Width; } if (height > maxHeight) { height = maxHeight.Value; } if (width > maxWidth) { width = maxWidth.Value; } if (layoutParams.Width != LP.MatchParent) { layoutParams.Width = (int)context.ToPixels(width); } if (layoutParams.Height != LP.MatchParent) { layoutParams.Height = (int)context.ToPixels(height); } NativeView.LayoutParameters = layoutParams; View.Layout(new Rectangle(x, y, width, height)); Renderer.UpdateLayout(); }
void IPlatformLayout.OnLayout(bool changed, int l, int t, int r, int b) { if (Page == null) { return; } if (changed) { LayoutRootPage(Page, r - l, b - t); } GetRenderer(Page)?.UpdateLayout(); for (var i = 0; i < _renderer.ChildCount; i++) { AView child = _renderer.GetChildAt(i); if (child is ModalContainer) { child.Measure(MeasureSpecFactory.MakeMeasureSpec(r - l, MeasureSpecMode.Exactly), MeasureSpecFactory.MakeMeasureSpec(t - b, MeasureSpecMode.Exactly)); child.Layout(l, t, r, b); } } }
public void UpdateLayout() { Performance.Start(out string reference); VisualElement view = _renderer.Element; AView aview = _renderer.View; var headlessOffset = CompressedLayout.GetHeadlessOffset(view); var x = (int)_context.ToPixels(view.X + headlessOffset.X); var y = (int)_context.ToPixels(view.Y + headlessOffset.Y); var width = Math.Max(0, (int)_context.ToPixels(view.Width)); var height = Math.Max(0, (int)_context.ToPixels(view.Height)); if (aview is FormsViewGroup formsViewGroup) { Performance.Start(reference, "MeasureAndLayout"); formsViewGroup.MeasureAndLayout(MeasureSpecFactory.MakeMeasureSpec(width, MeasureSpecMode.Exactly), MeasureSpecFactory.MakeMeasureSpec(height, MeasureSpecMode.Exactly), x, y, x + width, y + height); Performance.Stop(reference, "MeasureAndLayout"); } else if ((aview is LayoutViewGroup || aview is ContentViewGroup || aview is CoordinatorLayout || aview is FragmentContainerView) && width == 0 && height == 0) { // Nothing to do here; just chill. } else { Performance.Start(reference, "Measure"); aview.Measure(MeasureSpecFactory.MakeMeasureSpec(width, MeasureSpecMode.Exactly), MeasureSpecFactory.MakeMeasureSpec(height, MeasureSpecMode.Exactly)); Performance.Stop(reference, "Measure"); Performance.Start(reference, "Layout"); aview.Layout(x, y, x + width, y + height); Performance.Stop(reference, "Layout"); } // We have to make sure to update the ClipBounds to match the new size of the ViewGroup UpdateClipToBounds(); UpdateClip(); Performance.Stop(reference); //On Width or Height changes, the anchors needs to be updated UpdateAnchorX(); UpdateAnchorY(); }