void OnElementSizeChanged(object sender, EventArgs e) { Profile.FrameBegin(); Profile.FramePartition("ToPixels"); int width = (int)AndroidContext.ToPixels(Element.Width); int height = (int)AndroidContext.ToPixels(Element.Height); Profile.FramePartition("Measure"); _flyoutRenderer.AndroidView.Measure(MeasureSpecFactory.MakeMeasureSpec(width, MeasureSpecMode.Exactly), MeasureSpecFactory.MakeMeasureSpec(height, MeasureSpecMode.Exactly)); Profile.FramePartition("Layout"); _flyoutRenderer.AndroidView.Layout(0, 0, width, height); Profile.FrameEnd(); }
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(); }
protected override void OnLayout(bool changed, int left, int top, int right, int bottom) { var width = right - left; width -= (int)Context.ToPixels(25); var height = bottom - top; for (int i = 0; i < ChildCount; i++) { var child = GetChildAt(i); child.Measure(MeasureSpecFactory.MakeMeasureSpec(width, MeasureSpecMode.Exactly), MeasureSpecFactory.MakeMeasureSpec(height, MeasureSpecMode.Exactly)); child.Layout(0, 0, width, height); } _textBlock.DropDownHorizontalOffset = -_textBlock.Left; _textBlock.DropDownVerticalOffset = -(int)System.Math.Ceiling(_cardView.Radius); _textBlock.DropDownWidth = width; }
public static SizeRequest GetNativeSize( IVisualElementRenderer visualElementRenderer, double widthConstraint, double heightConstraint) { var context = visualElementRenderer.View.Context; // negative numbers have special meanings to android they don't to us widthConstraint = widthConstraint <= -1 ? double.PositiveInfinity : context.ToPixels(widthConstraint); heightConstraint = heightConstraint <= -1 ? double.PositiveInfinity : context.ToPixels(heightConstraint); bool widthConstrained = !double.IsPositiveInfinity(widthConstraint); bool heightConstrained = !double.IsPositiveInfinity(heightConstraint); int widthMeasureSpec = widthConstrained ? MeasureSpecFactory.MakeMeasureSpec((int)widthConstraint, MeasureSpecMode.AtMost) : MeasureSpecFactory.MakeMeasureSpec(0, MeasureSpecMode.Unspecified); int heightMeasureSpec = heightConstrained ? MeasureSpecFactory.MakeMeasureSpec((int)heightConstraint, MeasureSpecMode.AtMost) : MeasureSpecFactory.MakeMeasureSpec(0, MeasureSpecMode.Unspecified); SizeRequest rawResult = visualElementRenderer.GetDesiredSize(widthMeasureSpec, heightMeasureSpec); if (rawResult.Minimum == Size.Zero) { rawResult.Minimum = rawResult.Request; } var result = new SizeRequest(new Size(context.FromPixels(rawResult.Request.Width), context.FromPixels(rawResult.Request.Height)), new Size(context.FromPixels(rawResult.Minimum.Width), context.FromPixels(rawResult.Minimum.Height))); if ((widthConstrained && result.Request.Width < widthConstraint) || (heightConstrained && result.Request.Height < heightConstraint)) { // Do a final exact measurement in case the native control needs to fill the container (visualElementRenderer as IViewRenderer)?.MeasureExactly(); } return(result); }
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); }
protected override void OnLayout(bool changed, int left, int top, int right, int bottom) { // If the scroll view has changed size because of soft keyboard dismissal // (while WindowSoftInputModeAdjust is set to Resize), then we may need to request a // layout of the ScrollViewContainer bool requestContainerLayout = bottom > _previousBottom; _previousBottom = bottom; _container?.Measure(MeasureSpecFactory.MakeMeasureSpec(right - left, MeasureSpecMode.Unspecified), MeasureSpecFactory.MakeMeasureSpec(bottom - top, MeasureSpecMode.Unspecified)); base.OnLayout(changed, left, top, right, bottom); if (_view.Content != null && _hScrollView != null) { _hScrollView.Layout(0, 0, right - left, Math.Max(bottom - top, (int)Context.ToPixels(_view.Content.Height))); } else if (_view.Content != null && requestContainerLayout) { _container?.RequestLayout(); } // if the target sdk >= 17 then setting the LayoutDirection on the scroll view natively takes care of the scroll if (!_checkedForRtlScroll && _hScrollView != null && Element is IVisualElementController controller && controller.EffectiveFlowDirection.IsRightToLeft()) { if (Context.TargetSdkVersion() < 17) { _hScrollView.ScrollX = _container.MeasuredWidth - _hScrollView.MeasuredWidth - _hScrollView.ScrollX; } else { Device.BeginInvokeOnMainThread(() => UpdateScrollPosition(_hScrollView.ScrollX, ScrollY)); } } _checkedForRtlScroll = true; }
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)); 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); } }