private void Apply(AcrylicState state) { if (AlwaysUseFallback || !SupportsBlur()) { state.BlurDisposable.Disposable = null; // Fall back to solid color var fillPaint = GetFillPaint(Rect.Empty); ExecuteWithNoRelayout(state.Owner, v => v.SetBackgroundDrawable(Brush.GetBackgroundDrawable(this, state.DrawArea, fillPaint, state.MaskingPath, antiAlias: false))); if (state.FallbackDisposable.Disposable == null) { state.FallbackDisposable.Disposable = Disposable.Create( () => ExecuteWithNoRelayout(state.Owner, v => v.SetBackgroundDrawable(null))); } } else { state.FallbackDisposable.Disposable = null; ApplyAcrylicBlur(state); if (state.BlurDisposable.Disposable == null) { state.BlurDisposable.Disposable = Disposable.Create( () => RemoveAcrylicBlur(state)); } } }
/// <summary> /// Subscribes to AcrylicBrush for a given UI element and applies it. /// </summary> /// <param name="uiElement">UI element.</param> /// <returns>Disposable.</returns> internal IDisposable Subscribe( UIElement owner, CGRect fullArea, CGRect insideArea, CALayer layer, List <CALayer> sublayers, ref int insertionIndex, CAShapeLayer fillMask) { var state = new AcrylicState( owner, fullArea, insideArea, layer, sublayers, insertionIndex++, // we always use a single layer for acrylic fillMask); var compositeDisposable = new CompositeDisposable(7); this.RegisterDisposablePropertyChangedCallback( AlwaysUseFallbackProperty, (_, __) => Apply(state)) .DisposeWith(compositeDisposable); this.RegisterDisposablePropertyChangedCallback( FallbackColorProperty, (_, __) => Apply(state)) .DisposeWith(compositeDisposable); this.RegisterDisposablePropertyChangedCallback( TintColorProperty, (_, __) => Apply(state)) .DisposeWith(compositeDisposable); this.RegisterDisposablePropertyChangedCallback( TintOpacityProperty, (_, __) => Apply(state)) .DisposeWith(compositeDisposable); this.RegisterDisposablePropertyChangedCallback( OpacityProperty, (_, __) => Apply(state)) .DisposeWith(compositeDisposable); #if __MACOS__ this.RegisterDisposablePropertyChangedCallback( BackgroundSourceProperty, (_, __) => Apply(state)) .DisposeWith(compositeDisposable); #endif Apply(state); Disposable.Create(() => state.ApplyDisposable.Disposable = null) .DisposeWith(compositeDisposable); return(compositeDisposable); }
private void ApplyAcrylicBlur(AcrylicState state) { ApplyBackground(state); EnableBlur(state); UpdateProperties(state); }
private void RemoveAcrylicBlur(AcrylicState state) { SetBackground(state.Owner, null); state.BackgroundDrawable?.Dispose(); state.BackgroundDrawable = null; DisableBlur(state); DestroyBlur(state); }
private void DestroyBlur(AcrylicState state) { if (!state.BlurView.IsNullOrDisposed()) { state.Owner.RemoveView(state.BlurView); } state.BlurView?.Destroy(); state.BlurView = null; }
private void UpdateTint(AcrylicState state, bool invalidate = true) { var tintColorWithOpacity = Color.FromArgb( (byte)(TintOpacity * TintColor.A), TintColor.R, TintColor.G, TintColor.B); Android.Graphics.Color tintColor = tintColorWithOpacity; state.BlurView?.SetOverlayColor(tintColor, invalidate); }
private void ApplyBackground(AcrylicState state) { if (state.BackgroundDrawable == null) { state.BackgroundDrawable = new GradientDrawable(); state.BackgroundDrawable.SetShape(ShapeType.Rectangle); Android.Graphics.Color androidColor = Colors.Transparent; state.BackgroundDrawable.SetColor(androidColor); SetBackground(state.Owner, state.BackgroundDrawable); } }
private void LayoutBlurView(AcrylicState state, ViewGroup view) { if (view.MeasuredWidth == 0 || view.MeasuredHeight == 0 || state.BlurView == null) { return; } int width = view.MeasuredWidth; int height = view.MeasuredHeight; state.BlurView.Measure(width, height); state.BlurView.Layout(0, 0, width, height); }
private void DisableBlur(AcrylicState state) { if (state.Owner.ChildCount == 0 || !ReferenceEquals(state.Owner.GetChildAt(0), state.BlurViewWrapper)) { return; } if (this.Log().IsEnabled(LogLevel.Information)) { this.Log().LogInformation("Renderer::DisableBlur() => removing pre draw listener"); } state.Owner.RemoveView(state.BlurViewWrapper); }
internal IDisposable Subscribe(BindableView owner, Rect drawArea, Path maskingPath) { var state = new AcrylicState(owner, drawArea, maskingPath); var compositeDisposable = new CompositeDisposable(6); this.RegisterDisposablePropertyChangedCallback( AlwaysUseFallbackProperty, (_, __) => Apply(state)) .DisposeWith(compositeDisposable); this.RegisterDisposablePropertyChangedCallback( FallbackColorProperty, (_, __) => Apply(state)) .DisposeWith(compositeDisposable); this.RegisterDisposablePropertyChangedCallback( TintColorProperty, (_, __) => Apply(state)) .DisposeWith(compositeDisposable); this.RegisterDisposablePropertyChangedCallback( TintOpacityProperty, (_, __) => Apply(state)) .DisposeWith(compositeDisposable); this.RegisterDisposablePropertyChangedCallback( OpacityProperty, (_, __) => Apply(state)) .DisposeWith(compositeDisposable); Apply(state); Disposable.Create(() => { state.FallbackDisposable.Disposable = null; state.BlurDisposable.Disposable = null; }).DisposeWith(compositeDisposable); return(compositeDisposable); }
private void EnableBlur(AcrylicState state) { if (this.Log().IsEnabled(LogLevel.Information)) { this.Log().LogInformation("Renderer::EnableBlur()"); } if (state.BlurView == null) { state.BlurView = new RealtimeBlurView(state.Owner.Context); } state.BlurView.SetBlurRadius(state.Owner.Context.ToPixels(AndroidBlurRadius)); UpdateTint(state); state.BlurView.SetDownsampleFactor(CurrentBlurRadius <= 10 ? 1 : 2); UpdateCornerRadius(); if (state.Owner.ChildCount > 0 && ReferenceEquals(state.Owner.GetChildAt(0), state.BlurViewWrapper)) { // Already added return; } if (this.Log().IsEnabled(LogLevel.Information)) { this.Log().LogInformation("Renderer::EnableBlur() => adding pre draw listener"); } var blurViewWrapper = new ContentPresenter() { Content = state.BlurView, HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch }; state.Owner.AddView(blurViewWrapper, 0); state.BlurViewWrapper = blurViewWrapper; }
private void UpdateProperties(AcrylicState state) { UpdateCornerRadius(); UpdateTint(state); }
/// <summary> /// Applies the current state of Acrylic brush to a given UIElement /// </summary> /// <param name="uiElement">UIElement to set background brush to.</param> private void Apply(AcrylicState acrylicState) { var compositeDisposable = new CompositeDisposable(); // Reset existing layers acrylicState.ApplyDisposable.Disposable = compositeDisposable; if (acrylicState.AcrylicContainerLayer == null) { // Initialize the container layer. // This is done only once and the layer is reused if brush // properties change. acrylicState.AcrylicContainerLayer = new CALayer { Frame = acrylicState.FullArea, Mask = acrylicState.FillMask, BackgroundColor = _Color.Clear.CGColor, MasksToBounds = true, }; acrylicState.Parent.InsertSublayer(acrylicState.AcrylicContainerLayer, acrylicState.InsertionIndex); acrylicState.Sublayers.Add(acrylicState.AcrylicContainerLayer); // The layer itself is removed automatically by the BorderLayoutRenderer } if (AlwaysUseFallback) { // Apply solid color only var previousColor = acrylicState.AcrylicContainerLayer.BackgroundColor; acrylicState.AcrylicContainerLayer.BackgroundColor = FallbackColorWithOpacity; Disposable.Create(() => acrylicState.AcrylicContainerLayer.BackgroundColor = previousColor) .DisposeWith(compositeDisposable); } else { acrylicState.AcrylicContainerLayer.BackgroundColor = _Color.Clear.CGColor; var acrylicFrame = new CGRect(new CGPoint(acrylicState.InsideArea.X, acrylicState.InsideArea.Y), acrylicState.InsideArea.Size); var acrylicLayer = new CALayer { Frame = acrylicFrame, MasksToBounds = true, Opacity = (float)TintOpacity, BackgroundColor = TintColor }; acrylicState.BlurViews = CreateBlurViews(acrylicFrame); InsertViewsAtStart(acrylicState.Owner, acrylicState.BlurViews); acrylicState.AcrylicContainerLayer.AddSublayer(acrylicLayer); Disposable.Create(() => { acrylicState.AcrylicContainerLayer.Sublayers[0].RemoveFromSuperLayer(); RemoveViews(acrylicState.Owner, acrylicState.BlurViews); acrylicState.BlurViews = null; }).DisposeWith(compositeDisposable); } }