From ce21a7e7542ca2261ac19cd47d238fe5e1b8f8f2 Mon Sep 17 00:00:00 2001 From: chasakisd Date: Tue, 21 Jan 2020 15:10:23 +0200 Subject: [PATCH] Shape Support Circle --- .../OutlineProviders/PathOutlineProvider.cs | 2 +- .../PathProviders/BasePathProvider.cs | 6 ++ .../PathProviders/CirclePathProvider.cs | 25 +++++++ .../PathProviders/PathProvidersContainer.cs | 1 + .../Renderers/MaterialShapeManager.cs | 2 + .../XamarinBackgroundKit.Android.csproj | 1 + .../PathProviders/CirclePathProvider.cs | 59 +++++++++++++++++ .../PathProviders/PathProvidersContainer.cs | 1 + .../XamarinBackgroundKit.iOS.csproj | 1 + src/XamarinBackgroundKit/Shapes/Circle.cs | 4 ++ .../ShapeExplorerPage.xaml | 65 +++++++++++++++---- .../ShapeExplorerPage.xaml.cs | 3 + 12 files changed, 155 insertions(+), 15 deletions(-) create mode 100644 src/XamarinBackgroundKit.Android/PathProviders/CirclePathProvider.cs create mode 100644 src/XamarinBackgroundKit.iOS/PathProviders/CirclePathProvider.cs create mode 100644 src/XamarinBackgroundKit/Shapes/Circle.cs diff --git a/src/XamarinBackgroundKit.Android/OutlineProviders/PathOutlineProvider.cs b/src/XamarinBackgroundKit.Android/OutlineProviders/PathOutlineProvider.cs index e181861..2ed0a49 100644 --- a/src/XamarinBackgroundKit.Android/OutlineProviders/PathOutlineProvider.cs +++ b/src/XamarinBackgroundKit.Android/OutlineProviders/PathOutlineProvider.cs @@ -35,7 +35,7 @@ public override void GetOutline(View view, Outline outline) } var clipPath = pathProvider.CreatePath(view.Width, view.Height); - if (!clipPath.IsConvex) return; + if (clipPath == null || !clipPath.IsConvex) return; outline.SetConvexPath(clipPath); } diff --git a/src/XamarinBackgroundKit.Android/PathProviders/BasePathProvider.cs b/src/XamarinBackgroundKit.Android/PathProviders/BasePathProvider.cs index 22e5ba6..d63fbd2 100644 --- a/src/XamarinBackgroundKit.Android/PathProviders/BasePathProvider.cs +++ b/src/XamarinBackgroundKit.Android/PathProviders/BasePathProvider.cs @@ -36,6 +36,8 @@ public void Invalidate() public Path CreatePath(int width, int height) { + if (_disposed) return null; + /* If the path is not dirty return it */ if (!IsPathDirty || !(_shape is TShape tShape)) return Path; @@ -50,6 +52,8 @@ public Path CreatePath(int width, int height) public Path CreateBorderedPath(int width, int height) { + if (_disposed) return null; + /* If the path provider, does not support border, use the default */ if (!IsBorderSupported) return CreatePath(width, height); @@ -72,6 +76,8 @@ public Path CreateBorderedPath(int width, int height) public virtual void SetShape(IBackgroundShape shape) { + if (_disposed) return; + _shape = shape; Invalidate(); diff --git a/src/XamarinBackgroundKit.Android/PathProviders/CirclePathProvider.cs b/src/XamarinBackgroundKit.Android/PathProviders/CirclePathProvider.cs new file mode 100644 index 0000000..6ebdda7 --- /dev/null +++ b/src/XamarinBackgroundKit.Android/PathProviders/CirclePathProvider.cs @@ -0,0 +1,25 @@ +using System; +using Android.Graphics; +using XamarinBackgroundKit.Shapes; + +namespace XamarinBackgroundKit.Android.PathProviders +{ + public class CirclePathProvider : BasePathProvider + { + public override bool IsBorderSupported => true; + + public override void CreatePath(Path path, Circle shape, int width, int height) + { + var radius = Math.Min(width, height) / 2f; + + path.AddCircle(width / 2f, height / 2f, radius, Path.Direction.Ccw); + } + + public override void CreateBorderedPath(Path path, Circle shape, int width, int height, int strokeWidth) + { + var radius = (Math.Min(width, height) - strokeWidth) / 2f; + + path.AddCircle(width / 2f, height / 2f, radius, Path.Direction.Ccw); + } + } +} diff --git a/src/XamarinBackgroundKit.Android/PathProviders/PathProvidersContainer.cs b/src/XamarinBackgroundKit.Android/PathProviders/PathProvidersContainer.cs index c382ca9..4799a33 100644 --- a/src/XamarinBackgroundKit.Android/PathProviders/PathProvidersContainer.cs +++ b/src/XamarinBackgroundKit.Android/PathProviders/PathProvidersContainer.cs @@ -15,6 +15,7 @@ public static void Init() { Register(() => new ArcPathProvider()); Register(() => new RectPathProvider()); + Register(() => new CirclePathProvider()); Register(() => new DiagonalPathProvider()); Register(() => new TrianglePathProvider()); Register(() => new RoundRectPathProvider()); diff --git a/src/XamarinBackgroundKit.Android/Renderers/MaterialShapeManager.cs b/src/XamarinBackgroundKit.Android/Renderers/MaterialShapeManager.cs index 34bcf60..5d7fe02 100644 --- a/src/XamarinBackgroundKit.Android/Renderers/MaterialShapeManager.cs +++ b/src/XamarinBackgroundKit.Android/Renderers/MaterialShapeManager.cs @@ -19,6 +19,7 @@ public class MaterialShapeManager : IDisposable private Paint _maskPaint; private AView _nativeView; private IBackgroundShape _shape; + public IPathProvider PathProvider { get; private set; } public MaterialShapeManager() @@ -118,6 +119,7 @@ private void InitializeClipPath(int width, int height) /* Always prefer border path. If there is no need, the provider will return the default one */ var clipPath = PathProvider.CreateBorderedPath(width, height); + if (clipPath == null) return; _clipPath.Reset(); _clipPath.Set(clipPath); diff --git a/src/XamarinBackgroundKit.Android/XamarinBackgroundKit.Android.csproj b/src/XamarinBackgroundKit.Android/XamarinBackgroundKit.Android.csproj index ef46cdb..08a82f0 100644 --- a/src/XamarinBackgroundKit.Android/XamarinBackgroundKit.Android.csproj +++ b/src/XamarinBackgroundKit.Android/XamarinBackgroundKit.Android.csproj @@ -71,6 +71,7 @@ + diff --git a/src/XamarinBackgroundKit.iOS/PathProviders/CirclePathProvider.cs b/src/XamarinBackgroundKit.iOS/PathProviders/CirclePathProvider.cs new file mode 100644 index 0000000..f2e0ecf --- /dev/null +++ b/src/XamarinBackgroundKit.iOS/PathProviders/CirclePathProvider.cs @@ -0,0 +1,59 @@ +using System; +using CoreGraphics; +using UIKit; +using XamarinBackgroundKit.Shapes; + +namespace XamarinBackgroundKit.iOS.PathProviders +{ + public class CirclePathProvider : BasePathProvider + { + public override bool IsBorderSupported => true; + + public override void CreatePath(Circle shape, CGRect bounds) + { + using (var bezierPath = GetCirclePath(bounds)) + { + Path = bezierPath.CGPath; + } + } + + public override void CreateBorderedPath(Circle shape, CGRect bounds, double strokeWidth) + { + using (var bezierPath = GetCirclePath(bounds, (float)strokeWidth)) + { + BorderPath = bezierPath.CGPath; + } + } + + private static UIBezierPath GetCirclePath(CGRect bounds, float borderWidth = 0f) + { + var startX = bounds.Left; + var endX = bounds.Right; + var startY = bounds.Top; + var endY = bounds.Bottom; + + var delta = (float)Math.Abs(bounds.Width - bounds.Height) / 2f; + + if (bounds.Width > bounds.Height) + { + startX += delta; + endX -= 2 * delta; + } + else if (bounds.Width < bounds.Height) + { + startY += delta; + endY -= 2 * delta; + } + + var croppedBounds = new CGRect( + startX, startY, endX, endY); + + var strokedCroppedBounds = croppedBounds.Inset( + borderWidth, borderWidth); + + var radius = ((float)Math.Min(bounds.Width, bounds.Height) - borderWidth) / 2; + + return UIBezierPath.FromRoundedRect(strokedCroppedBounds, radius); + } + } +} diff --git a/src/XamarinBackgroundKit.iOS/PathProviders/PathProvidersContainer.cs b/src/XamarinBackgroundKit.iOS/PathProviders/PathProvidersContainer.cs index 91795a0..a94cd36 100644 --- a/src/XamarinBackgroundKit.iOS/PathProviders/PathProvidersContainer.cs +++ b/src/XamarinBackgroundKit.iOS/PathProviders/PathProvidersContainer.cs @@ -15,6 +15,7 @@ public static void Init() { Register(() => new ArcPathProvider()); Register(() => new RectPathProvider()); + Register(() => new CirclePathProvider()); Register(() => new DiagonalPathProvider()); Register(() => new TrianglePathProvider()); Register(() => new RoundRectPathProvider()); diff --git a/src/XamarinBackgroundKit.iOS/XamarinBackgroundKit.iOS.csproj b/src/XamarinBackgroundKit.iOS/XamarinBackgroundKit.iOS.csproj index c7c73f8..5be59fc 100644 --- a/src/XamarinBackgroundKit.iOS/XamarinBackgroundKit.iOS.csproj +++ b/src/XamarinBackgroundKit.iOS/XamarinBackgroundKit.iOS.csproj @@ -62,6 +62,7 @@ + diff --git a/src/XamarinBackgroundKit/Shapes/Circle.cs b/src/XamarinBackgroundKit/Shapes/Circle.cs new file mode 100644 index 0000000..69c5480 --- /dev/null +++ b/src/XamarinBackgroundKit/Shapes/Circle.cs @@ -0,0 +1,4 @@ +namespace XamarinBackgroundKit.Shapes +{ + public class Circle : BaseShape { } +} diff --git a/src/XamarinBackgroundKitSample/ShapeExplorerPage.xaml b/src/XamarinBackgroundKitSample/ShapeExplorerPage.xaml index 0b22a2b..d79eae3 100644 --- a/src/XamarinBackgroundKitSample/ShapeExplorerPage.xaml +++ b/src/XamarinBackgroundKitSample/ShapeExplorerPage.xaml @@ -9,6 +9,7 @@ Arc Rect + Circle RoundRect Diagonal Triangle @@ -120,21 +121,57 @@ - -