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));
                }
            }
        }
Exemple #2
0
        /// <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);
        }
Exemple #3
0
        private void ApplyAcrylicBlur(AcrylicState state)
        {
            ApplyBackground(state);

            EnableBlur(state);

            UpdateProperties(state);
        }
Exemple #4
0
        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);
        }
Exemple #7
0
        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;
        }
Exemple #12
0
 private void UpdateProperties(AcrylicState state)
 {
     UpdateCornerRadius();
     UpdateTint(state);
 }
Exemple #13
0
        /// <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);
            }
        }