private void DrawDefaultShadow(CALayer layer, CGRect bounds, nfloat cornerRadius) { var pancake = Element as PancakeView; // Ideally we want to be able to have individual corner radii + shadows // However, on iOS we can only do one radius + shadow. layer.CornerRadius = cornerRadius; layer.ShadowRadius = 10; layer.ShadowColor = UIColor.Black.CGColor; layer.ShadowOpacity = 0.4f; layer.ShadowOffset = new SizeF(); if (pancake.Sides != 4) { layer.ShadowPath = ShapeUtils.CreatePolygonPath(bounds, pancake.Sides, pancake.CornerRadius.TopLeft, pancake.OffsetAngle).CGPath; } else { layer.ShadowPath = ShapeUtils.CreateRoundedRectPath(bounds, pancake.CornerRadius).CGPath; } }
private void DrawElevation(CALayer layer, int elevation, CGRect bounds, nfloat cornerRadius) { // Source: https://medium.com/material-design-for-ios/part-1-elevation-e48ff795c693 var pancake = Element as PancakeView; layer.CornerRadius = cornerRadius; layer.ShadowRadius = elevation; layer.ShadowColor = UIColor.Black.CGColor; layer.ShadowOpacity = 0.24f; layer.ShadowOffset = new CGSize(0, elevation); if (pancake.Sides != 4) { layer.ShadowPath = ShapeUtils.CreatePolygonPath(bounds, pancake.Sides, pancake.CornerRadius.TopLeft, pancake.OffsetAngle).CGPath; } else { layer.ShadowPath = ShapeUtils.CreateRoundedRectPath(bounds, pancake.CornerRadius).CGPath; } layer.MasksToBounds = false; }
private void DrawBorder() { var pancake = Element as PancakeView; var layerName = "borderLayer"; // remove previous background layer if any var prevBorderLayer = _wrapperView.Layer.Sublayers?.FirstOrDefault(x => x.Name == layerName); prevBorderLayer?.RemoveFromSuperLayer(); if (pancake.BorderThickness > 0) { var borderLayer = new CAShapeLayer { StrokeColor = pancake.BorderColor == Xamarin.Forms.Color.Default ? UIColor.Clear.CGColor : pancake.BorderColor.ToCGColor(), FillColor = null, LineWidth = pancake.BorderThickness, Name = layerName }; // Create arcs for the given corner radius. bool hasShadowOrElevation = pancake.HasShadow || pancake.Elevation > 0; borderLayer.Path = pancake.Sides != 4 ? ShapeUtils.CreatePolygonPath(Bounds, pancake.Sides, pancake.CornerRadius.TopLeft, pancake.OffsetAngle).CGPath : ShapeUtils.CreateRoundedRectPath(Bounds, pancake.CornerRadius).CGPath; // insetBounds? var layerPosition = new CGPoint(borderLayer.Path.BoundingBox.Width / 2, borderLayer.Path.BoundingBox.Height / 2); borderLayer.Frame = borderLayer.Path.BoundingBox; borderLayer.Position = layerPosition; // Dash pattern for the border. if (pancake.BorderIsDashed) { borderLayer.LineDashPattern = new NSNumber[] { new NSNumber(6), new NSNumber(3) }; } if ((pancake.BorderGradientStartColor != default(Xamarin.Forms.Color) && pancake.BorderGradientEndColor != default(Xamarin.Forms.Color)) || (pancake.BorderGradientStops != null && pancake.BorderGradientStops.Any())) { var gradientFrame = Bounds.Inset(-pancake.BorderThickness, -pancake.BorderThickness); var gradientLayer = CreateGradientLayer(pancake.BorderGradientAngle, gradientFrame); gradientLayer.Position = new CGPoint((gradientFrame.Width / 2) - (pancake.BorderThickness), (gradientFrame.Height / 2) - (pancake.BorderThickness)); // Create a clone from the border layer and use that one as the mask. // Why? Because the mask and the border somehow can't be the same, so // don't want to do adjustments to borderLayer because it would influence the border. var maskLayer = new CAShapeLayer() { Path = borderLayer.Path, Position = new CGPoint(pancake.BorderThickness, pancake.BorderThickness), FillColor = null, LineWidth = pancake.BorderThickness, StrokeColor = UIColor.Red.CGColor, LineDashPattern = borderLayer.LineDashPattern }; gradientLayer.Mask = maskLayer; gradientLayer.Name = layerName; if (pancake.BorderGradientStops != null && pancake.BorderGradientStops.Count > 0) { // A range of colors is given. Let's add them. var orderedStops = pancake.BorderGradientStops.OrderBy(x => x.Offset).ToList(); gradientLayer.Colors = orderedStops.Select(x => x.Color.ToCGColor()).ToArray(); gradientLayer.Locations = orderedStops.Select(x => new NSNumber(x.Offset)).ToArray(); } else { // Only two colors provided, use that. gradientLayer.Colors = new CGColor[] { pancake.BorderGradientStartColor.ToCGColor(), pancake.BorderGradientEndColor.ToCGColor() }; } AddLayer(gradientLayer, -1, _wrapperView); } else { AddLayer(borderLayer, -1, _wrapperView); } } }
private void DrawBackground() { var pancake = Element as PancakeView; var layerName = "backgroundLayer"; // Remove previous background layer if any var prevBackgroundLayer = _actualView.Layer.Sublayers?.FirstOrDefault(x => x.Name == layerName); prevBackgroundLayer?.RemoveFromSuperLayer(); UIBezierPath cornerPath = null; if (pancake.Sides != 4) { cornerPath = ShapeUtils.CreatePolygonPath(Bounds, pancake.Sides, pancake.CornerRadius.TopLeft, pancake.OffsetAngle); } else { cornerPath = ShapeUtils.CreateRoundedRectPath(Bounds, pancake.CornerRadius); } // The layer used to mask other layers we draw on the background. var maskLayer = new CAShapeLayer { Frame = Bounds, Path = cornerPath.CGPath }; _actualView.Layer.Mask = maskLayer; _actualView.Layer.MasksToBounds = true; if ((pancake.BackgroundGradientStartColor != default(Xamarin.Forms.Color) && pancake.BackgroundGradientEndColor != default(Xamarin.Forms.Color)) || (pancake.BackgroundGradientStops != null && pancake.BackgroundGradientStops.Any())) { // Create a gradient layer that draws our background. var gradientLayer = CreateGradientLayer(pancake.BackgroundGradientAngle, Bounds); gradientLayer.Name = layerName; if (pancake.BackgroundGradientStops != null && pancake.BackgroundGradientStops.Count > 0) { // A range of colors is given. Let's add them. var orderedStops = pancake.BackgroundGradientStops.OrderBy(x => x.Offset).ToList(); gradientLayer.Colors = orderedStops.Select(x => x.Color.ToCGColor()).ToArray(); gradientLayer.Locations = orderedStops.Select(x => new NSNumber(x.Offset)).ToArray(); } else { // Only two colors provided, use that. gradientLayer.Colors = new CGColor[] { pancake.BackgroundGradientStartColor.ToCGColor(), pancake.BackgroundGradientEndColor.ToCGColor() }; } AddLayer(gradientLayer, 0, _actualView); } else { // Create a shape layer that draws our background. var shapeLayer = new CAShapeLayer { Frame = Bounds, Path = cornerPath.CGPath, MasksToBounds = true, FillColor = _colorToRender.CGColor, Name = layerName }; AddLayer(shapeLayer, 0, _actualView); } }