示例#1
0
        private static IDisposable InnerCreateLayers(BindableView view,
                                                     Windows.Foundation.Rect drawArea,
                                                     Brush background,
                                                     Thickness borderThickness,
                                                     Brush borderBrush,
                                                     CornerRadius cornerRadius,
                                                     Action onImageSet
                                                     )
        {
            var disposables = new CompositeDisposable();

            var physicalBorderThickness = borderThickness.LogicalToPhysicalPixels();

            if (cornerRadius != 0)
            {
                if (view is UIElement uiElement && uiElement.FrameRoundingAdjustment is { } fra)
                {
                    drawArea.Height += fra.Height;
                    drawArea.Width  += fra.Width;
                }

                var adjustedArea = drawArea.DeflateBy(physicalBorderThickness);

                using (var backgroundPath = cornerRadius.GetOutlinePath(adjustedArea.ToRectF()))
                {
                    //We only need to set a background if the drawArea is non-zero
                    if (!drawArea.HasZeroArea())
                    {
                        if (background is ImageBrush imageBrushBackground)
                        {
                            //Copy the path because it will be disposed when we exit the using block
                            var pathCopy      = new Path(backgroundPath);
                            var setBackground = DispatchSetImageBrushAsBackground(view, imageBrushBackground, drawArea, onImageSet, pathCopy);
                            disposables.Add(setBackground);
                        }
                        else if (background is AcrylicBrush acrylicBrush)
                        {
                            var apply = acrylicBrush.Subscribe(view, drawArea, backgroundPath);
                            disposables.Add(apply);
                        }
                        else
                        {
                            var fillPaint = background?.GetFillPaint(drawArea) ?? new Paint()
                            {
                                Color = Android.Graphics.Color.Transparent
                            };
                            ExecuteWithNoRelayout(view, v => v.SetBackgroundDrawable(Brush.GetBackgroundDrawable(background, drawArea, fillPaint, backgroundPath)));
                        }
                        disposables.Add(() => ExecuteWithNoRelayout(view, v => v.SetBackgroundDrawable(null)));
                    }

                    if (borderThickness != Thickness.Empty && borderBrush != null && !(borderBrush is ImageBrush))
                    {
                        using (var strokePaint = new Paint(borderBrush.GetStrokePaint(drawArea)))
                        {
                            //Create the path for the outer and inner rectangles that will become our border shape
                            var borderPath = cornerRadius.GetOutlinePath(drawArea.ToRectF());
                            borderPath.AddRoundRect(adjustedArea.ToRectF(), cornerRadius.GetRadii(), Path.Direction.Ccw);

                            var overlay = GetOverlayDrawable(
                                strokePaint,
                                physicalBorderThickness,
                                new global::System.Drawing.Size((int)drawArea.Width, (int)drawArea.Height),
                                borderPath);

                            if (overlay != null)
                            {
                                overlay.SetBounds(0, 0, view.Width, view.Height);
                                SetOverlay(view, disposables, overlay);
                            }
                        }
                    }
                }
            }
            else             // No corner radius
            {
                //We only need to set a background if the drawArea is non-zero
                if (!drawArea.HasZeroArea())
                {
                    if (background is ImageBrush imageBrushBackground)
                    {
                        var setBackground = DispatchSetImageBrushAsBackground(view, imageBrushBackground, drawArea, onImageSet);
                        disposables.Add(setBackground);
                    }
                    else if (background is AcrylicBrush acrylicBrush)
                    {
                        var apply = acrylicBrush.Subscribe(view, drawArea, maskingPath: null);
                        disposables.Add(apply);
                    }
                    else
                    {
                        var fillPaint = background?.GetFillPaint(drawArea) ?? new Paint()
                        {
                            Color = Android.Graphics.Color.Transparent
                        };
                        ExecuteWithNoRelayout(view, v => v.SetBackgroundDrawable(Brush.GetBackgroundDrawable(background, drawArea, fillPaint)));
                    }
                    disposables.Add(() => ExecuteWithNoRelayout(view, v => v.SetBackgroundDrawable(null)));
                }
            }

            if (borderBrush != null && !(borderBrush is ImageBrush))
            {
                //TODO: Handle case that BorderBrush is an ImageBrush
                using (var strokePaint = borderBrush.GetStrokePaint(drawArea))
                {
                    var overlay = GetOverlayDrawable(strokePaint, physicalBorderThickness, new global::System.Drawing.Size(view.Width, view.Height));

                    if (overlay != null)
                    {
                        overlay.SetBounds(0, 0, view.Width, view.Height);
                        SetOverlay(view, disposables, overlay);
                    }
                }
            }

            return(disposables);
        }
        private static IDisposable InnerCreateLayers(BindableView view,
                                                     Windows.Foundation.Rect drawArea,
                                                     Brush background,
                                                     Thickness borderThickness,
                                                     Brush borderBrush,
                                                     CornerRadius cornerRadius,
                                                     Action onImageSet
                                                     )
        {
            var disposables = new CompositeDisposable();

            var physicalBorderThickness = borderThickness.LogicalToPhysicalPixels();

            if (cornerRadius != 0)
            {
                var adjustedLineWidth = physicalBorderThickness.Top;                 // TODO: handle non-uniform BorderThickness correctly
                var adjustedArea      = drawArea;
                adjustedArea.Inflate(-adjustedLineWidth / 2, -adjustedLineWidth / 2);
                using (var path = cornerRadius.GetOutlinePath(adjustedArea.ToRectF()))
                {
                    path.SetFillType(Path.FillType.EvenOdd);

                    //We only need to set a background if the drawArea is non-zero
                    if (!drawArea.HasZeroArea())
                    {
                        if (background is ImageBrush imageBrushBackground)
                        {
                            //Copy the path because it will be disposed when we exit the using block
                            var pathCopy      = new Path(path);
                            var setBackground = DispatchSetImageBrushAsBackground(view, imageBrushBackground, drawArea, onImageSet, pathCopy);
                            disposables.Add(setBackground);
                        }
                        else if (background is AcrylicBrush acrylicBrush)
                        {
                            var apply = acrylicBrush.Subscribe(view, drawArea, path);
                            disposables.Add(apply);
                        }
                        else
                        {
                            var fillPaint = background?.GetFillPaint(drawArea) ?? new Paint()
                            {
                                Color = Android.Graphics.Color.Transparent
                            };
                            ExecuteWithNoRelayout(view, v => v.SetBackgroundDrawable(Brush.GetBackgroundDrawable(background, drawArea, fillPaint, path)));
                        }
                        disposables.Add(() => ExecuteWithNoRelayout(view, v => v.SetBackgroundDrawable(null)));
                    }

                    if (borderThickness != Thickness.Empty && borderBrush != null && !(borderBrush is ImageBrush))
                    {
                        using (var strokePaint = new Paint(borderBrush.GetStrokePaint(drawArea)))
                        {
                            var overlay = GetOverlayDrawable(strokePaint, physicalBorderThickness, new global::System.Drawing.Size((int)drawArea.Width, (int)drawArea.Height), path);

                            if (overlay != null)
                            {
                                overlay.SetBounds(0, 0, view.Width, view.Height);
                                SetOverlay(view, disposables, overlay);
                            }
                        }
                    }
                }
            }
            else             // No corner radius
            {
                //We only need to set a background if the drawArea is non-zero
                if (!drawArea.HasZeroArea())
                {
                    if (background is ImageBrush imageBrushBackground)
                    {
                        var setBackground = DispatchSetImageBrushAsBackground(view, imageBrushBackground, drawArea, onImageSet);
                        disposables.Add(setBackground);
                    }
                    else if (background is AcrylicBrush acrylicBrush)
                    {
                        var apply = acrylicBrush.Subscribe(view, drawArea, maskingPath: null);
                        disposables.Add(apply);
                    }
                    else
                    {
                        var fillPaint = background?.GetFillPaint(drawArea) ?? new Paint()
                        {
                            Color = Android.Graphics.Color.Transparent
                        };
                        ExecuteWithNoRelayout(view, v => v.SetBackgroundDrawable(Brush.GetBackgroundDrawable(background, drawArea, fillPaint)));
                    }
                    disposables.Add(() => ExecuteWithNoRelayout(view, v => v.SetBackgroundDrawable(null)));
                }

                if (borderBrush != null && !(borderBrush is ImageBrush))
                {
                    //TODO: Handle case that BorderBrush is an ImageBrush
                    using (var strokePaint = borderBrush.GetStrokePaint(drawArea))
                    {
                        var overlay = GetOverlayDrawable(strokePaint, physicalBorderThickness, new global::System.Drawing.Size(view.Width, view.Height));

                        if (overlay != null)
                        {
                            overlay.SetBounds(0, 0, view.Width, view.Height);
                            SetOverlay(view, disposables, overlay);
                        }
                    }
                }
            }

            return(disposables);
        }
示例#3
0
        private static IDisposable InnerCreateLayers(BindableView view,
                                                     Windows.Foundation.Rect drawArea,
                                                     Brush background,
                                                     Thickness borderThickness,
                                                     Brush borderBrush,
                                                     CornerRadius cornerRadius,
                                                     Action onImageSet
                                                     )
        {
            var disposables = new CompositeDisposable();

            var physicalBorderThickness = borderThickness.LogicalToPhysicalPixels();

            if (cornerRadius != 0)
            {
                using (Path path = new Path())
                {
                    path.SetFillType(Path.FillType.EvenOdd);

                    var radius = new CornerRadius(
                        topLeft: ViewHelper.LogicalToPhysicalPixels(cornerRadius.TopLeft),
                        topRight: ViewHelper.LogicalToPhysicalPixels(cornerRadius.TopRight),
                        bottomRight: ViewHelper.LogicalToPhysicalPixels(cornerRadius.BottomRight),
                        bottomLeft: ViewHelper.LogicalToPhysicalPixels(cornerRadius.BottomLeft)
                        );

                    var adjustedLineWidth = physicalBorderThickness.Top;

                    var area = new Windows.Foundation.Rect(drawArea.Left, drawArea.Top, drawArea.Width, drawArea.Height);
                    area.Inflate(-adjustedLineWidth / 2, -adjustedLineWidth / 2);

                    // This represents the doubled radii used to draw arcs, with each one maxed at the area's size.
                    // The width and height can vary for the same corner (elliptical arc)
                    var topLeftDiameterHeight     = Math.Min(radius.TopLeft * 2, area.Height);
                    var topLeftDiameterWidth      = Math.Min(radius.TopLeft * 2, area.Width);
                    var topRightDiameterHeight    = Math.Min(radius.TopRight * 2, area.Height);
                    var topRightDiameterWidth     = Math.Min(radius.TopRight * 2, area.Width);
                    var bottomLeftDiameterHeight  = Math.Min(radius.BottomLeft * 2, area.Height);
                    var bottomLeftDiameterWidth   = Math.Min(radius.BottomLeft * 2, area.Width);
                    var bottomRightDiameterHeight = Math.Min(radius.BottomRight * 2, area.Height);
                    var bottomRightDiameterWidth  = Math.Min(radius.BottomRight * 2, area.Width);

                    // Top line
                    path.MoveTo((float)(area.X + topLeftDiameterWidth / 2), (float)(area.Y));
                    path.LineTo((float)(area.Right - topRightDiameterWidth / 2), (float)(area.Y));

                    // Top right corner
                    path.ArcTo(
                        new RectF(
                            left: (float)(area.Right - topRightDiameterWidth),
                            top: (float)(area.Y),
                            bottom: (float)(area.Y + topRightDiameterHeight),
                            right: (float)(area.Right)
                            ),
                        startAngle: 270,
                        sweepAngle: 90
                        );

                    // Right line
                    path.LineTo((float)area.Right, (float)(area.Bottom - bottomRightDiameterHeight / 2));

                    // Bottom right corner
                    path.ArcTo(
                        new RectF(
                            left: (float)(area.Right - bottomRightDiameterWidth),
                            top: (float)(area.Bottom - bottomRightDiameterHeight),
                            bottom: (float)area.Bottom,
                            right: (float)area.Right
                            ),
                        startAngle: 0,
                        sweepAngle: 90
                        );

                    // Bottom line
                    path.LineTo((float)(area.X + bottomLeftDiameterWidth / 2), (float)area.Bottom);

                    // Bottom left corner
                    path.ArcTo(
                        new RectF(
                            left: (float)area.X,
                            top: (float)(area.Bottom - bottomLeftDiameterHeight),
                            bottom: (float)area.Bottom,
                            right: (float)(area.X + bottomLeftDiameterWidth)
                            ),
                        startAngle: 90,
                        sweepAngle: 90
                        );

                    // Left line
                    path.LineTo((float)area.X, (float)(area.Y + topLeftDiameterHeight / 2));

                    // Top left corner
                    path.ArcTo(
                        new RectF(
                            left: (float)area.X,
                            top: (float)area.Y,
                            bottom: (float)(area.Y + topLeftDiameterHeight),
                            right: (float)(area.X + topLeftDiameterWidth)
                            ),
                        startAngle: 180,
                        sweepAngle: 90
                        );

                    path.Close();

                    //We only need to set a background if the drawArea is non-zero
                    if (!drawArea.HasZeroArea())
                    {
                        var imageBrushBackground = background as ImageBrush;
                        if (imageBrushBackground != null)
                        {
                            //Copy the path because it will be disposed when we exit the using block
                            var pathCopy      = new Path(path);
                            var setBackground = DispatchSetImageBrushAsBackground(view, imageBrushBackground, drawArea, onImageSet, pathCopy);
                            disposables.Add(setBackground);
                        }
                        else
                        {
                            var fillPaint = background?.GetFillPaint(drawArea) ?? new Paint()
                            {
                                Color = Android.Graphics.Color.Transparent
                            };
                            ExecuteWithNoRelayout(view, v => v.SetBackgroundDrawable(GetBackgroundDrawable(background, drawArea, fillPaint, path)));
                        }
                        disposables.Add(() => ExecuteWithNoRelayout(view, v => v.SetBackgroundDrawable(null)));
                    }

                    if (borderThickness != Thickness.Empty && borderBrush != null && !(borderBrush is ImageBrush))
                    {
                        using (var strokePaint = new Paint(borderBrush.GetStrokePaint(drawArea)))
                        {
                            var overlay = GetOverlayDrawable(strokePaint, physicalBorderThickness, new Size((int)drawArea.Width, (int)drawArea.Height), path);

                            if (overlay != null)
                            {
                                overlay.SetBounds(0, 0, view.Width, view.Height);
                                SetOverlay(view, disposables, overlay);
                            }
                        }
                    }
                }
            }
            else             // No corner radius
            {
                //We only need to set a background if the drawArea is non-zero
                if (!drawArea.HasZeroArea())
                {
                    var imageBrushBackground = background as ImageBrush;
                    if (imageBrushBackground != null)
                    {
                        var setBackground = DispatchSetImageBrushAsBackground(view, imageBrushBackground, drawArea, onImageSet);
                        disposables.Add(setBackground);
                    }
                    else
                    {
                        var fillPaint = background?.GetFillPaint(drawArea) ?? new Paint()
                        {
                            Color = Android.Graphics.Color.Transparent
                        };
                        ExecuteWithNoRelayout(view, v => v.SetBackgroundDrawable(GetBackgroundDrawable(background, drawArea, fillPaint)));
                    }
                    disposables.Add(() => ExecuteWithNoRelayout(view, v => v.SetBackgroundDrawable(null)));
                }

                if (borderBrush != null && !(borderBrush is ImageBrush))
                {
                    //TODO: Handle case that BorderBrush is an ImageBrush
                    using (var strokePaint = borderBrush.GetStrokePaint(drawArea))
                    {
                        var overlay = GetOverlayDrawable(strokePaint, physicalBorderThickness, new Size(view.Width, view.Height));

                        if (overlay != null)
                        {
                            overlay.SetBounds(0, 0, view.Width, view.Height);
                            SetOverlay(view, disposables, overlay);
                        }
                    }
                }
            }

            return(disposables);
        }