Created
April 9, 2018 09:11
-
-
Save scalbatty/7effdc84d976df82cd3215860b7d6122 to your computer and use it in GitHub Desktop.
A playground for experimenting with the "panel curve" we use at Zenly
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// A playground for experimenting with the "panel curve" we use at Zenly | |
import UIKit | |
import PlaygroundSupport | |
// This view displays a filled "panel" curve within the given frame | |
final class CurvedView: UIView { | |
// This is the fill color for the shape | |
private var _color: UIColor = .white | |
var color: UIColor { | |
get { | |
return _color | |
} | |
set(newValue) { | |
_color = newValue | |
shapeLayer.fillColor = newValue.cgColor | |
} | |
} | |
/* We store the size when computing the shape in order | |
not to recompute on every call to `layoutSubview` if | |
it's not necessary. | |
*/ | |
private var lastComputedSize: CGSize = .zero | |
override func layoutSubviews() { | |
super.layoutSubviews() | |
if bounds.size != lastComputedSize { | |
computeShape() | |
} | |
} | |
/* The view has a sublayer which is a shape layer, | |
it's used to draw the curved shape | |
*/ | |
private let shapeLayer: CAShapeLayer = CAShapeLayer() | |
private func computeShape() { | |
// Remove the existing shape layer if necessary | |
if let sublayer = layer.sublayers?.first { | |
sublayer.removeFromSuperlayer() | |
} | |
// Define the points for the bezier path curve, | |
// each point has coordinates + 1 or 2 control points | |
let initialPoint = CGPoint(x: 0, y: frame.size.height * 0.38) | |
let curve1dest = CGPoint(x: frame.size.width * 0.05, y: frame.size.height * 0.11) | |
let curve1ControlPoint1 = CGPoint(x: 0.0, y: frame.size.height * 0.13) | |
let curve1ControlPoint2 = CGPoint(x: frame.size.width * 0.02, y: frame.size.height * 0.13) | |
let curve2dest = CGPoint(x: frame.size.width / 2.0, y: 0) | |
let curve2ControlPoint2 = CGPoint(x: frame.size.width * 0.2, y: 0) | |
let curve3dest = CGPoint(x: frame.size.width * 0.95, y: frame.size.height * 0.11) | |
let curve3ControlPoint1 = CGPoint(x: frame.size.width * 0.78, y: 0) | |
let curve4dest = CGPoint(x: frame.size.width, y: frame.size.height * 0.38) | |
let curve4ControlPoint1 = CGPoint(x: frame.size.width * 0.98, y: frame.size.height * 0.13) | |
let curve4ControlPoint2 = CGPoint(x: frame.size.width, y: frame.size.height * 0.13) | |
// Create the actual bezier path | |
let path: UIBezierPath = UIBezierPath() | |
path.move(to: initialPoint) | |
path.addCurve(to: curve1dest, controlPoint1: curve1ControlPoint1, controlPoint2: curve1ControlPoint2) | |
path.addCurve(to: curve2dest, controlPoint1: curve1dest, controlPoint2: curve2ControlPoint2) | |
path.addCurve(to: curve3dest, controlPoint1: curve3ControlPoint1, controlPoint2: curve3dest) | |
path.addCurve(to: curve4dest, controlPoint1: curve4ControlPoint1, controlPoint2: curve4ControlPoint2) | |
path.addLine(to: CGPoint(x: frame.size.width, y: frame.size.height)) | |
path.addLine(to: CGPoint(x: 0, y: frame.size.height)) | |
path.close() | |
// Set the path as the path for the shape layer | |
shapeLayer.path = path.cgPath | |
shapeLayer.fillColor = _color.cgColor | |
// Configure the shadow as well | |
shapeLayer.shadowColor = UIColor(white: 0.0, alpha: 0.3).cgColor | |
shapeLayer.shadowOffset = CGSize(width: 0, height: 2) | |
shapeLayer.shadowOpacity = 1 | |
shapeLayer.shadowRadius = 10 | |
shapeLayer.shadowPath = path.cgPath | |
// Sets the view background clear | |
layer.backgroundColor = UIColor.clear.cgColor | |
layer.insertSublayer(shapeLayer, at: 0) | |
} | |
} | |
class MyViewController : UIViewController { | |
override func loadView() { | |
let view = UIView() | |
view.backgroundColor = .white | |
let lightBlue = UIColor(red: 0.3, green: 0.7, blue: 1.0, alpha: 1) | |
let curvedView = CurvedView(frame: CGRect(x: 0, y: 300, width: 375, height: 80)) | |
curvedView.color = lightBlue | |
// The "curved view" is only the top part of the panel, | |
// so we add a "main view" underneath. | |
let mainView = UIView(frame: CGRect(x: 0, y: 380, width: 375, height: 288)) | |
mainView.backgroundColor = lightBlue | |
view.addSubview(curvedView) | |
view.addSubview(mainView) | |
self.view = view | |
} | |
} | |
PlaygroundPage.current.liveView = MyViewController() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment