/// <summary> /// Updates or creates a sublayer to render a border-like shape. /// </summary> /// <param name="owner">The parent layer to apply the shape</param> /// <param name="area">The rendering area</param> /// <param name="background">The background brush</param> /// <param name="borderThickness">The border thickness</param> /// <param name="borderBrush">The border brush</param> /// <param name="cornerRadius">The corner radius</param> /// <param name="backgroundImage">The background image in case of a ImageBrush background</param> public void UpdateLayer( FrameworkElement owner, Brush background, Thickness borderThickness, Brush borderBrush, CornerRadius cornerRadius, object backgroundImage ) { // Bounds is captured to avoid calling twice calls below. var area = new Rect(0, 0, owner.ActualWidth, owner.ActualHeight); var newState = new LayoutState(area, background, borderThickness, borderBrush, cornerRadius, backgroundImage); var previousLayoutState = _currentState; if (!newState.Equals(previousLayoutState)) { if ( background != null || cornerRadius != CornerRadius.None || (borderThickness != Thickness.Empty && borderBrush != null) ) { _layerDisposable.Disposable = null; _layerDisposable.Disposable = InnerCreateLayer(owner, newState); } else { _layerDisposable.Disposable = null; } _currentState = newState; } }
/// <summary> /// Updates or creates a sublayer to render a border-like shape. /// </summary> /// <param name="view">The view to which we should add the layers</param> /// <param name="background">The background brush of the border</param> /// <param name="borderThickness">The border thickness</param> /// <param name="borderBrush">The border brush</param> /// <param name="cornerRadius">The corner radius</param> /// <param name="padding">The padding to apply on the content</param> public void UpdateLayer( FrameworkElement view, Brush background, Thickness borderThickness, Brush borderBrush, CornerRadius cornerRadius, Thickness padding, bool willUpdateMeasures = false ) { // This is required because android Height and Width are hidden by Control. var baseView = view as View; var logicalDrawArea = view.LayoutSlot; // Set origin to 0, because drawArea should be in the coordinates of the view itself logicalDrawArea.X = 0; logicalDrawArea.Y = 0; var drawArea = logicalDrawArea.LogicalToPhysicalPixels(); var newState = new LayoutState(drawArea, background, borderThickness, borderBrush, cornerRadius, padding); var previousLayoutState = _currentState; if (!newState.Equals(previousLayoutState)) { bool imageHasChanged = newState.BackgroundImageSource != previousLayoutState?.BackgroundImageSource; bool shouldDisposeEagerly = imageHasChanged || newState.BackgroundImageSource == null; if (shouldDisposeEagerly) { // Clear previous value anyway in order to make sure the previous values are unset before the new ones. // This prevents the case where a second update would set a new background and then set the background to null when disposing the previous. _layerDisposable.Disposable = null; } Action onImageSet = null; var disposable = InnerCreateLayers(view, drawArea, background, borderThickness, borderBrush, cornerRadius, () => onImageSet?.Invoke()); // Most of the time we immediately dispose the previous layer. In the case where we're using an ImageBrush, // and the backing image hasn't changed, we dispose the previous layer at the moment the new background is applied, // to prevent a visible flicker. if (shouldDisposeEagerly) { _layerDisposable.Disposable = disposable; } else { onImageSet = () => _layerDisposable.Disposable = disposable; } if (willUpdateMeasures) { view.RequestLayout(); } else { view.Invalidate(); } _currentState = newState; } }
/// <summary> /// Updates or creates a sublayer to render a border-like shape. /// </summary> /// <param name="owner">The parent layer to apply the shape</param> /// <param name="area">The rendering area</param> /// <param name="background">The background brush</param> /// <param name="borderThickness">The border thickness</param> /// <param name="borderBrush">The border brush</param> /// <param name="cornerRadius">The corner radius</param> /// <param name="backgroundImage">The background image in case of a ImageBrush background</param> public void UpdateLayer( UIView owner, Brush background, Thickness borderThickness, Brush borderBrush, CornerRadius cornerRadius, UIImage backgroundImage ) { // Frame is captured to avoid calling twice calls below. var frame = owner.Frame; var area = new CGRect(0, 0, frame.Width, frame.Height); var newState = new LayoutState(area, background, borderThickness, borderBrush, cornerRadius, backgroundImage); var previousLayoutState = _currentState; if (!newState.Equals(previousLayoutState)) { if ( background != null || (borderThickness != Thickness.Empty && borderBrush != null) ) { _layerDisposable.Disposable = null; _layerDisposable.Disposable = InnerCreateLayer(owner.Layer, area, background, borderThickness, borderBrush, cornerRadius); } else { _layerDisposable.Disposable = null; } _currentState = newState; } }
/// <summary> /// Updates or creates a sublayer to render a border-like shape. /// </summary> /// <param name="owner">The parent layer to apply the shape</param> /// <param name="area">The rendering area</param> /// <param name="background">The background brush</param> /// <param name="borderThickness">The border thickness</param> /// <param name="borderBrush">The border brush</param> /// <param name="cornerRadius">The corner radius</param> /// <param name="backgroundImage">The background image in case of a ImageBrush background</param> /// <returns>An updated BoundsPath if the layer has been created or updated; null if there is no change.</returns> public CGPath UpdateLayer( _View owner, Brush background, BackgroundSizing backgroundSizing, Thickness borderThickness, Brush borderBrush, CornerRadius cornerRadius, _Image backgroundImage) { // Bounds is captured to avoid calling twice calls below. var bounds = owner.Bounds; var area = new CGRect(0, 0, bounds.Width, bounds.Height); var newState = new LayoutState(area, background, backgroundSizing, borderThickness, borderBrush, cornerRadius, backgroundImage); var previousLayoutState = _currentState; if (!newState.Equals(previousLayoutState)) { #if __MACOS__ owner.WantsLayer = true; #endif _layerDisposable.Disposable = null; _layerDisposable.Disposable = InnerCreateLayer(owner as UIElement, owner.Layer, newState); _currentState = newState; } return(newState.BoundsPath); }
/// <summary> /// Updates or creates a sublayer to render a border-like shape. /// </summary> /// <param name="view">The view to which we should add the layers</param> /// <param name="background">The background brush of the border</param> /// <param name="borderThickness">The border thickness</param> /// <param name="borderBrush">The border brush</param> /// <param name="cornerRadius">The corner radius</param> /// <param name="padding">The padding to apply on the content</param> public void UpdateLayers( FrameworkElement view, Brush background, Thickness borderThickness, Brush borderBrush, CornerRadius cornerRadius, Thickness padding ) { // This is required because android Height and Width are hidden by Control. var baseView = view as View; Size targetSize = new Size(baseView.Width, baseView.Height); var drawArea = new Windows.Foundation.Rect(0, 0, targetSize.Width, targetSize.Height); var newState = new LayoutState(drawArea, background, borderThickness, borderBrush, cornerRadius, padding); var previousLayoutState = _currentState; if (!newState.Equals(previousLayoutState)) { bool imageHasChanged = newState.BackgroundImageSource != previousLayoutState?.BackgroundImageSource; bool shouldDisposeEagerly = imageHasChanged || newState.BackgroundImageSource == null; if (shouldDisposeEagerly) { // Clear previous value anyway in order to make sure the previous values are unset before the new ones. // This prevents the case where a second update would set a new background and then set the background to null when disposing the previous. _layerDisposable.Disposable = null; } if ( background != null || (borderThickness != Thickness.Empty && borderBrush != null) ) { Action onImageSet = null; var disposable = InnerCreateLayers(view, drawArea, background, borderThickness, borderBrush, cornerRadius, () => onImageSet?.Invoke()); // Most of the time we immediately dispose the previous layer. In the case where we're using an ImageBrush, // and the backing image hasn't changed, we dispose the previous layer at the moment the new background is applied, // to prevent a visible flicker. if (shouldDisposeEagerly) { _layerDisposable.Disposable = disposable; } else { onImageSet = () => _layerDisposable.Disposable = disposable; } } view.Invalidate(); _currentState = newState; } }
/// <summary> /// Updates or creates a sublayer to render a border-like shape. /// </summary> /// <param name="owner">The parent layer to apply the shape</param> /// <param name="area">The rendering area</param> /// <param name="background">The background brush</param> /// <param name="borderThickness">The border thickness</param> /// <param name="borderBrush">The border brush</param> /// <param name="cornerRadius">The corner radius</param> /// <param name="backgroundImage">The background image in case of a ImageBrush background</param> public void UpdateLayer( _View owner, Brush background, Thickness borderThickness, Brush borderBrush, CornerRadius cornerRadius, _Image backgroundImage ) { // Bounds is captured to avoid calling twice calls below. var bounds = owner.Bounds; var area = new CGRect(0, 0, bounds.Width, bounds.Height); var newState = new LayoutState(area, background, borderThickness, borderBrush, cornerRadius, backgroundImage); var previousLayoutState = _currentState; if (!newState.Equals(previousLayoutState)) { if ( background != null || (borderThickness != Thickness.Empty && borderBrush != null) ) { #if __MACOS__ owner.WantsLayer = true; #endif _layerDisposable.Disposable = null; _layerDisposable.Disposable = InnerCreateLayer(owner.Layer, area, background, borderThickness, borderBrush, cornerRadius); } else { _layerDisposable.Disposable = null; } _currentState = newState; } }