protected override void OnDraw(ACanvas canvas) { if (Element == null) { return; } var control = (PancakeView)Element; SetClipChildren(true); //Create path to clip the child if (control.Sides != 4) { using (var path = PolygonUtils.GetPolygonCornerPath(Width, Height, control.Sides, control.CornerRadius.TopLeft, control.OffsetAngle)) { canvas.Save(); canvas.ClipPath(path); } } else { using (var path = new Path()) { path.AddRoundRect(new RectF(0, 0, Width, Height), GetRadii(control), Path.Direction.Ccw); canvas.Save(); canvas.ClipPath(path); } } DrawBorder(canvas, control); }
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); if (hexPath.IsConvex) { outline.SetConvexPath(hexPath); } return; } // 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)); }
protected override bool DrawChild(ACanvas canvas, global::Android.Views.View child, long drawingTime) { if (Element == null) { return(false); } var control = (PancakeView)Element; SetClipChildren(true); //Create path to clip the child if (control.Sides != 4) { using (var path = PolygonUtils.GetPolygonCornerPath(Width, Height, control.Sides, control.CornerRadius.TopLeft, control.OffsetAngle)) { canvas.Save(); canvas.ClipPath(path); } } else { using (var path = new Path()) { path.AddRoundRect(new RectF(0, 0, Width, Height), GetRadii(control), Path.Direction.Ccw); canvas.Save(); canvas.ClipPath(path); } } // Draw the child first so that the border shows up above it. var result = base.DrawChild(canvas, child, drawingTime); canvas.Restore(); DrawBorder(canvas, control); return(result); }
void DrawBackground(ACanvas canvas, int width, int height, CornerRadius cornerRadius, bool pressed) { using (var paint = new Paint { AntiAlias = true }) using (Path.Direction direction = Path.Direction.Cw) using (Paint.Style style = Paint.Style.Fill) { var path = new Path(); if (_pancake.Sides != 4) { path = PolygonUtils.GetPolygonCornerPath(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); } } } if ((_pancake.BackgroundGradientStartColor != default(Color) && _pancake.BackgroundGradientEndColor != default(Color)) || (_pancake.BackgroundGradientStops != null && _pancake.BackgroundGradientStops.Any())) { var angle = _pancake.BackgroundGradientAngle / 360.0; // Calculate the new positions based on angle between 0-360. var a = width * Math.Pow(Math.Sin(2 * Math.PI * ((angle + 0.75) / 2)), 2); var b = height * Math.Pow(Math.Sin(2 * Math.PI * ((angle + 0.0) / 2)), 2); var c = width * Math.Pow(Math.Sin(2 * Math.PI * ((angle + 0.25) / 2)), 2); var d = height * Math.Pow(Math.Sin(2 * Math.PI * ((angle + 0.5) / 2)), 2); if (_pancake.BackgroundGradientStops != null) { // A range of colors is given. Let's add them. var orderedStops = _pancake.BackgroundGradientStops.OrderBy(x => x.Offset).ToList(); var colors = orderedStops.Select(x => x.Color.ToAndroid().ToArgb()).ToArray(); var locations = orderedStops.Select(x => x.Offset).ToArray(); var shader = new LinearGradient(width - (float)a, (float)b, width - (float)c, (float)d, colors, locations, Shader.TileMode.Clamp); paint.SetShader(shader); } else { // Only two colors provided, use that. var shader = new LinearGradient(width - (float)a, (float)b, width - (float)c, (float)d, _pancake.BackgroundGradientStartColor.ToAndroid(), _pancake.BackgroundGradientEndColor.ToAndroid(), Shader.TileMode.Clamp); paint.SetShader(shader); } } else { global::Android.Graphics.Color color = _pancake.BackgroundColor.ToAndroid(); paint.SetStyle(style); paint.Color = color; } canvas.DrawPath(path, paint); } }
private void DrawBorder(ACanvas canvas, PancakeView control) { if (control.BorderThickness > 0) { var borderThickness = Context.ToPixels(control.BorderThickness); var halfBorderThickness = borderThickness / 2; bool hasShadowOrElevation = control.HasShadow || control.Elevation > 0; // TODO: This doesn't look entirely right yet when using it with rounded corners. using (var paint = new Paint { AntiAlias = true }) using (Path.Direction direction = Path.Direction.Cw) using (Paint.Style style = Paint.Style.Stroke) using (var rect = new RectF(control.BorderDrawingStyle == BorderDrawingStyle.Outside && !hasShadowOrElevation ? -halfBorderThickness : halfBorderThickness, control.BorderDrawingStyle == BorderDrawingStyle.Outside && !hasShadowOrElevation ? -halfBorderThickness : halfBorderThickness, control.BorderDrawingStyle == BorderDrawingStyle.Outside && !hasShadowOrElevation ? canvas.Width + halfBorderThickness : canvas.Width - halfBorderThickness, control.BorderDrawingStyle == BorderDrawingStyle.Outside && !hasShadowOrElevation ? canvas.Height + halfBorderThickness : canvas.Height - halfBorderThickness)) { Path path = null; if (control.Sides != 4) { path = PolygonUtils.GetPolygonCornerPath(Width, Height, control.Sides, control.CornerRadius.TopLeft, control.OffsetAngle); } else { path = new Path(); path.AddRoundRect(rect, GetRadii(control), direction); } if (control.BorderIsDashed) { // dashes merge when thickness is increased // off-distance should be scaled according to thickness paint.SetPathEffect(new DashPathEffect(new float[] { 10, 5 * control.BorderThickness }, 0)); } if ((control.BorderGradientStartColor != default(Color) && control.BorderGradientEndColor != default(Color)) || (control.BorderGradientStops != null && control.BorderGradientStops.Any())) { var angle = control.BorderGradientAngle / 360.0; // Calculate the new positions based on angle between 0-360. var a = canvas.Width * Math.Pow(Math.Sin(2 * Math.PI * ((angle + 0.75) / 2)), 2); var b = canvas.Height * Math.Pow(Math.Sin(2 * Math.PI * ((angle + 0.0) / 2)), 2); var c = canvas.Width * Math.Pow(Math.Sin(2 * Math.PI * ((angle + 0.25) / 2)), 2); var d = canvas.Height * Math.Pow(Math.Sin(2 * Math.PI * ((angle + 0.5) / 2)), 2); if (control.BorderGradientStops != null) { // A range of colors is given. Let's add them. var orderedStops = control.BorderGradientStops.OrderBy(x => x.Offset).ToList(); var colors = orderedStops.Select(x => x.Color.ToAndroid().ToArgb()).ToArray(); var locations = orderedStops.Select(x => x.Offset).ToArray(); var shader = new LinearGradient(canvas.Width - (float)a, (float)b, canvas.Width - (float)c, (float)d, colors, locations, Shader.TileMode.Clamp); paint.SetShader(shader); } else { // Only two colors provided, use that. var shader = new LinearGradient(canvas.Width - (float)a, (float)b, canvas.Width - (float)c, (float)d, control.BorderGradientStartColor.ToAndroid(), control.BorderGradientEndColor.ToAndroid(), Shader.TileMode.Clamp); paint.SetShader(shader); } } else { paint.Color = control.BorderColor.ToAndroid(); } paint.StrokeCap = Paint.Cap.Square; paint.StrokeWidth = borderThickness; paint.SetStyle(style); canvas.DrawPath(path, paint); } } }