public void UpdateMarkerLayout() { var view = Element; var _context = Context; var headlessOffset = CompressedLayout.GetHeadlessOffset(view); var x = (int)_context.ToPixels(view.X + headlessOffset.X); var y = (int)_context.ToPixels(view.Y + headlessOffset.Y); var size = view.Measure(double.PositiveInfinity, double.PositiveInfinity, MeasureFlags.IncludeMargins); var width = Math.Max(0, (int)_context.ToPixels(size.Request.Width)); var height = Math.Max(0, (int)_context.ToPixels(size.Request.Height)); Measure(MeasureSpec.MakeMeasureSpec(width, Android.Views.MeasureSpecMode.Unspecified), MeasureSpec.MakeMeasureSpec(height, Android.Views.MeasureSpecMode.Unspecified)); Layout(x, y, x + width, y + height); }
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 && 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"); } // 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(); }
public void UpdateLayout() { var reference = Guid.NewGuid().ToString(); Performance.Start(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 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)Build.VERSION.SdkInt >= 18) { UpdateClipToBounds(); } Performance.Stop(reference); //On Width or Height changes, the anchors needs to be updated UpdateAnchorX(); UpdateAnchorY(); }
public void UpdateLayout() { var reference = Guid.NewGuid().ToString(); Performance.Start(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 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"); } Performance.Stop(reference); //On Width or Height changes, the anchors needs to be updated UpdateAnchorX(); UpdateAnchorY(); }
void OnUpdateNativeControl(CALayer caLayer) { var view = Renderer.Element; var uiview = Renderer.NativeView; if (view == null || view.Batched) { return; } bool shouldInteract; if (view is Layout layout) { if (layout.InputTransparent) { shouldInteract = !layout.CascadeInputTransparent; } else { shouldInteract = layout.IsEnabled; } } else { shouldInteract = !view.InputTransparent && view.IsEnabled; } if (_isInteractive != shouldInteract) { #if __MOBILE__ uiview.UserInteractionEnabled = shouldInteract; #endif _isInteractive = shouldInteract; } var boundsChanged = _lastBounds != view.Bounds && TrackFrame; #if !__MOBILE__ var viewParent = view.RealParent as VisualElement; var parentBoundsChanged = _lastParentBounds != (viewParent == null ? Rectangle.Zero : viewParent.Bounds); #else var thread = !boundsChanged && !caLayer.Frame.IsEmpty && Application.Current?.OnThisPlatform()?.GetHandleControlUpdatesOnMainThread() == false; #endif var anchorX = (float)view.AnchorX; var anchorY = (float)view.AnchorY; var translationX = (float)view.TranslationX; var translationY = (float)view.TranslationY; var rotationX = (float)view.RotationX; var rotationY = (float)view.RotationY; var rotation = (float)view.Rotation; var scale = (float)view.Scale; var scaleX = (float)view.ScaleX * scale; var scaleY = (float)view.ScaleY * scale; var width = (float)view.Width; var height = (float)view.Height; var x = (float)view.X + (float)CompressedLayout.GetHeadlessOffset(view).X; var y = (float)view.Y + (float)CompressedLayout.GetHeadlessOffset(view).Y; var opacity = (float)view.Opacity; var isVisible = view.IsVisible; var updateTarget = Interlocked.Increment(ref _updateCount); void update() { if (updateTarget != _updateCount) { return; } #if __MOBILE__ var visualElement = view; #endif var parent = view.RealParent; var shouldRelayoutSublayers = false; if (isVisible && caLayer.Hidden) { #if !__MOBILE__ uiview.Hidden = false; #endif caLayer.Hidden = false; if (!caLayer.Frame.IsEmpty) { shouldRelayoutSublayers = true; } } if (!isVisible && !caLayer.Hidden) { #if !__MOBILE__ uiview.Hidden = true; #endif caLayer.Hidden = true; shouldRelayoutSublayers = true; } // ripe for optimization var transform = CATransform3D.Identity; #if __MOBILE__ bool shouldUpdate = (!(visualElement is Page) || visualElement is ContentPage) && width > 0 && height > 0 && parent != null && boundsChanged; #else // We don't care if it's a page or not since bounds of the window can change // TODO: Find why it doesn't work to check if the parentsBounds changed and remove true; parentBoundsChanged = true; bool shouldUpdate = width > 0 && height > 0 && parent != null && (boundsChanged || parentBoundsChanged); #endif // Dont ever attempt to actually change the layout of a Page unless it is a ContentPage // iOS is a really big fan of you not actually modifying the View's of the UIViewControllers if (shouldUpdate && TrackFrame) { #if __MOBILE__ var target = new RectangleF(x, y, width, height); #else var visualParent = parent as VisualElement; float newY = visualParent == null ? y : Math.Max(0, (float)(visualParent.Height - y - view.Height)); var target = new RectangleF(x, newY, width, height); #endif // must reset transform prior to setting frame... caLayer.Transform = transform; uiview.Frame = target; if (shouldRelayoutSublayers) { caLayer.LayoutSublayers(); } } else if (width <= 0 || height <= 0) { //TODO: FInd why it doesn't work #if __MOBILE__ caLayer.Hidden = true; #endif return; } #if __MOBILE__ caLayer.AnchorPoint = new PointF(anchorX, anchorY); #else caLayer.AnchorPoint = new PointF(anchorX - 0.5f, anchorY - 0.5f); #endif caLayer.Opacity = opacity; const double epsilon = 0.001; // position is relative to anchor point if (Math.Abs(anchorX - .5) > epsilon) { transform = transform.Translate((anchorX - .5f) * width, 0, 0); } if (Math.Abs(anchorY - .5) > epsilon) { transform = transform.Translate(0, (anchorY - .5f) * height, 0); } if (Math.Abs(translationX) > epsilon || Math.Abs(translationY) > epsilon) { transform = transform.Translate(translationX, translationY, 0); } if (Math.Abs(scaleX - 1) > epsilon || Math.Abs(scaleY - 1) > epsilon) { transform = transform.Scale(scaleX, scaleY, scale); } // not just an optimization, iOS will not "pixel align" a view which has m34 set if (Math.Abs(rotationY % 180) > epsilon || Math.Abs(rotationX % 180) > epsilon) { transform.m34 = 1.0f / -400f; } if (Math.Abs(rotationX % 360) > epsilon) { transform = transform.Rotate(rotationX * (float)Math.PI / 180.0f, 1.0f, 0.0f, 0.0f); } if (Math.Abs(rotationY % 360) > epsilon) { transform = transform.Rotate(rotationY * (float)Math.PI / 180.0f, 0.0f, 1.0f, 0.0f); } transform = transform.Rotate(rotation * (float)Math.PI / 180.0f, 0.0f, 0.0f, 1.0f); if (Foundation.NSThread.IsMain) { caLayer.Transform = transform; return; } CoreFoundation.DispatchQueue.MainQueue.DispatchAsync(() => { caLayer.Transform = transform; }); } #if __MOBILE__ if (thread) { CADisplayLinkTicker.Default.Invoke(update); } else { update(); } #else update(); #endif _lastBounds = view.Bounds; #if !__MOBILE__ _lastParentBounds = viewParent?.Bounds ?? Rectangle.Zero; #endif }