Commit 72c21de3 by Daniel Dahan

v1.x.x: updated to latest MK

parents fa7a3d7b 4a932999
Pod::Spec.new do |s|
s.name = 'MK'
s.version = '1.12.0'
s.version = '1.14.0'
s.license = { :type => "AGPLv3+", :file => "LICENSE" }
s.summary = 'A Material Design Framework In Swift'
s.homepage = 'http://materialkit.io'
......
# MaterialKit
### Build Beautiful Software
* [CocoaPods (MK)](https://cocoapods.org/?q=MK)
### CocoaPods Support
MaterialKit is now on CocoaPods under the name [MK](https://cocoapods.org/?q=MK).
### Floating Action Button
Make a call to action with a Floating Action Button.
![MaterialKitPreview](http://www.materialkit.io/fabbuttonpreview.gif)
```swift
var button: FabButton = FabButton()
button.setTitle("+", forState: .Normal)
button.titleLabel!.font = Roboto.lightWithSize(16)
// layout
view.addSubview(button)
Layout.size(view, child: button, width: 60, height: 60)
```
### Raised Button
Use a Raised Button to capture attention.
MaterialKit is on CocoaPods under the name [MK](https://cocoapods.org/?q=MK).
### Basic MaterialView
![MaterialKitPreview](http://www.materialkit.io/raisedbuttonpreview.gif)
To get started, let's introduce MaterialView, a lightweight UIView Object that has flexibility in mind. Common controls have been added to make things easier. For example, let's make a circle view that has a shadow, border, and image.
![MaterialKitPreview](http://www.materialkit.io/github/img1.png)
```swift
var button: RaisedButton = RaisedButton()
button.setTitle("Raised", forState: .Normal)
// layout
view.addSubview(button)
Layout.size(view, child: button, width: 200, height: 60)
```
### Flat Button
Keep it simple and elegant with a Flat Button.
![MaterialKitPreview](http://www.materialkit.io/flatbuttonpreview.gif)
```swift
var button: RaisedButton = RaisedButton()
button.setTitle("Flat", forState: .Normal)
// layout
view.addSubview(button)
Layout.size(view, child: button, width: 200, height: 60)
let v: MaterialView = MaterialView(frame: CGRectMake(0, 0, 200, 200))
v.shape = .Circle
v.shadowDepth = .Depth2
v.borderWidth = .Border1
v.image = UIImage(named: "focus")
```
### Basic Card
Easily make cards with fully customizable components.
### Animated MaterialPulseView
![MaterialKitPreview](http://www.materialkit.io/basiccardpreview.gif)
Let's expand on the basic MaterialView and use an animated MaterialPulseView. In this example, we will make the shape a square with some rounded corners.
![MaterialKitPreview](http://www.materialkit.io/github/img2.gif)
```swift
var card: BasicCardView = BasicCardView()
// title
card.titleLabel = UILabel()
card.titleLabel!.text = "Card Title"
// details
card.detailLabel = UILabel()
card.detailLabel!.text = "I am a very simple card. I am good at containing small bits of information. I am convenient because I require little markup to use effectively."
// divider
card.divider = UIView()
// buttons
var cancelButton: FlatButton = FlatButton()
cancelButton.pulseColor = MaterialTheme.blueGrey.darken3
cancelButton.setTitle("Cancel", forState: .Normal)
cancelButton.setTitleColor(MaterialTheme.yellow.darken3, forState: .Normal)
var okButton: FlatButton = FlatButton()
okButton.pulseColor = MaterialTheme.blueGrey.darken3
okButton.setTitle("Okay", forState: .Normal)
okButton.setTitleColor(MaterialTheme.yellow.darken3, forState: .Normal)
card.leftButtons = [cancelButton, okButton]
// layout
view.addSubview(card)
view.addConstraints(Layout.constraint("H:|-(pad)-[child]-(pad)-|", options: nil, metrics: ["pad": 20], views: ["child": card]))
view.addConstraints(Layout.constraint("V:|-(pad)-[child]", options: nil, metrics: ["pad": 100], views: ["child": card]))
let v: MaterialPulseView = MaterialPulseView(frame: CGRectMake(0, 0, 200, 200))
v.shape = .Square
v.cornerRadius = .Radius2
v.shadowDepth = .Depth2
v.image = UIImage(named: "focus")
```
### Image Card
Add photos with an Image Card.
### Simple FlatButton
![MaterialKitPreview](http://www.materialkit.io/imagecardpreview.gif)
A FlatButton is the best place to start when introducing MaterialKit buttons. It is simple, clean, and very effective. Below is an example of a FlatButton in action.
![MaterialKitPreview](http://www.materialkit.io/github/img3.gif)
```swift
var card: ImageCardView = ImageCardView()
card.imageView = UIImageView(image: UIImage(named: "photo.jpg"))
// layout
view.addSubview(card)
view.addConstraints(Layout.constraint("H:|-(pad)-[child]-(pad)-|", options: nil, metrics: ["pad": 20], views: ["child": card]))
view.addConstraints(Layout.constraint("V:|-(pad)-[child]", options: nil, metrics: ["pad": 100], views: ["child": card]))
let v: FlatButton = FlatButton(frame: CGRectMake(0, 0, 200, 64))
v.setTitle("Flat", forState: .Normal)
v.titleLabel!.font = RobotoFont.mediumWithSize(32)
```
### Full Image Card
Allow the Image Card to really shine by adding a title, some details, and buttons.
### Noticeable RaisedButton
![MaterialKitPreview](http://www.materialkit.io/imagecardfullpreview.gif)
A RaisedButton is sure to get attention. Take a look at the following code sample.
![MaterialKitPreview](http://www.materialkit.io/github/img4.gif)
```swift
var card: ImageCardView = ImageCardView()
card.imageView = UIImageView(image: UIImage(named: "photo.jpg"))
// title
card.titleLabel = UILabel()
card.titleLabel!.text = "Card Title"
// details
card.detailLabel = UILabel()
card.detailLabel!.text = "I am a very simple card. I am good at containing small bits of information. I am convenient because I require little markup to use effectively."
// divider
card.divider = UIView()
// buttons
var cancelButton: FlatButton = FlatButton()
cancelButton.pulseColor = MaterialTheme.blueGrey.darken3
cancelButton.setTitle("Cancel", forState: .Normal)
cancelButton.setTitleColor(MaterialTheme.yellow.darken3, forState: .Normal)
var okButton: FlatButton = FlatButton()
okButton.pulseColor = MaterialTheme.blueGrey.darken3
okButton.setTitle("Okay", forState: .Normal)
okButton.setTitleColor(MaterialTheme.yellow.darken3, forState: .Normal)
card.leftButtons = [cancelButton, okButton]
// layout
view.addSubview(card)
view.addConstraints(Layout.constraint("H:|-(pad)-[child]-(pad)-|", options: nil, metrics: ["pad": 20], views: ["child": card]))
view.addConstraints(Layout.constraint("V:|-(pad)-[child]", options: nil, metrics: ["pad": 100], views: ["child": card]))
let v: RaisedButton = RaisedButton(frame: CGRectMake(0, 0, 200, 64))
v.setTitle("Raised", forState: .Normal)
v.titleLabel!.font = RobotoFont.mediumWithSize(32)
```
### Side Navigation
Add a sleek Side Navigation to give your users a wonderful experience.
### Actionable FabButton
![MaterialKitPreview](http://www.materialkit.io/sidenavpreview.gif)
A FabButton is essential to Material Design's overall look. I leave this example as simple as possible to showcase its beauty.
![MaterialKitPreview](http://www.materialkit.io/github/img5.gif)
```swift
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
sideNav = SideNavigationViewController(mainViewController: MainViewController(), leftViewController: LeftViewController(), rightViewController: RightViewController())
sideNav!.delegate = self
window = UIWindow(frame: UIScreen.mainScreen().bounds)
window!.rootViewController = sideNav
window!.makeKeyAndVisible()
return true
}
let v: FabButton = FabButton(frame: CGRectMake(0, 0, 64, 64))
v.setImage(UIImage(named: "ic_create_white"), forState: .Normal)
v.setImage(UIImage(named: "ic_create_white"), forState: .Highlighted)
```
### Material Themes
### Sleek NavigationBarView
Beautify your app with color. All Material Design color palettes are supported.
A NavigationBarView is a very common UI element and the more presentable it is, the better. The following example shows how to setup a NavigationBarView on the fly.
[Color Palettes](http://www.google.com/design/spec/style/color.html)
![MaterialKitPreview](http://www.materialkit.io/github/img6.gif)
```swift
var button: RaisedButton = RaisedButton()
button.setTitle("Raised", forState: .Normal)
button.setTitleColor(MaterialTheme.blue.darken3, forState: .Normal)
button.backgroundColor = MaterialTheme.yellow.darken3
button.pulseColor = MaterialTheme.blueGrey.color
let v: NavigationBarView = NavigationBarView(titleLabel: MaterialLabel())!
v.titleLabel!.text = "Title"
v.titleLabel!.textAlignment = .Center
v.titleLabel!.textColor = MaterialColor.white
let b1: FlatButton = FlatButton()
b1.setTitle("B1", forState: .Normal)
b1.setTitleColor(MaterialColor.white, forState: .Normal)
b1.pulseColor = MaterialColor.white
let b2: FlatButton = FlatButton()
b2.setTitle("B2", forState: .Normal)
b2.setTitleColor(MaterialColor.white, forState: .Normal)
b2.pulseColor = MaterialColor.white
v.leftButtons = [b1, b2]
let b3: FlatButton = FlatButton()
b3.setTitle("B3", forState: .Normal)
b3.setTitleColor(MaterialColor.white, forState: .Normal)
b3.pulseColor = MaterialColor.white
let b4: FlatButton = FlatButton()
b4.setTitle("B4", forState: .Normal)
b4.setTitleColor(MaterialColor.white, forState: .Normal)
b4.pulseColor = MaterialColor.white
v.rightButtons = [b3, b4]
```
### License
[AGPLv3](http://choosealicense.com/licenses/agpl-3.0/)
### Contributors
* [Daniel Dahan](https://github.com/danieldahan)
* [Adam Dahan](https://github.com/adamdahan)
* [Michael Reyder](https://github.com/mishaGK)
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
import AVFoundation
@objc(PreviewDelegate)
public protocol PreviewDelegate {
optional func previewTappedToFocusAt(preview: Preview, point: CGPoint)
optional func previewTappedToExposeAt(preview: Preview, point: CGPoint)
optional func previewTappedToReset(preview: Preview, focus: UIView, exposure: UIView)
}
public class Preview: UIView {
/**
:name: boxBounds
:description: A static property that sets the initial size of the focusBox and exposureBox properties.
*/
static public var boxBounds: CGRect = CGRectMake(0, 0, 150, 150)
/**
:name: delegate
:description: An optional instance of PreviewDelegate to handle events that are triggered during various
stages of engagement.
*/
public weak var delegate: PreviewDelegate?
/**
:name: tapToFocusEnabled
:description: A mutator and accessor that enables and disables tap to focus gesture.
*/
public var tapToFocusEnabled: Bool {
get {
return singleTapRecognizer!.enabled
}
set(value) {
singleTapRecognizer!.enabled = value
}
}
/**
:name: tapToExposeEnabled
:description: A mutator and accessor that enables and disables tap to expose gesture.
*/
public var tapToExposeEnabled: Bool {
get {
return doubleTapRecognizer!.enabled
}
set(value) {
doubleTapRecognizer!.enabled = value
}
}
//
// override for layerClass
//
override public class func layerClass() -> AnyClass {
return AVCaptureVideoPreviewLayer.self
}
/**
:name: session
:description: A mutator and accessor for the preview AVCaptureSession value.
*/
public var session: AVCaptureSession {
get {
return (layer as! AVCaptureVideoPreviewLayer).session
}
set(value) {
(layer as! AVCaptureVideoPreviewLayer).session = value
}
}
/**
:name: focusBox
:description: An optional UIView for the focusBox animation. This is used when the
tapToFocusEnabled property is set to true.
*/
public var focusBox: UIView?
/**
:name: exposureBox
:description: An optional UIView for the exposureBox animation. This is used when the
tapToExposeEnabled property is set to true.
*/
public var exposureBox: UIView?
//
// :name: singleTapRecognizer
// :description: Gesture recognizer for single tap.
//
private var singleTapRecognizer: UITapGestureRecognizer?
//
// :name: doubleTapRecognizer
// :description: Gesture recognizer for double tap.
//
private var doubleTapRecognizer: UITapGestureRecognizer?
//
// :name: doubleDoubleTapRecognizer
// :description: Gesture recognizer for double/double tap.
//
private var doubleDoubleTapRecognizer: UITapGestureRecognizer?
required public init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
prepareView()
}
public override init(frame: CGRect) {
super.init(frame: frame)
prepareView()
}
public init() {
super.init(frame: CGRectZero)
setTranslatesAutoresizingMaskIntoConstraints(false)
prepareView()
}
//
// :name: handleSingleTap
//
internal func handleSingleTap(recognizer: UIGestureRecognizer) {
let point: CGPoint = recognizer.locationInView(self)
runBoxAnimationOnView(focusBox, point: point)
delegate?.previewTappedToFocusAt?(self, point: captureDevicePointForPoint(point))
}
//
// :name: handleDoubleTap
//
internal func handleDoubleTap(recognizer: UIGestureRecognizer) {
let point: CGPoint = recognizer.locationInView(self)
runBoxAnimationOnView(exposureBox, point: point)
delegate?.previewTappedToExposeAt?(self, point: captureDevicePointForPoint(point))
}
//
// :name: handleDoubleDoubleTap
//
internal func handleDoubleDoubleTap(recognizer: UIGestureRecognizer) {
runResetAnimation()
}
//
// :name: prepareView
// :description: Common setup for view.
//
private func prepareView() {
let captureLayer: AVCaptureVideoPreviewLayer = layer as! AVCaptureVideoPreviewLayer
captureLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
singleTapRecognizer = UITapGestureRecognizer(target: self, action: "handleSingleTap:")
singleTapRecognizer!.numberOfTapsRequired = 1
doubleTapRecognizer = UITapGestureRecognizer(target: self, action: "handleDoubleTap:")
doubleTapRecognizer!.numberOfTapsRequired = 2
doubleDoubleTapRecognizer = UITapGestureRecognizer(target: self, action: "handleDoubleDoubleTap:")
doubleDoubleTapRecognizer!.numberOfTapsRequired = 2
doubleDoubleTapRecognizer!.numberOfTouchesRequired = 2
addGestureRecognizer(singleTapRecognizer!)
addGestureRecognizer(doubleTapRecognizer!)
addGestureRecognizer(doubleDoubleTapRecognizer!)
singleTapRecognizer!.requireGestureRecognizerToFail(doubleTapRecognizer!)
focusBox = viewWithColor(.redColor())
exposureBox = viewWithColor(.blueColor())
addSubview(focusBox!)
addSubview(exposureBox!)
}
//
// :name: viewWithColor
// :description: Initializes a UIView with a set UIColor.
//
private func viewWithColor(color: UIColor) -> UIView {
let view: UIView = UIView(frame: Preview.boxBounds)
view.backgroundColor = MaterialTheme.clear.color
view.layer.borderColor = color.CGColor
view.layer.borderWidth = 5
view.hidden = true
return view
}
//
// :name: runBoxAnimationOnView
// :description: Runs the animation used for focusBox and exposureBox on single and double
// taps respectively at a given point.
//
private func runBoxAnimationOnView(view: UIView!, point: CGPoint) {
view.center = point
view.hidden = false
UIView.animateWithDuration(0.15, delay: 0, options: .CurveEaseInOut, animations: { _ in
view.layer.transform = CATransform3DMakeScale(0.5, 0.5, 1)
}) { _ in
let delayInSeconds: Double = 0.5
let popTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(delayInSeconds * Double(NSEC_PER_SEC)))
dispatch_after(popTime, dispatch_get_main_queue()) {
view.hidden = true
view.transform = CGAffineTransformIdentity
}
}
}
//
// :name: captureDevicePointForPoint
// :description: Interprets the correct point from touch to preview layer.
//
private func captureDevicePointForPoint(point: CGPoint) -> CGPoint {
let previewLayer: AVCaptureVideoPreviewLayer = layer as! AVCaptureVideoPreviewLayer
return previewLayer.captureDevicePointOfInterestForPoint(point)
}
//
// :name: runResetAnimation
// :description: Executes the reset animation for focus and exposure.
//
private func runResetAnimation() {
if !tapToFocusEnabled && !tapToExposeEnabled {
return
}
let previewLayer: AVCaptureVideoPreviewLayer = layer as! AVCaptureVideoPreviewLayer
let centerPoint: CGPoint = previewLayer.pointForCaptureDevicePointOfInterest(CGPointMake(0.5, 0.5))
focusBox!.center = centerPoint
exposureBox!.center = centerPoint
exposureBox!.transform = CGAffineTransformMakeScale(1.2, 1.2)
focusBox!.hidden = false
exposureBox!.hidden = false
UIView.animateWithDuration(0.15, delay: 0, options: .CurveEaseInOut, animations: { _ in
self.focusBox!.layer.transform = CATransform3DMakeScale(0.5, 0.5, 1)
self.exposureBox!.layer.transform = CATransform3DMakeScale(0.7, 0.7, 1)
}) { _ in
let delayInSeconds: Double = 0.5
let popTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(delayInSeconds * Double(NSEC_PER_SEC)))
dispatch_after(popTime, dispatch_get_main_queue()) {
self.focusBox!.hidden = true
self.exposureBox!.hidden = true
self.focusBox!.transform = CGAffineTransformIdentity
self.exposureBox!.transform = CGAffineTransformIdentity
self.delegate?.previewTappedToReset?(self, focus: self.focusBox!, exposure: self.exposureBox!)
}
}
}
}
......@@ -20,32 +20,26 @@ import UIKit
public class FabButton : MaterialButton {
//
// :name: prepareButton
// :name: prepareView
//
internal override func prepareView() {
super.prepareView()
setTitleColor(MaterialTheme.white.color, forState: .Normal)
backgroundColor = MaterialTheme.red.darken1
contentEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0)
setTitleColor(MaterialTheme.button.fab.titleLabelColorForNormalState, forState: .Normal)
titleLabel!.font = MaterialTheme.button.fab.titleLabelFont
userInteractionEnabled = MaterialTheme.button.fab.userInteractionEnabled
backgroundColor = MaterialTheme.button.fab.backgroudColor
pulseColorOpacity = MaterialTheme.button.fab.pulseColorOpacity
pulseColor = MaterialTheme.button.fab.pulseColor
shadowDepth = MaterialTheme.button.fab.shadowDepth
shadowColor = MaterialTheme.button.fab.shadowColor
zPosition = MaterialTheme.button.fab.zPosition
masksToBounds = MaterialTheme.button.fab.masksToBounds
cornerRadius = MaterialTheme.button.fab.cornerRadius
borderWidth = MaterialTheme.button.fab.borderWidth
borderColor = MaterialTheme.button.fab.bordercolor
contentInsets = MaterialTheme.button.fab.contentInsets
shape = MaterialTheme.button.fab.shape
}
//
// :name: prepareButton
//
internal override func prepareButton() {
super.prepareButton()
prepareShadow()
backgroundColorView.layer.cornerRadius = bounds.width / 2
}
//
// :name: pulseBegan
//
internal override func pulseBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
super.pulseBegan(touches, withEvent: event)
UIView.animateWithDuration(0.3, animations: {
self.pulseView!.transform = CGAffineTransformMakeScale(3, 3)
self.transform = CGAffineTransformMakeScale(1.1, 1.1)
})
}
}
}
\ No newline at end of file
......@@ -24,29 +24,22 @@ public class FlatButton : MaterialButton {
//
internal override func prepareView() {
super.prepareView()
titleLabel!.font = Roboto.medium
setTitleColor(MaterialTheme.blueGrey.darken4, forState: .Normal)
pulseColor = MaterialTheme.blueGrey.lighten3
backgroundColor = MaterialTheme.clear.color
contentEdgeInsets = UIEdgeInsetsMake(6, 16, 6, 16)
setTitleColor(MaterialTheme.button.flat.titleLabelColorForNormalState, forState: .Normal)
titleLabel!.font = MaterialTheme.button.flat.titleLabelFont
userInteractionEnabled = MaterialTheme.button.flat.userInteractionEnabled
backgroundColor = MaterialTheme.button.flat.backgroudColor
pulseColorOpacity = MaterialTheme.button.flat.pulseColorOpacity
pulseColor = MaterialTheme.button.flat.pulseColor
shadowDepth = MaterialTheme.button.flat.shadowDepth
shadowColor = MaterialTheme.button.flat.shadowColor
zPosition = MaterialTheme.button.flat.zPosition
masksToBounds = MaterialTheme.button.flat.masksToBounds
cornerRadius = MaterialTheme.button.flat.cornerRadius
borderWidth = MaterialTheme.button.flat.borderWidth
borderColor = MaterialTheme.button.flat.bordercolor
contentInsets = MaterialTheme.button.flat.contentInsets
shape = MaterialTheme.button.flat.shape
}
//
// :name: prepareButton
//
internal override func prepareButton() {
super.prepareButton()
backgroundColorView.layer.cornerRadius = 3
}
//
// :name: pulseBegan
//
internal override func pulseBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
super.pulseBegan(touches, withEvent: event)
UIView.animateWithDuration(0.3, animations: {
self.pulseView!.transform = CGAffineTransformMakeScale(4, 4)
self.transform = CGAffineTransformMakeScale(1.05, 1.05)
})
}
}
}
\ No newline at end of file
......@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>io.graphkit.$(PRODUCT_NAME:rfc1034identifier)</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
......@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.12.0</string>
<string>1.14.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
......
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public struct MaterialAnimation {
/**
:name: spin
*/
public static func spin(view: UIView, duration: CFTimeInterval, rotations: Int = 1, completion: (() -> Void)? = nil) {
let a: CABasicAnimation = CABasicAnimation()
a.keyPath = "transform.rotation"
a.duration = duration
a.byValue = M_PI * 2 * Double(rotations)
view.layer.addAnimation(a, forKey: nil)
}
}
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public typealias MaterialBorderType = CGFloat
public enum MaterialBorder {
case Border0
case Border1
case Border2
case Border3
case Border4
}
/**
:name: MaterialBorderToValue
*/
public func MaterialBorderToValue(border: MaterialBorder) -> MaterialBorderType {
switch border {
case .Border0:
return 0
case .Border1:
return 0.5
case .Border2:
return 1
case .Border3:
return 2
case .Border4:
return 3
}
}
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public class MaterialCardView : UIView {
//
// :name: backgroundColorView
//
internal lazy var backgroundColorView: UIView = UIView()
//
// :name: pulseViewContainer
//
internal lazy var pulseViewContainer: UIView = UIView()
//
// :name: pulseView
//
internal var pulseView: UIView?
/**
:name: backgroundColor
*/
public override var backgroundColor: UIColor? {
get {
return backgroundColorView.backgroundColor
}
set(value) {
backgroundColorView.backgroundColor = value
}
}
/**
:name: pulseColor
*/
public var pulseColor: UIColor = MaterialTheme.blueGrey.lighten3
/**
:name: init
*/
public required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
prepareView()
}
/**
:name: init
*/
public required override init(frame: CGRect) {
super.init(frame: frame)
prepareView()
}
/**
:name: init
*/
public convenience init() {
self.init(frame: CGRectZero)
}
/**
:name: touchesBegan
*/
public override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
super.touchesBegan(touches, withEvent: event)
pulseBegan(touches, withEvent: event)
}
/**
:name: touchesEnded
*/
public override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
super.touchesEnded(touches, withEvent: event)
shrink()
pulseEnded(touches, withEvent: event)
}
/**
:name: touchesCancelled
*/
public override func touchesCancelled(touches: Set<NSObject>!, withEvent event: UIEvent!) {
super.touchesCancelled(touches, withEvent: event)
shrink()
pulseEnded(touches, withEvent: event)
}
//
// :name: prepareView
//
internal func prepareView() {
setTranslatesAutoresizingMaskIntoConstraints(false)
prepareBackgroundColorView()
preparePulseViewContainer()
prepareCard()
}
//
// :name: prepareCard
//
internal func prepareCard() {}
//
// :name: prepareShadow
//
internal func prepareShadow() {
layer.shadowColor = MaterialTheme.black.color.CGColor
layer.shadowOffset = CGSizeMake(0.1, 0.1)
layer.shadowOpacity = 0.4
layer.shadowRadius = 2
}
//
// :name: removeShadow
//
internal func removeShadow() {
layer.shadowColor = MaterialTheme.clear.color.CGColor
layer.shadowOffset = CGSizeMake(0, 0)
layer.shadowOpacity = 0
layer.shadowRadius = 0
}
//
// :name: layoutSubviews
//
public override func layoutSubviews() {
super.layoutSubviews()
layer.shadowPath = UIBezierPath(rect: bounds).CGPath
}
//
// :name: pulseBegan
//
internal func pulseBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
let width: CGFloat = bounds.size.width / 3
pulseView = UIView(frame: CGRectMake(0, 0, width, width))
pulseView!.layer.cornerRadius = width / 2
pulseView!.center = (touches.first as! UITouch).locationInView(self)
pulseView!.backgroundColor = pulseColor.colorWithAlphaComponent(0.3)
addSubview(pulseViewContainer)
Layout.expandToParent(self, child: pulseViewContainer)
pulseViewContainer.addSubview(pulseView!)
UIView.animateWithDuration(0.3, animations: {
self.pulseView!.transform = CGAffineTransformMakeScale(3, 3)
self.transform = CGAffineTransformMakeScale(1.05, 1.05)
}, completion: nil)
}
//
// :name: pulseEnded
//
internal func pulseEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
UIView.animateWithDuration(0.3,
animations: { _ in
self.pulseView?.alpha = 0
}
) { _ in
self.pulseViewContainer.removeFromSuperview()
self.pulseView?.removeFromSuperview()
self.pulseView = nil
}
}
//
// :name: prepareBackgroundColorView
//
// We need this view so we can use the masksToBounds
// so the pulse doesn't animate off the button
private func prepareBackgroundColorView() {
backgroundColorView.setTranslatesAutoresizingMaskIntoConstraints(false)
backgroundColorView.layer.cornerRadius = 2
backgroundColorView.layer.masksToBounds = true
backgroundColorView.clipsToBounds = true
backgroundColorView.userInteractionEnabled = false
insertSubview(backgroundColorView, atIndex: 0)
Layout.expandToParent(self, child: backgroundColorView)
}
//
// :name: preparePulseViewContainer
//
// We need this view so we can use the masksToBounds
// so the pulse doesn't animate off the button
private func preparePulseViewContainer() {
pulseViewContainer.setTranslatesAutoresizingMaskIntoConstraints(false)
pulseViewContainer.layer.cornerRadius = 2
pulseViewContainer.layer.masksToBounds = true
pulseViewContainer.clipsToBounds = true
pulseViewContainer.userInteractionEnabled = false
}
//
// :name: shrink
//
private func shrink() {
UIView.animateWithDuration(0.3,
delay: 0,
usingSpringWithDamping: 0.2,
initialSpringVelocity: 10,
options: nil,
animations: {
self.transform = CGAffineTransformIdentity
},
completion: nil
)
}
}
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public typealias MaterialDepthType = (offset: CGSize, opacity: Float, radius: CGFloat)
public enum MaterialDepth {
case Depth0
case Depth1
case Depth2
case Depth3
case Depth4
case Depth5
}
/**
:name: MaterialDepthToValue
*/
public func MaterialDepthToValue(depth: MaterialDepth) -> MaterialDepthType {
switch depth {
case .Depth0:
return (offset: CGSizeZero, opacity: 0, radius: 0)
case .Depth1:
return (offset: CGSizeMake(0.2, 0.2), opacity: 0.5, radius: 1)
case .Depth2:
return (offset: CGSizeMake(0.4, 0.4), opacity: 0.5, radius: 2)
case .Depth3:
return (offset: CGSizeMake(0.6, 0.6), opacity: 0.5, radius: 3)
case .Depth4:
return (offset: CGSizeMake(0.8, 0.8), opacity: 0.5, radius: 4)
case .Depth5:
return (offset: CGSizeMake(1, 1), opacity: 0.5, radius: 5)
}
}
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public protocol MaterialFontType {}
public struct MaterialFont : MaterialFontType {
/**
:name: pointSize
*/
public static let pointSize: CGFloat = 16
/**
:name: systemFontWithSize
*/
public static func systemFontWithSize(size: CGFloat) -> UIFont {
return UIFont.systemFontOfSize(size)
}
/**
:name: boldSystemFontWithSize
*/
public static func boldSystemFontWithSize(size: CGFloat) -> UIFont {
return UIFont.boldSystemFontOfSize(size)
}
/**
:name: italicSystemFontWithSize
*/
public static func italicSystemFontWithSize(size: CGFloat) -> UIFont {
return UIFont.italicSystemFontOfSize(size)
}
}
\ No newline at end of file
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public typealias MaterialGravityType = String
public enum MaterialGravity {
case Center
case Top
case Bottom
case Left
case Right
case TopLeft
case TopRight
case BottomLeft
case BottomRight
case Resize
case ResizeAspect
case ResizeAspectFill
}
/**
:name: MaterialGravityToString
*/
public func MaterialGravityToString(gravity: MaterialGravity) -> String {
switch gravity {
case .Center:
return kCAGravityCenter
case .Top:
return kCAGravityTop
case .Bottom:
return kCAGravityBottom
case .Left:
return kCAGravityLeft
case .Right:
return kCAGravityRight
case .TopLeft:
return kCAGravityTopLeft
case .TopRight:
return kCAGravityTopRight
case .BottomLeft:
return kCAGravityBottomLeft
case .BottomRight:
return kCAGravityBottomRight
case .Resize:
return kCAGravityResize
case .ResizeAspect:
return kCAGravityResizeAspect
case .ResizeAspectFill:
return kCAGravityResizeAspectFill
}
}
\ No newline at end of file
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public typealias MaterialInsetsType = (top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat)
public enum MaterialInsets {
case Inset0
case Inset1
case Inset2
case Inset3
case Inset4
}
/**
:name: MaterialInsetsToValue
*/
public func MaterialInsetsToValue(inset: MaterialInsets) -> MaterialInsetsType {
switch inset {
case .Inset0:
return (top: 0, left: 0, bottom: 0, right: 0)
case .Inset1:
return (top: 2, left: 4, bottom: 2, right: 4)
case .Inset2:
return (top: 4, left: 8, bottom: 4, right: 8)
case .Inset3:
return (top: 8, left: 16, bottom: 8, right: 16)
case .Inset4:
return (top: 16, left: 32, bottom: 16, right: 32)
}
}
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public class MaterialLabel : UILabel {
/**
:name: layerClass
*/
public override class func layerClass() -> AnyClass {
return CATextLayer.self
}
/**
:name: textLayer
*/
public var textLayer: CATextLayer {
return layer as! CATextLayer
}
/**
:name: text
*/
public override var text: String? {
didSet {
textLayer.string = text
}
}
/**
:name: textColor
*/
public override var textColor: UIColor? {
didSet {
textLayer.foregroundColor = textColor?.CGColor
}
}
/**
:name: font
*/
public override var font: UIFont? {
didSet {
if let v = font {
textLayer.font = CGFontCreateWithFontName(v.fontName as CFStringRef)!
pointSize = v.pointSize
}
}
}
/**
:name: pointSize
*/
public var pointSize: CGFloat! {
didSet {
textLayer.fontSize = pointSize
}
}
/**
:name: textAlignment
*/
public override var textAlignment: NSTextAlignment {
didSet {
switch textAlignment {
case .Left:
textLayer.alignmentMode = kCAAlignmentLeft
case .Center:
textLayer.alignmentMode = kCAAlignmentCenter
case .Right:
textLayer.alignmentMode = kCAAlignmentRight
case .Justified:
textLayer.alignmentMode = kCAAlignmentJustified
case .Natural:
textLayer.alignmentMode = kCAAlignmentNatural
}
}
}
/**
:name: wrapped
*/
public var wrapped: Bool! {
didSet {
textLayer.wrapped = nil == wrapped ? MaterialTheme.label.wrapped : wrapped!
}
}
/**
:name: contentsScale
*/
public var contentsScale: CGFloat! {
didSet {
textLayer.contentsScale = nil == contentsScale ? MaterialTheme.label.contentsScale : contentsScale!
}
}
/**
:name: lineBreakMode
*/
public override var lineBreakMode: NSLineBreakMode {
didSet {
switch lineBreakMode {
case .ByWordWrapping: // Wrap at word boundaries, default
wrapped = true
textLayer.truncationMode = kCATruncationNone
case .ByCharWrapping: // Wrap at character boundaries
wrapped = true
textLayer.truncationMode = kCATruncationNone
case .ByClipping: // Simply clip
wrapped = false
textLayer.truncationMode = kCATruncationNone
case .ByTruncatingHead: // Truncate at head of line: "...wxyz"
wrapped = false
textLayer.truncationMode = kCATruncationStart
case .ByTruncatingTail: // Truncate at tail of line: "abcd..."
wrapped = false
textLayer.truncationMode = kCATruncationEnd
case .ByTruncatingMiddle: // Truncate middle of line: "ab...yz"
wrapped = false
textLayer.truncationMode = kCATruncationMiddle
}
}
}
/**
:name: init
*/
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
/**
:name: init
*/
public override init(frame: CGRect) {
super.init(frame: frame)
prepareView()
}
/**
:name: init
*/
public convenience init() {
self.init(frame: CGRectZero)
}
//
// :name: prepareView
//
internal func prepareView() {
textAlignment = MaterialTheme.label.textAlignment
wrapped = MaterialTheme.label.wrapped
contentsScale = MaterialTheme.label.contentsScale
font = MaterialTheme.label.font
}
}
\ No newline at end of file
......@@ -18,14 +18,14 @@
import UIKit
public struct Layout {
public struct MaterialLayout {
/**
:name: width
*/
public static func width(parent: UIView, child: UIView, width: CGFloat = 0) {
let metrics: Dictionary<String, AnyObject> = ["width" : width]
let views: Dictionary<String, AnyObject> = ["child" : child]
parent.addConstraints(constraint("H:[child(width)]", options: nil, metrics: metrics, views: views))
parent.addConstraints(constraint("H:[child(width)]", options: [], metrics: metrics, views: views))
}
/**
......@@ -34,61 +34,61 @@ public struct Layout {
public static func height(parent: UIView, child: UIView, height: CGFloat = 0) {
let metrics: Dictionary<String, AnyObject> = ["height" : height]
let views: Dictionary<String, AnyObject> = ["child" : child]
parent.addConstraints(constraint("V:[child(height)]", options: nil, metrics: metrics, views: views))
parent.addConstraints(constraint("V:[child(height)]", options: [], metrics: metrics, views: views))
}
/**
:name: size
*/
public static func size(parent: UIView, child: UIView, width: CGFloat = 0, height: CGFloat = 0) {
Layout.width(parent, child: child, width: width)
Layout.height(parent, child: child, height: height)
MaterialLayout.width(parent, child: child, width: width)
MaterialLayout.height(parent, child: child, height: height)
}
/**
:name: expandToParent
:name: alignToParent
*/
public static func expandToParent(parent: UIView, child: UIView) {
public static func alignToParent(parent: UIView, child: UIView) {
let views: Dictionary<String, AnyObject> = ["child" : child]
parent.addConstraints(constraint("H:|[child]|", options: nil, metrics: nil, views: views))
parent.addConstraints(constraint("V:|[child]|", options: nil, metrics: nil, views: views))
parent.addConstraints(constraint("H:|[child]|", options: [], metrics: nil, views: views))
parent.addConstraints(constraint("V:|[child]|", options: [], metrics: nil, views: views))
}
/**
:name: expandToParentHorizontally
:name: alignToParentHorizontally
*/
public static func expandToParentHorizontally(parent: UIView, child: UIView) {
expandToParentHorizontallyWithPad(parent, child: child, left: 0, right: 0)
public static func alignToParentHorizontally(parent: UIView, child: UIView) {
alignToParentHorizontallyWithInsets(parent, child: child, left: 0, right: 0)
}
/**
:name: expandToParentHorizontallyWithPad
:name: alignToParentHorizontallyWithInsets
*/
public static func expandToParentHorizontallyWithPad(parent: UIView, child: UIView, left: CGFloat = 0, right: CGFloat = 0) {
parent.addConstraints(constraint("H:|-(left)-[child]-(right)-|", options: nil, metrics: ["left": left, "right": right], views: ["child" : child]))
public static func alignToParentHorizontallyWithInsets(parent: UIView, child: UIView, left: CGFloat = 0, right: CGFloat = 0) {
parent.addConstraints(constraint("H:|-(left)-[child]-(right)-|", options: [], metrics: ["left": left, "right": right], views: ["child" : child]))
}
/**
:name: expandToParentVertically
:name: alignToParentVertically
*/
public static func expandToParentVertically(parent: UIView, child: UIView) {
expandToParentVerticallyWithPad(parent, child: child, top: 0, bottom: 0)
public static func alignToParentVertically(parent: UIView, child: UIView) {
alignToParentVerticallyWithInsets(parent, child: child, top: 0, bottom: 0)
}
/**
:name: expandToParentVerticallyWithPad
:name: alignToParentVerticallyWithInsets
*/
public static func expandToParentVerticallyWithPad(parent: UIView, child: UIView, top: CGFloat = 0, bottom: CGFloat = 0) {
parent.addConstraints(constraint("V:|-(top)-[child]-(bottom)-|", options: nil, metrics: ["bottom": bottom, "top": top], views: ["child" : child]))
public static func alignToParentVerticallyWithInsets(parent: UIView, child: UIView, top: CGFloat = 0, bottom: CGFloat = 0) {
parent.addConstraints(constraint("V:|-(top)-[child]-(bottom)-|", options: [], metrics: ["bottom": bottom, "top": top], views: ["child" : child]))
}
/**
:name: expandToParentWithPad
:name: alignToParentWithInsets
*/
public static func expandToParentWithPad(parent: UIView, child: UIView, top: CGFloat = 0, left: CGFloat = 0, bottom: CGFloat = 0, right: CGFloat = 0) {
public static func alignToParentWithInsets(parent: UIView, child: UIView, top: CGFloat = 0, left: CGFloat = 0, bottom: CGFloat = 0, right: CGFloat = 0) {
let views: Dictionary<String, AnyObject> = ["child" : child]
parent.addConstraints(constraint("H:|-(left)-[child]-(right)-|", options: nil, metrics: ["left": left, "right": right], views: views))
parent.addConstraints(constraint("V:|-(top)-[child]-(bottom)-|", options: nil, metrics: ["bottom": bottom, "top": top], views: views))
parent.addConstraints(constraint("H:|-(left)-[child]-(right)-|", options: [], metrics: ["left": left, "right": right], views: views))
parent.addConstraints(constraint("V:|-(top)-[child]-(bottom)-|", options: [], metrics: ["bottom": bottom, "top": top], views: views))
}
/**
......@@ -97,8 +97,8 @@ public struct Layout {
public static func alignFromTopLeft(parent: UIView, child: UIView, top: CGFloat = 0, left: CGFloat = 0) {
let metrics: Dictionary<String, AnyObject> = ["top" : top, "left" : left]
let views: Dictionary<String, AnyObject> = ["child" : child]
parent.addConstraints(constraint("H:|-(left)-[child]", options: nil, metrics: metrics, views: views))
parent.addConstraints(constraint("V:|-(top)-[child]", options: nil, metrics: metrics, views: views))
parent.addConstraints(constraint("H:|-(left)-[child]", options: [], metrics: metrics, views: views))
parent.addConstraints(constraint("V:|-(top)-[child]", options: [], metrics: metrics, views: views))
}
/**
......@@ -107,8 +107,8 @@ public struct Layout {
public static func alignFromTopRight(parent: UIView, child: UIView, top: CGFloat = 0, right: CGFloat = 0) {
let metrics: Dictionary<String, AnyObject> = ["top" : top, "right" : right]
let views: Dictionary<String, AnyObject> = ["child" : child]
parent.addConstraints(constraint("H:[child]-(right)-|", options: nil, metrics: metrics, views: views))
parent.addConstraints(constraint("V:|-(top)-[child]", options: nil, metrics: metrics, views: views))
parent.addConstraints(constraint("H:[child]-(right)-|", options: [], metrics: metrics, views: views))
parent.addConstraints(constraint("V:|-(top)-[child]", options: [], metrics: metrics, views: views))
}
/**
......@@ -117,8 +117,8 @@ public struct Layout {
public static func alignFromBottomLeft(parent: UIView, child: UIView, bottom: CGFloat = 0, left: CGFloat = 0) {
let metrics: Dictionary<String, AnyObject> = ["bottom" : bottom, "left" : left]
let views: Dictionary<String, AnyObject> = ["child" : child]
parent.addConstraints(constraint("H:|-(left)-[child]", options: nil, metrics: metrics, views: views))
parent.addConstraints(constraint("V:[child]-(bottom)-|", options: nil, metrics: metrics, views: views))
parent.addConstraints(constraint("H:|-(left)-[child]", options: [], metrics: metrics, views: views))
parent.addConstraints(constraint("V:[child]-(bottom)-|", options: [], metrics: metrics, views: views))
}
/**
......@@ -127,29 +127,47 @@ public struct Layout {
public static func alignFromBottomRight(parent: UIView, child: UIView, bottom: CGFloat = 0, right: CGFloat = 0) {
let metrics: Dictionary<String, AnyObject> = ["bottom" : bottom, "right" : right]
let views: Dictionary<String, AnyObject> = ["child" : child]
parent.addConstraints(constraint("H:[child]-(right)-|", options: nil, metrics: metrics, views: views))
parent.addConstraints(constraint("V:[child]-(bottom)-|", options: nil, metrics: metrics, views: views))
}
/**
:name: alignAllSides
*/
public static func alignAllSides(parent: UIView, child: UIView) {
expandToParent(parent, child: child)
}
parent.addConstraints(constraint("H:[child]-(right)-|", options: [], metrics: metrics, views: views))
parent.addConstraints(constraint("V:[child]-(bottom)-|", options: [], metrics: metrics, views: views))
}
/**
:name: alignFromTop
*/
public static func alignFromTop(parent: UIView, child: UIView, top: CGFloat = 0) {
parent.addConstraints(constraint("V:|-(top)-[child]", options: [], metrics: ["top" : top], views: ["child" : child]))
}
/**
:name: alignFromLeft
*/
public static func alignFromLeft(parent: UIView, child: UIView, left: CGFloat = 0) {
parent.addConstraints(constraint("H:|-(left)-[child]", options: [], metrics: ["left" : left], views: ["child" : child]))
}
/**
:name: alignFromBottom
*/
public static func alignFromBottom(parent: UIView, child: UIView, bottom: CGFloat = 0) {
parent.addConstraints(constraint("V:[child]-(bottom)-|", options: [], metrics: ["bottom" : bottom], views: ["child" : child]))
}
/**
:name: alignFromRight
*/
public static func alignFromRight(parent: UIView, child: UIView, right: CGFloat = 0) {
parent.addConstraints(constraint("H:[child]-(right)-|", options: [], metrics: ["right" : right], views: ["child" : child]))
}
/**
:name: constraint
*/
public static func constraint(format: String, options: NSLayoutFormatOptions, metrics: Dictionary<String, AnyObject>?, views: Dictionary<String, AnyObject>) -> Array<NSLayoutConstraint> {
for (_, v) in views {
v.setTranslatesAutoresizingMaskIntoConstraints(false)
}
return NSLayoutConstraint.constraintsWithVisualFormat(
format,
options: options,
metrics: metrics,
views: views
) as! Array<NSLayoutConstraint>
)
}
}
}
\ No newline at end of file
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public class MaterialPulseView: MaterialView {
//
// :name: touchesLayer
//
internal lazy var touchesLayer: CAShapeLayer = CAShapeLayer()
//
// :name: pulseLayer
//
internal lazy var pulseLayer: CAShapeLayer = CAShapeLayer()
/**
:name: pulseColorOpacity
*/
public var pulseColorOpacity: CGFloat! {
didSet {
pulseColorOpacity = nil == pulseColorOpacity ? 0.5 : pulseColorOpacity!
}
}
/**
:name: pulseColor
*/
public var pulseColor: UIColor? {
didSet {
pulseLayer.backgroundColor = pulseColor?.colorWithAlphaComponent(pulseColorOpacity!).CGColor
}
}
/**
:name: init
*/
public convenience init() {
self.init(frame: CGRectMake(MaterialTheme.pulseView.x, MaterialTheme.pulseView.y, MaterialTheme.pulseView.width, MaterialTheme.pulseView.height))
}
/**
:name: layoutSubviews
*/
public override func layoutSubviews() {
super.layoutSubviews()
touchesLayer.frame = bounds
touchesLayer.cornerRadius = layer.cornerRadius
}
/**
:name: touchesBegan
*/
public override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesBegan(touches, withEvent: event)
let point: CGPoint = touches.first!.locationInView(self)
// set start position
CATransaction.begin()
CATransaction.setAnimationDuration(0)
let w: CGFloat = width / 2
pulseLayer.hidden = false
pulseLayer.position = point
pulseLayer.bounds = CGRectMake(0, 0, w, w)
pulseLayer.cornerRadius = CGFloat(w / 2)
CATransaction.commit()
// expand
CATransaction.begin()
CATransaction.setAnimationDuration(0.3)
pulseLayer.transform = CATransform3DMakeScale(2.5, 2.5, 2.5)
layer.transform = CATransform3DMakeScale(1.05, 1.05, 1.05)
CATransaction.commit()
}
/**
:name: touchesEnded
*/
public override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesEnded(touches, withEvent: event)
shrink()
}
/**
:name: touchesCancelled
*/
public override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
super.touchesCancelled(touches, withEvent: event)
shrink()
}
/**
:name: actionForLayer
*/
public override func actionForLayer(layer: CALayer, forKey event: String) -> CAAction? {
return nil // returning nil enables the animations for the layer property that are normally disabled.
}
//
// :name: prepareView
//
internal override func prepareView() {
super.prepareView()
userInteractionEnabled = MaterialTheme.pulseView.userInteractionEnabled
backgroundColor = MaterialTheme.pulseView.backgroudColor
pulseColorOpacity = MaterialTheme.pulseView.pulseColorOpacity
pulseColor = MaterialTheme.pulseView.pulseColor
contentsRect = MaterialTheme.pulseView.contentsRect
contentsCenter = MaterialTheme.pulseView.contentsCenter
contentsScale = MaterialTheme.pulseView.contentsScale
contentsGravity = MaterialTheme.pulseView.contentsGravity
shadowDepth = MaterialTheme.pulseView.shadowDepth
shadowColor = MaterialTheme.pulseView.shadowColor
zPosition = MaterialTheme.pulseView.zPosition
masksToBounds = MaterialTheme.pulseView.masksToBounds
cornerRadius = MaterialTheme.pulseView.cornerRadius
borderWidth = MaterialTheme.pulseView.borderWidth
borderColor = MaterialTheme.pulseView.bordercolor
// touchesLayer
touchesLayer.zPosition = 1000
touchesLayer.masksToBounds = true
layer.addSublayer(touchesLayer)
// pulseLayer
pulseLayer.hidden = true
touchesLayer.addSublayer(pulseLayer)
}
//
// :name: shrink
//
internal func shrink() {
CATransaction.begin()
CATransaction.setAnimationDuration(0.3)
pulseLayer.hidden = true
pulseLayer.transform = CATransform3DIdentity
layer.transform = CATransform3DIdentity
CATransaction.commit()
}
}
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public typealias MaterialRadiusType = CGFloat
public enum MaterialRadius {
case Radius0
case Radius1
case Radius2
case Radius3
case Radius4
}
/**
:name: MaterialRadiusToValue
*/
public func MaterialRadiusToValue(radius: MaterialRadius) -> MaterialRadiusType {
switch radius {
case .Radius0:
return 0
case .Radius1:
return 4
case .Radius2:
return 8
case .Radius3:
return 16
case .Radius4:
return 32
}
}
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
public enum MaterialShape {
case Square
case Circle
}
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public typealias MaterialSizeType = CGFloat
public enum MaterialSize {
case Size0
case Size1
case Size2
case Size3
case Size4
}
/**
:name: MaterialSizeToValue
*/
public func MaterialSizeToValue(size: MaterialSize) -> MaterialSizeType {
switch size {
case .Size0:
return 0
case .Size1:
return 0.5
case .Size2:
return 1
case .Size3:
return 2
case .Size4:
return 3
}
}
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
public enum MaterialStatusBarStyle : Int {
case Default
case LightContent
}
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
@objc(MaterialTextDelegate)
public protocol TextDelegate {
optional func textStorageWillProcessEdit(text: MaterialText, textStorage: MaterialTextStorage, string: String, range: NSRange)
optional func textStorageDidProcessEdit(text: MaterialText, textStorage: MaterialTextStorage, string: String, result: NSTextCheckingResult, flags: NSMatchingFlags, stop: UnsafeMutablePointer<ObjCBool>)
}
@objc(MaterialText)
public class MaterialText: NSObject {
/**
:name: searchPattern
:description: A string representation of the regular expression that matches text within
the TextStorage string property. By default, the search pattern recognizes words and emoji
haracters beginning with hashtags.
*/
public var searchPattern: String = "(^|\\s)#[\\d\\w_\u{203C}\u{2049}\u{20E3}\u{2122}\u{2139}\u{2194}-\u{2199}\u{21A9}-\u{21AA}\u{231A}-\u{231B}\u{23E9}-\u{23EC}\u{23F0}\u{23F3}\u{24C2}\u{25AA}-\u{25AB}\u{25B6}\u{25C0}\u{25FB}-\u{25FE}\u{2600}-\u{2601}\u{260E}\u{2611}\u{2614}-\u{2615}\u{261D}\u{263A}\u{2648}-\u{2653}\u{2660}\u{2663}\u{2665}-\u{2666}\u{2668}\u{267B}\u{267F}\u{2693}\u{26A0}-\u{26A1}\u{26AA}-\u{26AB}\u{26BD}-\u{26BE}\u{26C4}-\u{26C5}\u{26CE}\u{26D4}\u{26EA}\u{26F2}-\u{26F3}\u{26F5}\u{26FA}\u{26FD}\u{2702}\u{2705}\u{2708}-\u{270C}\u{270F}\u{2712}\u{2714}\u{2716}\u{2728}\u{2733}-\u{2734}\u{2744}\u{2747}\u{274C}\u{274E}\u{2753}-\u{2755}\u{2757}\u{2764}\u{2795}-\u{2797}\u{27A1}\u{27B0}\u{2934}-\u{2935}\u{2B05}-\u{2B07}\u{2B1B}-\u{2B1C}\u{2B50}\u{2B55}\u{3030}\u{303D}\u{3297}\u{3299}\u{1F004}\u{1F0CF}\u{1F170}-\u{1F171}\u{1F17E}-\u{1F17F}\u{1F18E}\u{1F191}-\u{1F19A}\u{1F1E7}-\u{1F1EC}\u{1F1EE}-\u{1F1F0}\u{1F1F3}\u{1F1F5}\u{1F1F7}-\u{1F1FA}\u{1F201}-\u{1F202}\u{1F21A}\u{1F22F}\u{1F232}-\u{1F23A}\u{1F250}-\u{1F251}\u{1F300}-\u{1F320}\u{1F330}-\u{1F335}\u{1F337}-\u{1F37C}\u{1F380}-\u{1F393}\u{1F3A0}-\u{1F3C4}\u{1F3C6}-\u{1F3CA}\u{1F3E0}-\u{1F3F0}\u{1F400}-\u{1F43E}\u{1F440}\u{1F442}-\u{1F4F7}\u{1F4F9}-\u{1F4FC}\u{1F500}-\u{1F507}\u{1F509}-\u{1F53D}\u{1F550}-\u{1F567}\u{1F5FB}-\u{1F640}\u{1F645}-\u{1F64F}\u{1F680}-\u{1F68A}]+" {
didSet {
textStorage.searchExpression = NSRegularExpression(pattern: searchPattern, options: nil, error: nil)
}
}
/**
:name: textStorage
:description: Reference to wrapped NSTextStorage
*/
public let textStorage: MaterialTextStorage
/**
:name: delegate
:description: An optional instance of TextDelegate to handle text processing events.
*/
public weak var delegate: TextDelegate?
/**
:name: init
*/
public override init() {
textStorage = MaterialTextStorage()
super.init()
textStorage.searchExpression = NSRegularExpression(pattern: searchPattern, options: nil, error: nil)
textStorage.textStorageWillProcessEdit = { (textStorage: MaterialTextStorage, string: String, range: NSRange) -> Void in
self.delegate?.textStorageWillProcessEdit?(self, textStorage: textStorage, string: string, range: range)
}
textStorage.textStorageDidProcessEdit = { (textStorage: MaterialTextStorage, result: NSTextCheckingResult, flags: NSMatchingFlags, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
self.delegate?.textStorageDidProcessEdit?(self, textStorage: textStorage, string: textStorage.string, result: result, flags: flags, stop: stop)
}
}
/**
:name: string
:description: Managed string value.
*/
public var string: String {
get {
return textStorage.string
}
}
/**
:name: matches
:description: An array of matches found in the TextStorage string property based on the
searchPattern property.
*/
public var matches: Array<String> {
get {
let results: Array<NSTextCheckingResult> = textStorage.searchExpression!.matchesInString(string, options: nil, range: NSMakeRange(0, count(string.utf16))) as! Array<NSTextCheckingResult>
return unique(map(results) {(self.string as NSString).substringWithRange($0.range)})
}
}
/**
:name: unique
:description: Ensures a unique value in the matches return array.
*/
private func unique<S: SequenceType, E: Hashable where E == S.Generator.Element>(source: S) -> [E] {
var seen: [E:Bool] = [:]
return filter(source) {nil == seen.updateValue(true, forKey: $0)}
}
}
\ No newline at end of file
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
internal typealias MaterialTextStorageWillProcessEdit = (MaterialTextStorage, String, NSRange) -> Void
internal typealias MaterialTextStorageDidProcessEdit = (MaterialTextStorage, NSTextCheckingResult, NSMatchingFlags, UnsafeMutablePointer<ObjCBool>) -> Void
public class MaterialTextStorage: NSTextStorage {
/**
:name: store
:description: Acts as the model, storing the string value.
*/
private lazy var store: NSMutableAttributedString = NSMutableAttributedString()
/**
:name: searchExpression
:description: Matches text within the TextStorage string property.
*/
internal var searchExpression: NSRegularExpression?
/**
:name: textStorageWillProcessEdit
:description: If set, this block callback executes when there is a change in the TextStorage
string value.
*/
internal var textStorageWillProcessEdit: MaterialTextStorageWillProcessEdit?
/**
:name: textStorageDidProcessEdit
:description: If set, this block callback executes when a match is detected after a change in
the TextStorage string value.
*/
internal var textStorageDidProcessEdit: MaterialTextStorageDidProcessEdit?
required public init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override public init() {
super.init()
}
/**
:name: string
:description: Managed string value.
*/
override public var string: String {
get {
return store.string
}
}
override public func processEditing() {
let range: NSRange = (string as NSString).paragraphRangeForRange(editedRange)
textStorageWillProcessEdit?(self, string, range)
searchExpression!.enumerateMatchesInString(string, options: nil, range: range) { (result: NSTextCheckingResult!, flags: NSMatchingFlags, stop: UnsafeMutablePointer<ObjCBool>) in
self.textStorageDidProcessEdit?(self, result, flags, stop)
}
super.processEditing()
}
override public func attributesAtIndex(location: Int, effectiveRange range: NSRangePointer) -> [NSObject : AnyObject] {
return store.attributesAtIndex(location, effectiveRange: range)
}
override public func replaceCharactersInRange(range: NSRange, withString str: String) {
store.replaceCharactersInRange(range, withString: str)
edited(NSTextStorageEditActions.EditedCharacters, range: range, changeInLength: count(str.utf16) - range.length)
}
override public func setAttributes(attrs: [NSObject : AnyObject]?, range: NSRange) {
store.setAttributes(attrs, range: range)
edited(NSTextStorageEditActions.EditedAttributes, range: range, changeInLength: 0)
}
}
\ No newline at end of file
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public class MaterialView: UIView {
//
// :name: visualLayer
//
public private(set) lazy var visualLayer: CAShapeLayer = CAShapeLayer()
/**
:name: image
*/
public var image: UIImage? {
didSet {
visualLayer.contents = image?.CGImage
}
}
/**
:name: contentsRect
*/
public var contentsRect: CGRect! {
didSet {
visualLayer.contentsRect = nil == contentsRect ? CGRectMake(0, 0, 1, 1) : contentsRect!
}
}
/**
:name: contentsCenter
*/
public var contentsCenter: CGRect! {
didSet {
visualLayer.contentsCenter = nil == contentsCenter ? CGRectMake(0, 0, 1, 1) : contentsCenter!
}
}
/**
:name: contentsScale
*/
public var contentsScale: CGFloat! {
didSet {
visualLayer.contentsScale = nil == contentsScale ? UIScreen.mainScreen().scale : contentsScale!
}
}
/**
:name: contentsGravity
*/
public var contentsGravity: MaterialGravity! {
didSet {
visualLayer.contentsGravity = MaterialGravityToString(nil == contentsGravity ? .ResizeAspectFill : contentsGravity!)
}
}
/**
:name: backgroundColor
*/
public override var backgroundColor: UIColor? {
get {
return nil == visualLayer.backgroundColor ? nil : UIColor(CGColor: visualLayer.backgroundColor!)
}
set(value) {
visualLayer.backgroundColor = value?.CGColor
}
}
/**
:name: x
*/
public var x: CGFloat {
get {
return frame.origin.x
}
set(value) {
frame.origin.x = value
}
}
/**
:name: y
*/
public var y: CGFloat {
get {
return frame.origin.y
}
set(value) {
frame.origin.y = value
}
}
/**
:name: width
*/
public var width: CGFloat {
get {
return frame.size.width
}
set(value) {
frame.size.width = value
if nil != shape {
frame.size.height = value
prepareShape()
}
}
}
/**
:name: height
*/
public var height: CGFloat {
get {
return frame.size.height
}
set(value) {
frame.size.height = value
if nil != shape {
frame.size.width = value
prepareShape()
}
}
}
/**
:name: shadowColor
*/
public var shadowColor: UIColor! {
didSet {
layer.shadowColor = nil == shadowColor ? MaterialColor.clear.CGColor : shadowColor!.CGColor
}
}
/**
:name: shadowOffset
*/
public var shadowOffset: CGSize! {
didSet {
layer.shadowOffset = nil == shadowOffset ? CGSizeMake(0, 0) : shadowOffset!
}
}
/**
:name: shadowOpacity
*/
public var shadowOpacity: Float! {
didSet {
layer.shadowOpacity = nil == shadowOpacity ? 0 : shadowOpacity!
}
}
/**
:name: shadowRadius
*/
public var shadowRadius: CGFloat! {
didSet {
layer.shadowRadius = nil == shadowRadius ? 0 : shadowRadius!
}
}
/**
:name: masksToBounds
*/
public var masksToBounds: Bool! {
didSet {
visualLayer.masksToBounds = nil == masksToBounds ? false : masksToBounds!
}
}
/**
:name: cornerRadius
*/
public var cornerRadius: MaterialRadius! {
didSet {
layer.cornerRadius = MaterialRadiusToValue(nil == cornerRadius ? .Radius0 : cornerRadius!)
shape = nil
}
}
/**
:name: shape
*/
public var shape: MaterialShape? {
didSet {
if nil != shape {
if width < height {
frame.size.width = height
} else {
frame.size.height = width
}
prepareShape()
}
}
}
/**
:name: borderWidth
*/
public var borderWidth: MaterialBorder! {
didSet {
layer.borderWidth = MaterialBorderToValue(nil == borderWidth ? .Border0 : borderWidth!)
}
}
/**
:name: borderColor
*/
public var borderColor: UIColor! {
didSet {
layer.borderColor = nil == borderColor ? MaterialColor.clear.CGColor : borderColor!.CGColor
}
}
/**
:name: shadowDepth
*/
public var shadowDepth: MaterialDepth! {
didSet {
let value: MaterialDepthType = MaterialDepthToValue(shadowDepth!)
shadowOffset = value.offset
shadowOpacity = value.opacity
shadowRadius = value.radius
}
}
/**
:name: zPosition
*/
public var zPosition: CGFloat! {
didSet {
layer.zPosition = zPosition
}
}
/**
:name: init
*/
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
/**
:name: init
*/
public override init(frame: CGRect) {
super.init(frame: frame)
prepareView()
}
/**
:name: init
*/
public convenience init() {
self.init(frame: CGRectMake(MaterialTheme.view.x, MaterialTheme.view.y, MaterialTheme.view.width, MaterialTheme.view.height))
}
/**
:name: layerClass
*/
public override class func layerClass() -> AnyClass {
return CAShapeLayer.self
}
/**
:name: layoutSubviews
*/
public override func layoutSubviews() {
super.layoutSubviews()
visualLayer.frame = bounds
visualLayer.cornerRadius = layer.cornerRadius
}
//
// :name: prepareView
//
internal func prepareView() {
userInteractionEnabled = MaterialTheme.view.userInteractionEnabled
backgroundColor = MaterialTheme.view.backgroudColor
contentsRect = MaterialTheme.view.contentsRect
contentsCenter = MaterialTheme.view.contentsCenter
contentsScale = MaterialTheme.view.contentsScale
contentsGravity = MaterialTheme.view.contentsGravity
shadowDepth = MaterialTheme.view.shadowDepth
shadowColor = MaterialTheme.view.shadowColor
zPosition = MaterialTheme.view.zPosition
masksToBounds = MaterialTheme.view.masksToBounds
cornerRadius = MaterialTheme.view.cornerRadius
borderWidth = MaterialTheme.view.borderWidth
borderColor = MaterialTheme.view.bordercolor
// visualLayer
visualLayer.zPosition = -1
layer.addSublayer(visualLayer)
}
//
// :name: prepareShape
//
internal func prepareShape() {
layer.cornerRadius = .Square == shape ? 0 : width / 2
}
}
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public class NavigationBarView: MaterialView {
/**
:name: statusBarStyle
*/
public var statusBarStyle: MaterialStatusBarStyle! {
didSet {
UIApplication.sharedApplication().setStatusBarStyle(.LightContent == statusBarStyle ? .LightContent : .Default, animated: true)
}
}
/**
:name: titleInsets
*/
public var titleInsets: MaterialInsets? {
didSet {
titleInsetsRef = nil == titleInsets ? nil : MaterialInsetsToValue(titleInsets!)
}
}
/**
:name: titleInsetsRef
*/
public var titleInsetsRef: MaterialInsetsType! {
didSet {
titleInsetsRef = nil == titleInsetsRef ? (top: 0, left: 0, bottom: 0, right: 0) : titleInsetsRef!
reloadView()
}
}
/**
:name: titleLabel
*/
public var titleLabel: UILabel? {
didSet {
if let v = titleLabel {
v.translatesAutoresizingMaskIntoConstraints = false
}
reloadView()
}
}
/**
:name: leftButtonsInsets
*/
public var leftButtonsInsets: MaterialInsets? {
didSet {
leftButtonsInsetsRef = nil == leftButtonsInsets ? nil : MaterialInsetsToValue(leftButtonsInsets!)
}
}
/**
:name: leftButtonsInsetsRef
*/
public var leftButtonsInsetsRef: MaterialInsetsType! {
didSet {
leftButtonsInsetsRef = nil == leftButtonsInsetsRef ? (top: 0, left: 0, bottom: 0, right: 0) : leftButtonsInsetsRef!
reloadView()
}
}
/**
:name: leftButtons
*/
public var leftButtons: Array<MaterialButton>? {
didSet {
if let v = leftButtons {
for b in v {
b.translatesAutoresizingMaskIntoConstraints = false
}
}
reloadView()
}
}
/**
:name: rightButtonsInsets
*/
public var rightButtonsInsets: MaterialInsets? {
didSet {
rightButtonsInsetsRef = nil == rightButtonsInsets ? nil : MaterialInsetsToValue(rightButtonsInsets!)
}
}
/**
:name: rightButtonsInsetsRef
*/
public var rightButtonsInsetsRef: MaterialInsetsType! {
didSet {
rightButtonsInsetsRef = nil == rightButtonsInsetsRef ? (top: 0, left: 0, bottom: 0, right: 0) : rightButtonsInsetsRef!
reloadView()
}
}
/**
:name: rightButtons
*/
public var rightButtons: Array<MaterialButton>? {
didSet {
if let v = rightButtons {
for b in v {
b.translatesAutoresizingMaskIntoConstraints = false
}
}
reloadView()
}
}
/**
:name: init
*/
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
/**
:name: init
*/
public override init(frame: CGRect) {
super.init(frame: frame)
}
/**
:name: init
*/
public convenience init() {
self.init(frame: CGRectMake(MaterialTheme.navigation.x, MaterialTheme.navigation.y, MaterialTheme.navigation.width, MaterialTheme.navigation.height))
}
/**
:name: init
*/
public convenience init?(titleLabel: UILabel? = nil, leftButtons: Array<MaterialButton>? = nil, rightButtons: Array<MaterialButton>? = nil) {
self.init(frame: CGRectMake(MaterialTheme.navigation.x, MaterialTheme.navigation.y, MaterialTheme.navigation.width, MaterialTheme.navigation.height))
self.prepareProperties(titleLabel, leftButtons: leftButtons, rightButtons: rightButtons)
}
/**
:name: reloadView
*/
public func reloadView() {
// clear constraints so new ones do not conflict
removeConstraints(constraints)
for v in subviews {
v.removeFromSuperview()
}
// leftButtons
if let v = leftButtons {
var h: String = "H:|"
var d: Dictionary<String, AnyObject> = Dictionary<String, AnyObject>()
var i: Int = 0
for b in v {
let k: String = "b\(i++)"
d[k] = b
h += "-(left)-[\(k)]"
insertSubview(b, atIndex: 1)
MaterialLayout.alignFromBottom(self, child: b, bottom: leftButtonsInsetsRef!.bottom)
}
addConstraints(MaterialLayout.constraint(h, options: [], metrics: ["left" : leftButtonsInsetsRef!.left], views: d))
}
// title
if let v = titleLabel {
insertSubview(v, atIndex: 0)
MaterialLayout.alignToParentHorizontallyWithInsets(self, child: v, left: titleInsetsRef!.left, right: titleInsetsRef!.right)
MaterialLayout.alignFromBottom(self, child: v, bottom: titleInsetsRef!.bottom)
}
// rightButtons
if let v = rightButtons {
var h: String = "H:"
var d: Dictionary<String, AnyObject> = Dictionary<String, AnyObject>()
var i: Int = 0
for b in v {
let k: String = "b\(i++)"
d[k] = b
h += "[\(k)]-(right)-"
insertSubview(b, atIndex: 1)
MaterialLayout.alignFromBottom(self, child: b, bottom: rightButtonsInsetsRef!.bottom)
}
addConstraints(MaterialLayout.constraint(h + "|", options: [], metrics: ["right" : rightButtonsInsetsRef!.right], views: d))
}
}
//
// :name: prepareProperties
//
internal func prepareProperties(titleLabel: UILabel?, leftButtons: Array<MaterialButton>?, rightButtons: Array<MaterialButton>?) {
self.titleLabel = titleLabel
self.leftButtons = leftButtons
self.rightButtons = rightButtons
}
//
// :name: prepareView
//
internal override func prepareView() {
super.prepareView()
userInteractionEnabled = MaterialTheme.navigation.userInteractionEnabled
backgroundColor = MaterialTheme.navigation.backgroudColor
statusBarStyle = MaterialTheme.navigation.statusBarStyle
titleInsetsRef = MaterialTheme.navigation.titleInsetsRef
leftButtonsInsetsRef = MaterialTheme.navigation.leftButtonsInsetsRef
rightButtonsInsetsRef = MaterialTheme.navigation.rightButtonsInsetsRef
contentsRect = MaterialTheme.navigation.contentsRect
contentsCenter = MaterialTheme.navigation.contentsCenter
contentsScale = MaterialTheme.navigation.contentsScale
contentsGravity = MaterialTheme.navigation.contentsGravity
shadowDepth = MaterialTheme.navigation.shadowDepth
shadowColor = MaterialTheme.navigation.shadowColor
zPosition = MaterialTheme.navigation.zPosition
masksToBounds = MaterialTheme.navigation.masksToBounds
cornerRadius = MaterialTheme.navigation.cornerRadius
borderWidth = MaterialTheme.navigation.borderWidth
borderColor = MaterialTheme.navigation.bordercolor
}
}
......@@ -20,34 +20,26 @@ import UIKit
public class RaisedButton : MaterialButton {
//
// :name: prepareButton
// :name: prepareView
//
internal override func prepareView() {
internal override func prepareView() {
super.prepareView()
titleLabel!.font = Roboto.medium
setTitleColor(MaterialTheme.white.color, forState: .Normal)
backgroundColor = MaterialTheme.blue.accent2
contentEdgeInsets = UIEdgeInsetsMake(6, 16, 6, 16)
setTitleColor(MaterialTheme.button.raised.titleLabelColorForNormalState, forState: .Normal)
titleLabel!.font = MaterialTheme.button.raised.titleLabelFont
userInteractionEnabled = MaterialTheme.button.raised.userInteractionEnabled
backgroundColor = MaterialTheme.button.raised.backgroudColor
pulseColorOpacity = MaterialTheme.button.raised.pulseColorOpacity
pulseColor = MaterialTheme.button.raised.pulseColor
shadowDepth = MaterialTheme.button.raised.shadowDepth
shadowColor = MaterialTheme.button.raised.shadowColor
zPosition = MaterialTheme.button.raised.zPosition
masksToBounds = MaterialTheme.button.raised.masksToBounds
cornerRadius = MaterialTheme.button.raised.cornerRadius
borderWidth = MaterialTheme.button.raised.borderWidth
borderColor = MaterialTheme.button.raised.bordercolor
contentInsets = MaterialTheme.button.raised.contentInsets
shape = MaterialTheme.button.raised.shape
}
//
// :name: prepareButton
//
internal override func prepareButton() {
super.prepareButton()
prepareShadow()
backgroundColorView.layer.cornerRadius = 3
}
//
// :name: pulseBegan
//
internal override func pulseBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
super.pulseBegan(touches, withEvent: event)
UIView.animateWithDuration(0.3, animations: {
self.pulseView!.transform = CGAffineTransformMakeScale(4, 4)
self.transform = CGAffineTransformMakeScale(1.05, 1.05)
})
}
}
}
\ No newline at end of file
......@@ -18,12 +18,19 @@
import UIKit
public struct Roboto {
public struct RobotoFont : MaterialFontType {
/**
:name: pointSize
*/
public static var pointSize: CGFloat {
return MaterialFont.pointSize
}
/**
:name: thin
*/
public static var thin: UIFont {
return thinWithSize(MaterialTheme.textFontSize)
return thinWithSize(MaterialFont.pointSize)
}
/**
......@@ -33,65 +40,65 @@ public struct Roboto {
if let f = UIFont(name: "Roboto-Thin", size: size) {
return f
}
return UIFont.systemFontOfSize(size)
return MaterialFont.systemFontWithSize(size)
}
/**
:name: light
*/
public static var light: UIFont {
return lightWithSize(MaterialTheme.textFontSize)
return lightWithSize(MaterialFont.pointSize)
}
/**
:name: lightWithSize
*/
public static func lightWithSize(size: CGFloat) -> UIFont {
if let f = UIFont(name: "Roboto-Light", size: size) {
return f
}
return UIFont.systemFontOfSize(size)
}
public static func lightWithSize(size: CGFloat) -> UIFont {
if let f = UIFont(name: "Roboto-Light", size: size) {
return f
}
return MaterialFont.systemFontWithSize(size)
}
/**
:name: regular
*/
public static var regular: UIFont {
return regularWithSize(MaterialTheme.textFontSize)
return regularWithSize(MaterialFont.pointSize)
}
/**
:name: mediumWithSize
:name: regularWithSize
*/
public static func mediumWithSize(size: CGFloat) -> UIFont {
if let f = UIFont(name: "Roboto-Medium", size: size) {
return f
}
return UIFont.systemFontOfSize(size)
}
public static func regularWithSize(size: CGFloat) -> UIFont {
if let f = UIFont(name: "Roboto-Regular", size: size) {
return f
}
return MaterialFont.systemFontWithSize(size)
}
/**
:name: medium
:name: mediumWithSize
*/
public static var medium: UIFont {
return mediumWithSize(MaterialTheme.textFontSize)
public static func mediumWithSize(size: CGFloat) -> UIFont {
if let f = UIFont(name: "Roboto-Medium", size: size) {
return f
}
return MaterialFont.boldSystemFontWithSize(size)
}
/**
:name: regularWithSize
:name: medium
*/
public static func regularWithSize(size: CGFloat) -> UIFont {
if let f = UIFont(name: "Roboto-Regular", size: size) {
return f
}
return UIFont.systemFontOfSize(size)
}
public static var medium: UIFont {
return mediumWithSize(MaterialFont.pointSize)
}
/**
:name: bold
*/
public static var bold: UIFont {
return boldWithSize(MaterialTheme.textFontSize)
return boldWithSize(MaterialFont.pointSize)
}
/**
......@@ -101,6 +108,6 @@ public struct Roboto {
if let f = UIFont(name: "Roboto-Regular", size: size) {
return f
}
return UIFont.systemFontOfSize(size)
return MaterialFont.boldSystemFontWithSize(size)
}
}
}
\ No newline at end of file
//
// Copyright (C) 2015 GraphKit, Inc. <http://graphkit.io> and other GraphKit contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program located at the root of the software package
// in a file called LICENSE. If not, see <http://www.gnu.org/licenses/>.
//
import UIKit
public class TextView: UITextView {
//
// :name: layoutConstraints
//
internal lazy var layoutConstraints: Array<NSLayoutConstraint> = Array<NSLayoutConstraint>()
/**
:name: init
*/
public required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
prepareView()
}
/**
:name: init
*/
public override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
if CGRectZero == frame {
setTranslatesAutoresizingMaskIntoConstraints(false)
}
prepareView()
}
//
// :name: deinit
// :description: Notification observer removed from UITextView.
//
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self, name: UITextViewTextDidChangeNotification, object: nil)
}
/**
:name: placeholder
:description: The placeholder label string.
*/
public var placeholderLabel: UILabel? {
didSet {
if let p = placeholderLabel {
p.setTranslatesAutoresizingMaskIntoConstraints(false)
p.font = font
p.textAlignment = textAlignment
p.numberOfLines = 0
p.backgroundColor = MaterialTheme.clear.color
addSubview(p)
updateLabelConstraints()
textViewTextDidChange()
}
}
}
/**
:name: text
:description: When set, updates the placeholder text.
*/
public override var text: String! {
didSet {
textViewTextDidChange()
}
}
/**
:name: attributedText
:description: When set, updates the placeholder attributedText.
*/
public override var attributedText: NSAttributedString! {
didSet {
textViewTextDidChange()
}
}
/**
:name: textContainerInset
:description: When set, updates the placeholder constraints.
*/
public override var textContainerInset: UIEdgeInsets {
didSet {
updateLabelConstraints()
}
}
public override func layoutSubviews() {
super.layoutSubviews()
placeholderLabel?.preferredMaxLayoutWidth = textContainer.size.width - textContainer.lineFragmentPadding * 2
}
//
// :name: textViewTextDidChange
// :description: Updates the label visibility when text is empty or not.
//
internal func textViewTextDidChange() {
if let p = placeholderLabel {
p.hidden = !text.isEmpty
}
}
//
// :name: prepareView
// :description: Sets up the common initilized values.
//
private func prepareView() {
// label needs to be added to the view
// hierarchy before setting insets
textContainerInset = UIEdgeInsetsMake(16, 16, 16, 16)
backgroundColor = MaterialTheme.clear.color
NSNotificationCenter.defaultCenter().addObserver(self, selector: "textViewTextDidChange", name: UITextViewTextDidChangeNotification, object: nil)
updateLabelConstraints()
}
//
// :name: updateLabelConstraints
// :description: Updates the placeholder constraints.
//
private func updateLabelConstraints() {
if let p = placeholderLabel {
NSLayoutConstraint.deactivateConstraints(layoutConstraints)
layoutConstraints = Layout.constraint("H:|-(left)-[placeholderLabel]-(right)-|",
options: nil,
metrics: [
"left": textContainerInset.left + textContainer.lineFragmentPadding,
"right": textContainerInset.right + textContainer.lineFragmentPadding
], views: [
"placeholderLabel": p
])
layoutConstraints += Layout.constraint("V:|-(top)-[placeholderLabel]-(>=bottom)-|",
options: nil,
metrics: [
"top": textContainerInset.top,
"bottom": textContainerInset.bottom
],
views: [
"placeholderLabel": p
])
NSLayoutConstraint.activateConstraints(layoutConstraints)
}
}
}
......@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>io.graphkit.$(PRODUCT_NAME:rfc1034identifier)</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment