Skip to content

Commit

Permalink
Merge pull request #56 from sthewissen/fix-shadows
Browse files Browse the repository at this point in the history
Fixes #42
  • Loading branch information
sthewissen authored Oct 6, 2019
2 parents 6a97d66 + ebce4a5 commit 1783d99
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -112,23 +112,29 @@ void DrawBackground(ACanvas canvas, int width, int height, CornerRadius cornerRa

if (_pancake.Sides != 4)
{
path = PolygonUtils.GetPolygonCornerPath(width, height, _pancake.Sides, _pancake.CornerRadius.TopLeft, _pancake.OffsetAngle);
path = ShapeUtils.CreatePolygonPath(width, height, _pancake.Sides, _pancake.CornerRadius.TopLeft, _pancake.OffsetAngle);
}
else
{

using (var rect = new RectF(0, 0, width, height))
{
float topLeft = _convertToPixels(cornerRadius.TopLeft);
float topRight = _convertToPixels(cornerRadius.TopRight);
float bottomRight = _convertToPixels(cornerRadius.BottomRight);
float bottomLeft = _convertToPixels(cornerRadius.BottomLeft);

if (!_pancake.HasShadow || _pancake.Elevation > 0)
path.AddRoundRect(rect, new float[] { topLeft, topLeft, topRight, topRight, bottomRight, bottomRight, bottomLeft, bottomLeft }, direction);
else
path.AddRoundRect(rect, new float[] { topLeft, topLeft, topLeft, topLeft, topLeft, topLeft, topLeft, topLeft }, direction);
}
float topLeft = _convertToPixels(cornerRadius.TopLeft);
float topRight = _convertToPixels(cornerRadius.TopRight);
float bottomRight = _convertToPixels(cornerRadius.BottomRight);
float bottomLeft = _convertToPixels(cornerRadius.BottomLeft);

path = ShapeUtils.CreateRoundedRectPath(width, height, topLeft, topRight, bottomRight, bottomLeft);

//using (var rect = new RectF(0, 0, width, height))
//{
// float topLeft = _convertToPixels(cornerRadius.TopLeft);
// float topRight = _convertToPixels(cornerRadius.TopRight);
// float bottomRight = _convertToPixels(cornerRadius.BottomRight);
// float bottomLeft = _convertToPixels(cornerRadius.BottomLeft);

// if (!_pancake.HasShadow || _pancake.Elevation > 0)
// path.AddRoundRect(rect, new float[] { topLeft, topLeft, topRight, topRight, bottomRight, bottomRight, bottomLeft, bottomLeft }, direction);
// else
// path.AddRoundRect(rect, new float[] { topLeft, topLeft, topLeft, topLeft, topLeft, topLeft, topLeft, topLeft }, direction);
//}
}

if ((_pancake.BackgroundGradientStartColor != default(Color) && _pancake.BackgroundGradientEndColor != default(Color)) || (_pancake.BackgroundGradientStops != null && _pancake.BackgroundGradientStops.Any()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,17 +99,14 @@ private void SetupShadow(PancakeView pancake)

if (hasShadowOrElevation)
{
if (pancake.Sides == 4 || (pancake.Sides != 4 && pancake.CornerRadius.TopLeft == 0))
{
// To have shadow show up, we need to clip. However, clipping means that individual corners are lost :(
this.OutlineProvider = new RoundedCornerOutlineProvider(pancake, Context.ToPixels);
this.ClipToOutline = true;
}
else
{
this.OutlineProvider = null;
this.ClipToOutline = false;
}
// To have shadow show up, we need to clip.
this.OutlineProvider = new RoundedCornerOutlineProvider(pancake, Context.ToPixels);
this.ClipToOutline = true;
}
else
{
this.OutlineProvider = null;
this.ClipToOutline = false;
}
}

Expand Down Expand Up @@ -171,18 +168,20 @@ protected override void OnDraw(ACanvas canvas)
//Create path to clip the child
if (control.Sides != 4)
{
using (var path = PolygonUtils.GetPolygonCornerPath(Width, Height, control.Sides, control.CornerRadius.TopLeft, control.OffsetAngle))
using (var path = ShapeUtils.CreatePolygonPath(Width, Height, control.Sides, control.CornerRadius.TopLeft, control.OffsetAngle))
{
canvas.Save();
canvas.ClipPath(path);
}
}
else
{
using (var path = new Path())
using (var path = ShapeUtils.CreateRoundedRectPath(Width, Height,
Context.ToPixels(control.CornerRadius.TopLeft),
Context.ToPixels(control.CornerRadius.TopRight),
Context.ToPixels(control.CornerRadius.BottomRight),
Context.ToPixels(control.CornerRadius.BottomLeft)))
{
path.AddRoundRect(new RectF(0, 0, Width, Height), GetRadii(control), Path.Direction.Ccw);

canvas.Save();
canvas.ClipPath(path);
}
Expand All @@ -202,18 +201,20 @@ protected override bool DrawChild(ACanvas canvas, global::Android.Views.View chi
//Create path to clip the child
if (control.Sides != 4)
{
using (var path = PolygonUtils.GetPolygonCornerPath(Width, Height, control.Sides, control.CornerRadius.TopLeft, control.OffsetAngle))
using (var path = ShapeUtils.CreatePolygonPath(Width, Height, control.Sides, control.CornerRadius.TopLeft, control.OffsetAngle))
{
canvas.Save();
canvas.ClipPath(path);
}
}
else
{
using (var path = new Path())
using (var path = ShapeUtils.CreateRoundedRectPath(Width, Height,
Context.ToPixels(control.CornerRadius.TopLeft),
Context.ToPixels(control.CornerRadius.TopRight),
Context.ToPixels(control.CornerRadius.BottomRight),
Context.ToPixels(control.CornerRadius.BottomLeft)))
{
path.AddRoundRect(new RectF(0, 0, Width, Height), GetRadii(control), Path.Direction.Ccw);

canvas.Save();
canvas.ClipPath(path);
}
Expand All @@ -228,23 +229,6 @@ protected override bool DrawChild(ACanvas canvas, global::Android.Views.View chi
return result;
}

private float[] GetRadii(PancakeView control)
{
float topLeft = Context.ToPixels(control.CornerRadius.TopLeft);
float topRight = Context.ToPixels(control.CornerRadius.TopRight);
float bottomRight = Context.ToPixels(control.CornerRadius.BottomRight);
float bottomLeft = Context.ToPixels(control.CornerRadius.BottomLeft);

var radii = new[] { topLeft, topLeft, topRight, topRight, bottomRight, bottomRight, bottomLeft, bottomLeft };

if (control.HasShadow || control.Elevation > 0)
{
radii = new[] { topLeft, topLeft, topLeft, topLeft, topLeft, topLeft, topLeft, topLeft };
}

return radii;
}

private void DrawBorder(ACanvas canvas, PancakeView control)
{
if (control.BorderThickness > 0)
Expand All @@ -265,12 +249,15 @@ private void DrawBorder(ACanvas canvas, PancakeView control)
Path path = null;
if (control.Sides != 4)
{
path = PolygonUtils.GetPolygonCornerPath(Width, Height, control.Sides, control.CornerRadius.TopLeft, control.OffsetAngle);
path = ShapeUtils.CreatePolygonPath(Width, Height, control.Sides, control.CornerRadius.TopLeft, control.OffsetAngle);
}
else
{
path = new Path();
path.AddRoundRect(rect, GetRadii(control), direction);
path = ShapeUtils.CreateRoundedRectPath(Width, Height,
Context.ToPixels(control.CornerRadius.TopLeft),
Context.ToPixels(control.CornerRadius.TopRight),
Context.ToPixels(control.CornerRadius.BottomRight),
Context.ToPixels(control.CornerRadius.BottomLeft));
}

if (control.BorderIsDashed)
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,32 @@ public RoundedCornerOutlineProvider(PancakeView pancake, Func<double, float> con
{
_pancake = pancake;
_convertToPixels = convertToPixels;

}

public override void GetOutline(global::Android.Views.View view, Outline outline)
{
if (_pancake.Sides != 4)
{
var cornerRadius = (view.Width / _pancake.Width) * _pancake.CornerRadius.TopLeft;
var hexPath = PolygonUtils.GetPolygonCornerPath(view.Width, view.Height, _pancake.Sides, cornerRadius, _pancake.OffsetAngle);
var hexPath = ShapeUtils.CreatePolygonPath(view.Width, view.Height, _pancake.Sides, _pancake.HasShadow ? 0 : _pancake.CornerRadius.TopLeft, _pancake.OffsetAngle);

if (hexPath.IsConvex)
{
outline.SetConvexPath(hexPath);
}

return;
}
else
{
var path = ShapeUtils.CreateRoundedRectPath(view.Width, view.Height,
_convertToPixels(_pancake.CornerRadius.TopLeft),
_convertToPixels(_pancake.CornerRadius.TopRight),
_convertToPixels(_pancake.CornerRadius.BottomRight),
_convertToPixels(_pancake.CornerRadius.BottomLeft));

// TODO: Figure out how to clip individual rounded corners with different radii.
outline.SetRoundRect(new Rect(0, 0, view.Width, view.Height), _convertToPixels(_pancake.CornerRadius.TopLeft));
if (path.IsConvex)
{
outline.SetConvexPath(path);
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System;
using Android.Graphics;

namespace Xamarin.Forms.PancakeView.Droid
{
public static class ShapeUtils
{
public static Path CreateRoundedRectPath(float rectWidth, float rectHeight, float topLeft, float topRight, float bottomRight, float bottomLeft)
{
var path = new Path();
var radii = new[] { topLeft, topLeft,
topRight, topRight,
bottomRight, bottomRight,
bottomLeft, bottomLeft };

path.AddRoundRect(new RectF(0, 0, rectWidth, rectHeight), radii, Path.Direction.Ccw);
path.Close();

return path;
}

public static Path CreatePolygonPath(double rectWidth, double rectHeight, int sides, double cornerRadius = 0.0, double rotationOffset = 0.0)
{
var offsetRadians = rotationOffset * Math.PI / 180;

var path = new Path();
var theta = 2 * Math.PI / sides;

// depends on the rotation
var width = (-cornerRadius + Math.Min(rectWidth, rectHeight)) / 2;
var center = new Point(rectWidth / 2, rectHeight / 2);

var radius = width + cornerRadius - (Math.Cos(theta) * cornerRadius) / 2;

var angle = offsetRadians;
var corner = new Point(center.X + (radius - cornerRadius) * Math.Cos(angle), center.Y + (radius - cornerRadius) * Math.Sin(angle));
path.MoveTo((float)(corner.X + cornerRadius * Math.Cos(angle + theta)), (float)(corner.Y + cornerRadius * Math.Sin(angle + theta)));

for (var i = 0; i < sides; i++)
{
angle += theta;
corner = new Point(center.X + (radius - cornerRadius) * Math.Cos(angle), center.Y + (radius - cornerRadius) * Math.Sin(angle));
var tip = new Point(center.X + radius * Math.Cos(angle), center.Y + radius * Math.Sin(angle));
var start = new Point(corner.X + cornerRadius * Math.Cos(angle - theta), corner.Y + cornerRadius * Math.Sin(angle - theta));
var end = new Point(corner.X + cornerRadius * Math.Cos(angle + theta), corner.Y + cornerRadius * Math.Sin(angle + theta));

path.LineTo(start.X, start.Y);
path.QuadTo(tip.X, tip.Y, end.X, end.Y);
}

path.Close();

return path;
}

public class Point
{
public float X { get; set; }
public float Y { get; set; }
public Point(double X, double Y)
{
this.X = (float)X;
this.Y = (float)Y;
}
}
}
}

0 comments on commit 1783d99

Please # to comment.