Commit d230c6b3 by Daniel Dahan

working on new example code

parent 0aef3d76
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
961F5F2C1C1726A300C94B43 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 961F5F2B1C1726A300C94B43 /* ViewController.swift */; }; 961F5F2C1C1726A300C94B43 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 961F5F2B1C1726A300C94B43 /* ViewController.swift */; };
961F5F311C1726A300C94B43 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 961F5F301C1726A300C94B43 /* Assets.xcassets */; }; 961F5F311C1726A300C94B43 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 961F5F301C1726A300C94B43 /* Assets.xcassets */; };
961F5F341C1726A300C94B43 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 961F5F321C1726A300C94B43 /* LaunchScreen.storyboard */; }; 961F5F341C1726A300C94B43 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 961F5F321C1726A300C94B43 /* LaunchScreen.storyboard */; };
96607D8B1C3F5795008D47D8 /* MaterialKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96607D8A1C3F5795008D47D8 /* MaterialKit.framework */; };
96607D8C1C3F5795008D47D8 /* MaterialKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 96607D8A1C3F5795008D47D8 /* MaterialKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
...@@ -20,6 +22,7 @@ ...@@ -20,6 +22,7 @@
dstPath = ""; dstPath = "";
dstSubfolderSpec = 10; dstSubfolderSpec = 10;
files = ( files = (
96607D8C1C3F5795008D47D8 /* MaterialKit.framework in Embed Frameworks */,
); );
name = "Embed Frameworks"; name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
...@@ -33,6 +36,7 @@ ...@@ -33,6 +36,7 @@
961F5F301C1726A300C94B43 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; 961F5F301C1726A300C94B43 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
961F5F331C1726A300C94B43 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; 961F5F331C1726A300C94B43 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
961F5F351C1726A300C94B43 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 961F5F351C1726A300C94B43 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
96607D8A1C3F5795008D47D8 /* MaterialKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; name = MaterialKit.framework; path = "/Users/danieldahan/Library/Developer/Xcode/DerivedData/MaterialKit-gdulktuccbcfwbdfadtpxkworhyc/Build/Products/Debug-iphoneos/MaterialKit.framework"; sourceTree = "<absolute>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
...@@ -40,6 +44,7 @@ ...@@ -40,6 +44,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
96607D8B1C3F5795008D47D8 /* MaterialKit.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
...@@ -49,6 +54,7 @@ ...@@ -49,6 +54,7 @@
961F5F1D1C1726A300C94B43 = { 961F5F1D1C1726A300C94B43 = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
96607D8A1C3F5795008D47D8 /* MaterialKit.framework */,
961F5F281C1726A300C94B43 /* MaterialLayout */, 961F5F281C1726A300C94B43 /* MaterialLayout */,
961F5F271C1726A300C94B43 /* Products */, 961F5F271C1726A300C94B43 /* Products */,
); );
......
...@@ -28,6 +28,10 @@ ...@@ -28,6 +28,10 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/**
MaterialLayout
*/
import UIKit import UIKit
import MaterialKit import MaterialKit
...@@ -35,24 +39,16 @@ class ViewController: UIViewController { ...@@ -35,24 +39,16 @@ class ViewController: UIViewController {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
prepareView() prepareView()
// Examples of using MaterialLayout.
prepareAlignToParentHorizontallyExample() prepareAlignToParentHorizontallyExample()
// prepareAlignToParentVerticallyExample() prepareAlignToParentVerticallyExample()
} }
/** /// General preparation methods are placed here.
:name: prepareView
:description: General preparation statements.
*/
private func prepareView() { private func prepareView() {
view.backgroundColor = MaterialColor.white view.backgroundColor = MaterialColor.white
} }
/** /// Layout views horizontally with equal width.
:name: prepareAlignToParentHorizontallyExample
:description: Laying out views horizontally with equal width.
*/
private func prepareAlignToParentHorizontallyExample() { private func prepareAlignToParentHorizontallyExample() {
let label1: UILabel = UILabel() let label1: UILabel = UILabel()
label1.translatesAutoresizingMaskIntoConstraints = false label1.translatesAutoresizingMaskIntoConstraints = false
...@@ -100,10 +96,7 @@ class ViewController: UIViewController { ...@@ -100,10 +96,7 @@ class ViewController: UIViewController {
} }
} }
/** /// Layout views vertically with equal height.
:name: prepareAlignToParentVerticallyExample
:description: Laying out views vertically with equal height.
*/
private func prepareAlignToParentVerticallyExample() { private func prepareAlignToParentVerticallyExample() {
let label1: UILabel = UILabel() let label1: UILabel = UILabel()
label1.translatesAutoresizingMaskIntoConstraints = false label1.translatesAutoresizingMaskIntoConstraints = false
......
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'MK' s.name = 'MK'
s.version = '1.27.11' s.version = '1.27.12'
s.license = 'BSD' s.license = 'BSD'
s.summary = 'Beautiful Material Design in Swift.' s.summary = 'Beautiful Material Design in Swift.'
s.homepage = 'http://materialkit.io' s.homepage = 'http://materialkit.io'
......
![MaterialKit](http://www.materialkit.io/MK/MaterialKit.png) ![GraphKit](http://www.graphkit.io/GK/GraphKit.png)
# Welcome to MaterialKit ## Welcome to GraphKit
MaterialKit is a graphics and animation framework based on Google's Material Design. A major goal in the design of MaterialKit is to allow the creativity of others to easily be expressed. The following README is written to get you started, and is by no means a complete tutorial on all that is possible. Additional examples may be found in the Examples directory that go beyond the README documentation. GraphKit is a data framework. A data framework solves the issue of modeling, mapping, moving, and manipulating data. GraphKit may be used in its simplest form to save and search for data, or it may be used to create robust data-driven applications. What makes GraphKit interesting is in its approach to take the dirty work out of writing algorithms, building recommendations, and driving application behavior.
## Why use GraphKit?
Working with data is complicated and usually left to the end of the application development lifecycle. It takes time to setup models with CoreData and even more time to make changes to that model. To ease the use of data in an application, and to make it more enjoyable, GraphKit removes the complexity and allows developers to focus on the parts they care about.
With GraphKit, it becomes easy to map Entity models, create relationships, and build realtime predictive applications that bring a unique experience to your end user. Data structures within GraphKit have a probability extension that allow search queries to become more than simple dumps of data. All data changes can easily be observed to create a completely reactive experience for users, while easing the development of your application.
## How To Get Started ## How To Get Started
- [Download MaterialKit](https://github.com/CosmicMind/MaterialKit/archive/master.zip). - [Download GraphKit](https://github.com/CosmicMind/GraphKit/archive/master.zip).
- Explore the examples in the Examples directory. - Explore the examples in the Examples directory.
## Communication ## Communication
- If you **need help**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/materialkit). (Tag 'materialkit') - If you **need help**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/graphkit). (Tag 'graphkit')
- If you'd like to **ask a general question**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/materialkit). - If you'd like to **ask a general question**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/graphkit).
- If you **found a bug**, _and can provide steps to reliably reproduce it_, open an issue. - If you **found a bug**, _and can provide steps to reliably reproduce it_, open an issue.
- If you **have a feature request**, open an issue. - If you **have a feature request**, open an issue.
- If you **want to contribute**, submit a pull request. - If you **want to contribute**, submit a pull request.
...@@ -25,16 +31,16 @@ MaterialKit is a graphics and animation framework based on Google's Material Des ...@@ -25,16 +31,16 @@ MaterialKit is a graphics and animation framework based on Google's Material Des
$ gem install cocoapods $ gem install cocoapods
``` ```
> CocoaPods 0.39.0+ is required to build MaterialKit 1.0.0+. > CocoaPods 0.39.0+ is required to build GraphKit 4.0.0+.
To integrate MaterialKit into your Xcode project using CocoaPods, specify it in your `Podfile`: To integrate GraphKit into your Xcode project using CocoaPods, specify it in your `Podfile`:
```ruby ```ruby
source 'https://github.com/CocoaPods/Specs.git' source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0' platform :ios, '8.0'
use_frameworks! use_frameworks!
pod 'MK', '~> 1.0' pod 'GK', '~> 4.0'
``` ```
Then, run the following command: Then, run the following command:
...@@ -53,587 +59,466 @@ You can install Carthage with Homebrew using the following command: ...@@ -53,587 +59,466 @@ You can install Carthage with Homebrew using the following command:
$ brew update $ brew update
$ brew install carthage $ brew install carthage
``` ```
To integrate MaterialKit into your Xcode project using Carthage, specify it in your Cartfile: To integrate GraphKit into your Xcode project using Carthage, specify it in your Cartfile:
```bash ```bash
github "CosmicMind/MaterialKit" github "CosmicMind/GraphKit"
``` ```
Run carthage to build the framework and drag the built MaterialKit.framework into your Xcode project. Run carthage to build the framework and drag the built GraphKit.framework into your Xcode project.
### Changelog ### Changelog
The MaterialKit framework is a fast growing project and will encounter changes throughout its development. It is recommended that the [Changelog](https://github.com/CosmicMind/MaterialKit/wiki/Changelog) be reviewed prior to updating versions. The GraphKit framework is a fast growing project and will encounter changes throughout its development. It is recommended that the [Changelog](https://github.com/CosmicMind/GraphKit/wiki/Changelog) be reviewed prior to updating versions.
### Contents ### A Quick Tour
* [MaterialColor](#materialcolor) * [Entity](#entity)
* [TextField](#textfield) * [Bond](#bond)
* [TextView](#textview) * [Action](#action)
* [MaterialLayer](#materiallayer) * [Groups](#groups)
* [MaterialView](#materialview) * [Probability](#probability)
* [MaterialPulseView](#materialpulseview) * [Data Driven](#datadriven)
* [FlatButton](#flatbutton) * [Faceted Search](#facetedsearch)
* [RaisedButton](#raisedbutton) * [JSON](#json)
* [FabButton](#fabbutton) * [Data Structures](#datastructures)
* [CardView](#cardview) * [DoublyLinkedList](#doublylinkedlist)
* [ImageCardView](#imagecardview) * [Stack](#stack)
* [NavigationBarView](#navigationbarview) * [Queue](#queue)
* [SideNavigationViewController](#sidenavigationviewcontroller) * [Deque](#deque)
* [CaptureView](#captureview) * [RedBlackTree](#redblacktree)
* [SortedSet](#sortedset)
* [SortedMultiSet](#sortedmultiset)
* [SortedDictionary](#sorteddictionary)
* [SortedMultiDictionary](#sortedmultidictionary)
### Upcoming ### Upcoming
* SearchBarView * Example Projects
* SearchBarViewController * Additional Data Structures
* TabView
* TabViewController
* Scrolling Techniques
* Dialogs
* Snackbar
* ProgressBar (circular and horizontal)
* DatePicker
* TimePicker
* More Examples
<a name="materialcolor"></a>
### MaterialColor
Explore a complete range of Material Design colors using MaterialColor. Below is an example of setting a button's background color property. <a name="entity"></a>
### Entity
![MaterialKitMaterialColorPalette](http://www.materialkit.io/MK/MaterialKitMaterialColorPalette.png) An Entity is a model object that represents a person, place, or thing. For example a User, Button, Photo, Video, or Note -- pretty much anything that you would like to objectify. To distinguish between different Entity types, the _type_ instance property is set upon instantiation of a new Entity object. For Example, creating different Entity types is as easy as the code below.
```swift ```swift
let button: FabButton = FabButton() // Create a User Entity type.
button.backgroundColor = MaterialColor.blue.darken1 let user: Entity = Entity(type: "User")
// Create a Book Entity type.
let book: Entity = Entity(type: "Book")
// Create a Photo Entity type.
let photo: Entity = Entity(type: "Photo")
``` ```
<a name="textfield"></a> When a new Entity is created, a record in CoreData is made, which provides a unique _id_ for the object. The Entity is not yet saved, so discarding an Entity does not create any unnecessary overhead.
### TextField
[Learn More About Entity Objects](https://github.com/CosmicMind/GraphKit/wiki/Entity)
A TextField is an excellent way to improve UX. Checkout the Examples directory for a project using this component. <a name="bond"></a>
### Bond
![MaterialKitTextField](http://www.materialkit.io/MK/MaterialKitTextField.gif) A Bond is a model object that represents a relationship between two [Entity](https://github.com/CosmicMind/GraphKit/wiki/Entity) objects. To distinguish between different Bond types, the _type_ instance property is set upon instantiation of a new Bond object. To form meaningful relationships, sentence structures are used, with a _subject_ and _object_ that form the relationship. For example, we have two Entity types, a User and a Book. The User is the Author of the Book, so how is this modeled? In a sentence it would be, _User is Author of Book_. The User is the _subject_ in this case, and the _object_ is the Book. In code, the following is how this would be modeled.
```swift
// Create a User Entity type.
let user: Entity = Entity(type: "User")
// Create a Book Entity type.
let book: Entity = Entity(type: "Book")
// Create an Author Bond type.
let author: Bond = Bond(type: "Author")
// Make the relationship.
author.subject = user
author.object = book
```
Another way to think of this relationship through a sentence structure is, _the Book was Written by the User_. So now the Book is the _subject_, the User is the _object_, and Written is the relationship. In code, our example now looks like the following.
```swift ```swift
let textField: TextField = TextField(frame: CGRectMake(57, 100, 300, 24)) // Create a Written Bond type.
textField.placeholder = "First Name" let written: Bond = Bond(type: "Written")
textField.font = RobotoFont.regularWithSize(20)
textField.textColor = MaterialColor.black // Make the relationship.
textField.titleLabel = UILabel() written.subject = book
textField.titleLabel!.font = RobotoFont.mediumWithSize(12) written.object = user
textField.titleLabelColor = MaterialColor.grey.lighten1
textField.titleLabelActiveColor = MaterialColor.blue.accent3
textField.clearButtonMode = .WhileEditing
view.addSubview(textField)
// Add nameField to UIViewController.
view.addSubview(nameField)
``` ```
Although both would work.
[Learn More About Bond Objects](https://github.com/CosmicMind/GraphKit/wiki/Bond)
<a name="textview"></a> <a name="action"></a>
### TextView ### Action
Easily match any regular expression pattern in a body of text. Below is an example of the default hashtag pattern matching. An Action is used to form a relationship between many Entity Objects. Like an Entity, an Action also has a type property that specifies the collection to which it belongs to. An Action's relationship structure is like a sentence, in that it relates a collection of Subjects to a collection of Objects. Below is an example of a User purchasing many Books. It may be thought of as "User Purchased these Book(s)."
![MaterialKitTextView](http://www.materialkit.io/MK/MaterialKitTextView.gif) ```swift
let graph: Graph = Graph()
Checkout the Examples Programmatic directory for a sample project using this wonderful component. let user: Entity = Entity(type: "User")
let books: Array<Entity> = graph.searchForEntity(types: ["Book"])
<a name="materiallayer"></a> let purchased: Action = Action(type: "Purchased")
### MaterialLayer purchased.addSubject(user)
MaterialLayer is a lightweight CAShapeLayer used throughout MaterialKit. It is designed to easily take shape, depth, and animations. Below is an example demonstrating the ease of adding shape and depth to MaterialLayer. for book in books {
purchased.addObject(book)
}
![MaterialKitMaterialLayer](http://www.materialkit.io/MK/MaterialKitMaterialLayer.gif) graph.save()
```
<a name="groups"></a>
### Groups
Groups are used to organize Entities, Bonds, and Actions into different collections from their types. This allows multiple types to exist in a single collection. For example, a Photo and Video Entity type may exist in a group called Media. Another example may be including a Photo and Book Entity type in a Favorites group for your users' account. Below are examples of using groups.
```swift ```swift
let materialLayer: MaterialLayer = MaterialLayer(frame: CGRectMake(132, 132, 150, 150)) let photo: Entity = Entity(type: "Photo")
materialLayer.image = UIImage(named: "CosmicMindAppIcon") photo.addGroup("Media")
materialLayer.shape = .Circle photo.addGroup("Favorites")
materialLayer.shadowDepth = .Depth2 photo.addGroup("Holiday Album")
let video: Entity = Entity(type: "Video")
video.addGroup("Media")
// Add layer to UIViewController. let book: Entity = Entity(type: "Book")
view.layer.addSublayer(materialLayer) book.addGroup("Favorites")
book.addGroup("To Read")
// Searching groups.
let favorites: Array<Entity> = graph.searchForEntity(groups: ["Favorites"])
``` ```
<a name="materialview"></a> <a name="probability"></a>
### MaterialView ### Probability
MaterialView is the base UIView class used throughout MaterialKit. Like MaterialLayer, it is designed to easily take shape, depth, and animations. The major difference is that MaterialView has all the added features of the UIView class. Below is an example of setting a MaterialView's cornerRadius, shape, and depth. Probability is a core feature within GraphKit. Your application may be completely catered to your users' habits and usage. To demonstrate this wonderful feature, let's look at some examples:
![MaterialKitMaterialView](http://www.materialkit.io/MK/MaterialKitMaterialView.gif) Determining the probability of rolling a 3 using a die of 6 numbers.
```swift ```swift
let materialView: MaterialView = MaterialView(frame: CGRectMake(132, 132, 150, 150)) let die: Array<Int> = Array<Int>(arrayLiteral: 1, 2, 3, 4, 5, 6)
materialView.image = UIImage(named: "FocusAppIcon") print(die.probabilityOf(3)) // Output: 0.166666666666667
materialView.shape = .Square
materialView.shadowDepth = .Depth2
materialView.cornerRadius = .Radius3
// Add view to UIViewController.
view.addSubview(materialView)
``` ```
<a name="materialpulseview"></a> The expected value of rolling a 3 or 6 with 100 trials using a die of 6 numbers.
### MaterialPulseView
MaterialPulseView is at the heart of all pulse animations. Any view that subclasses MaterialPulseView instantly inherits the pulse animation with full customizability. ```swift
let die: Array<Int> = Array<Int>(arrayLiteral: 1, 2, 3, 4, 5, 6)
print(die.expectedValueOf(100, elements: 3, 6)) // Output: 33.3333333333333
```
![MaterialKitMaterialPulseView](http://www.materialkit.io/MK/MaterialKitMaterialPulseView.gif) Recommending a Physics book if the user is likely to buy a Physics book.
```swift ```swift
let materialPulseView: MaterialPulseView = MaterialPulseView(frame: CGRectMake(132, 132, 150, 150)) let purchased: Array<Action> = graph.searchForAction(types: ["Purchased"])
materialPulseView.image = UIImage(named: "ContentAppIcon")
materialPulseView.shape = .Circle let pOfX: Double = purchased.probabilityOf { (action: Action) in
materialPulseView.shadowDepth = .Depth2 if let entity: Entity = action.objects.first {
if "Book" == entity.type {
return entity.hasGroup("Physics")
}
}
return false
}
if 33.33 < pOfX {
// Recommend a Physics book.
}
```
<a name="datadriven"></a>
### Data Driven
As data moves through your application, the state of information may be observed to create a reactive experience. Below is an example of watching when a "User Clicked a Button".
// Add view to UIViewController. ```swift
view.addSubview(materialPulseView) // Set the UIViewController's Protocol to GraphDelegate.
let graph: Graph = Graph()
graph.delegate = self
graph.watchForAction(types: ["Clicked"])
let user: Entity = Entity(type: "User")
let clicked: Action = Action(type: "Clicked")
let button: Entity = Entity(type: "Button")
clicked.addSubject(user)
clicked.addObject(button)
graph.save()
// Delegate method.
func graphDidInsertAction(graph: Graph, action: Action) {
switch(action.type) {
case "Clicked":
print(action.subjects.first?.type) // User
print(action.objects.first?.type) // Button
case "Swiped":
// Handle swipe.
default:break
}
}
``` ```
<a name="flatbutton"></a> <a name="facetedsearch"></a>
### FlatButton ### Faceted Search
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. To explore the intricate relationships within the Graph, the search API adopts a faceted design. This allows the exploration of your data through any view point. The below examples show how to use the Graph search API:
![MaterialKitFlatButton](http://www.materialkit.io/MK/MaterialKitFlatButton.gif) Searching multiple Entity types.
```swift ```swift
let button: FlatButton = FlatButton(frame: CGRectMake(107, 107, 200, 65)) let collection: Array<Entity> = graph.searchForEntity(types: ["Photo", "Video"])
button.setTitle("Flat", forState: .Normal)
button.titleLabel!.font = RobotoFont.mediumWithSize(32)
// Add to UIViewController.
view.addSubview(button)
``` ```
<a name="raisedbutton"></a> Searching multiple Entity groups.
### RaisedButton
A RaisedButton is sure to get attention. Take a look at the following animation example. ```swift
let collection: Array<Entity> = graph.searchForEntity(groups: ["Media", "Favorites"])
```
![MaterialKitRaisedButton](http://www.materialkit.io/MK/MaterialKitRaisedButton.gif) Searching multiple Entity properties.
```swift ```swift
let button: RaisedButton = RaisedButton(frame: CGRectMake(107, 207, 200, 65)) let collection: Array<Entity> = graph.searchForEntity(properties: [(key: "name", value: "Eve"), ("age", 27)])
button.setTitle("Raised", forState: .Normal) ```
button.titleLabel!.font = RobotoFont.mediumWithSize(32)
Searching multiple facets simultaneously will aggregate all results into a single collection.
// Add to UIViewController. ```swift
view.addSubview(button) let collection: Array<Entity> = graph.searchForEntity(types: ["Photo", "Friends"], groups: ["Media", "Favorites"])
``` ```
<a name="fabbutton"></a> Filters may be used to narrow in on a search result. For example, searching a book title and group within purchases.
### FabButton
A FabButton is essential to Material Design's overall look. Below showcases its beauty. ```swift
let collection: Array<Action> = graph.searchForAction(types: ["Purchased"]).filter { (action: Action) -> Bool in
if let entity: Entity = action.objects.first {
if "Book" == entity.type && "The Holographic Universe" == entity["title"] as? String {
return entity.hasGroup("Physics")
}
}
return false
}
```
<a name="json"></a>
### JSON
![MaterialKitFabButton](http://www.materialkit.io/MK/MaterialKitFabButton.gif) JSON is a widely used format for serializing data. GraphKit comes with a JSON toolset. Below are some examples of its usage.
```swift ```swift
let img: UIImage? = UIImage(named: "ic_create_white") // Serialize Dictionary.
let button: FabButton = FabButton(frame: CGRectMake(175, 315, 64, 64)) let data: NSData? = JSON.serialize(["user": ["username": "daniel", "password": "abc123", "token": 123456789]])
button.setImage(img, forState: .Normal)
button.setImage(img, forState: .Highlighted)
// Add to UIViewController. // Parse NSData.
view.addSubview(button) let j1: JSON? = JSON.parse(data!)
print(j1?["user"]?["username"]?.asString) // Output: "daniel"
// Stringify.
let stringified: String? = JSON.stringify(j1!)
print(stringified) // Output: "{\"user\":{\"password\":\"abc123\",\"token\":123456789,\"username\":\"daniel\"}}"
// Parse String.
let j2: JSON? = JSON.parse(stringified!)
print(j2?["user"]?["token"]?.asInt) // Output: 123456789
``` ```
<a name="cardview"></a> <a name="datastructures"></a>
### CardView ### Data Structures
GraphKit comes packed with some powerful data structures to help write algorithms. The following structures are included: DoublyLinkedList, Stack, Queue, Deque, RedBlackTree, SortedSet, SortedMultiSet, SortedDictionary, and SortedMultiDictionary.
Right out of the box to a fully customizable configuration, CardView always stands out. Take a look at a few examples in action and find more in the Examples directory. <a name="doublylinkedlist"></a>
### DoublyLinkedList
![MaterialKitCardView](http://www.materialkit.io/MK/MaterialKitCardView.gif) The DoublyLinkedList data structure is excellent for large growing collections of data. Below is an example of its usage.
```swift ```swift
let cardView: CardView = CardView() let listA: DoublyLinkedList<Int> = DoublyLinkedList<Int>()
listA.insertAtFront(3)
// Title label. listA.insertAtFront(2)
let titleLabel: UILabel = UILabel() listA.insertAtFront(1)
titleLabel.text = "Welcome Back!"
titleLabel.textColor = MaterialColor.blue.darken1 let listB: DoublyLinkedList<Int> = DoublyLinkedList<Int>()
titleLabel.font = RobotoFont.mediumWithSize(20) listB.insertAtBack(4)
cardView.titleLabel = titleLabel listB.insertAtBack(5)
listB.insertAtBack(6)
// Detail label.
let detailLabel: UILabel = UILabel() let listC: DoublyLinkedList<Int> = listA + listB
detailLabel.text = "It’s been a while, have you read any new books lately?"
detailLabel.numberOfLines = 0 listC.cursorToFront()
cardView.detailLabel = detailLabel repeat {
print(listC.cursor)
// Yes button. } while nil != listC.next
let btn1: FlatButton = FlatButton() // Output:
btn1.pulseColor = MaterialColor.blue.lighten1 // 1
btn1.pulseFill = true // 2
btn1.pulseScale = false // 3
btn1.setTitle("YES", forState: .Normal) // 4
btn1.setTitleColor(MaterialColor.blue.darken1, forState: .Normal) // 5
// 6
// No button.
let btn2: FlatButton = FlatButton()
btn2.pulseColor = MaterialColor.blue.lighten1
btn2.pulseFill = true
btn2.pulseScale = false
btn2.setTitle("NO", forState: .Normal)
btn2.setTitleColor(MaterialColor.blue.darken1, forState: .Normal)
// Add buttons to left side.
cardView.leftButtons = [btn1, btn2]
// To support orientation changes, use MaterialLayout.
view.addSubview(cardView)
cardView.translatesAutoresizingMaskIntoConstraints = false
MaterialLayout.alignFromTop(view, child: cardView, top: 100)
MaterialLayout.alignToParentHorizontally(view, child: cardView, left: 20, right: 20)
``` ```
Easily remove the pulse animation and add a background image for an entirely new feel. <a name="stack"></a>
### Stack
![MaterialKitCardViewFavorite](http://www.materialkit.io/MK/MaterialKitCardViewFavorite.gif) The Stack data structure is a container of objects that are inserted and removed according to the last-in-first-out (LIFO) principle. Below is an example of its usage.
```swift ```swift
let cardView: CardView = CardView() let stack: Stack<Int> = Stack<Int>()
cardView.divider = false stack.push(1)
cardView.backgroundColor = MaterialColor.red.darken1 stack.push(2)
cardView.pulseScale = false stack.push(3)
cardView.pulseColor = nil
while !stack.isEmpty {
cardView.image = UIImage(named: "iTunesArtwork")?.resize(toWidth: 400) print(stack.pop())
cardView.contentsGravity = .BottomRight }
// Output:
// Title label. // 3
let titleLabel: UILabel = UILabel() // 2
titleLabel.text = "MaterialKit" // 1
titleLabel.textColor = MaterialColor.white
titleLabel.font = RobotoFont.mediumWithSize(24)
cardView.titleLabel = titleLabel
// Detail label.
let detailLabel: UILabel = UILabel()
detailLabel.text = "Build beautiful software."
detailLabel.textColor = MaterialColor.white
detailLabel.numberOfLines = 0
cardView.detailLabel = detailLabel
// Favorite button.
let img1: UIImage? = UIImage(named: "ic_favorite_white")
let btn1: FlatButton = FlatButton()
btn1.pulseColor = MaterialColor.white
btn1.pulseFill = true
btn1.pulseScale = false
btn1.setImage(img1, forState: .Normal)
btn1.setImage(img1, forState: .Highlighted)
// Add buttons to left side.
cardView.leftButtons = [btn1]
// To support orientation changes, use MaterialLayout.
view.addSubview(cardView)
cardView.translatesAutoresizingMaskIntoConstraints = false
MaterialLayout.alignFromTop(view, child: cardView, top: 100)
MaterialLayout.alignToParentHorizontally(view, child: cardView, left: 20, right: 20)
``` ```
Adjust the alignment of the UI elements to create different configurations of the CardView. <a name="queue"></a>
### Queue
![MaterialKitCardViewDataDriven](http://www.materialkit.io/MK/MaterialKitCardViewDataDriven.gif) The Queue data structure is a container of objects that are inserted and removed according to the first-in-first-out (FIFO) principle. Below is an example of its usage.
```swift ```swift
let cardView: CardView = CardView() let queue: Queue<Int> = Queue<Int>()
cardView.dividerInset.left = 100 queue.enqueue(1)
cardView.titleLabelInset.left = 100 queue.enqueue(2)
cardView.detailLabelInset.left = 100 queue.enqueue(3)
cardView.pulseColor = MaterialColor.teal.lighten4
while !queue.isEmpty {
// Image. print(queue.dequeue())
cardView.image = UIImage(named: "GraphKit") }
cardView.contentsGravity = .TopLeft // Output:
// 1
// Title label. // 2
let titleLabel: UILabel = UILabel() // 3
titleLabel.text = "GraphKit"
titleLabel.font = RobotoFont.mediumWithSize(24)
cardView.titleLabel = titleLabel
// Detail label.
let detailLabel: UILabel = UILabel()
detailLabel.text = "Build scalable data-driven apps."
detailLabel.numberOfLines = 0
cardView.detailLabel = detailLabel
// LEARN MORE button.
let btn1: FlatButton = FlatButton()
btn1.pulseColor = MaterialColor.teal.lighten1
btn1.pulseFill = true
btn1.pulseScale = false
btn1.setTitle("LEARN MORE", forState: .Normal)
btn1.setTitleColor(MaterialColor.teal.darken1, forState: .Normal)
// Add buttons to right side.
cardView.rightButtons = [btn1]
// To support orientation changes, use MaterialLayout.
view.addSubview(cardView)
cardView.translatesAutoresizingMaskIntoConstraints = false
MaterialLayout.alignFromTop(view, child: cardView, top: 100)
MaterialLayout.alignToParentHorizontally(view, child: cardView, left: 20, right: 20)
``` ```
CardViews are so flexible they create entirely new components by removing all but certain elements. For example, bellow is a button bar by only setting the button values of the CardView. <a name="deque"></a>
### Deque
![MaterialKitCardViewButtonBar](http://www.materialkit.io/MK/MaterialKitCardViewButtonBar.gif) The Deque data structure is a container of objects that are inserted and removed according to the first-in-first-out (FIFO) and last-in-first-out (LIFO) principle. Essentially, a Deque is a Stack and Queue combined. Below are examples of its usage.
```swift ```swift
let cardView: CardView = CardView() let dequeA: Deque<Int> = Deque<Int>()
cardView.divider = false dequeA.insertAtBack(1)
cardView.pulseColor = nil dequeA.insertAtBack(2)
cardView.pulseScale = false dequeA.insertAtBack(3)
cardView.backgroundColor = MaterialColor.blueGrey.darken4
while !dequeA.isEmpty {
// Favorite button. print(dequeA.removeAtFront())
let img1: UIImage? = UIImage(named: "ic_search_white") }
let btn1: FlatButton = FlatButton() // Output:
btn1.pulseColor = MaterialColor.white // 1
btn1.pulseFill = true // 2
btn1.pulseScale = false // 3
btn1.setImage(img1, forState: .Normal)
btn1.setImage(img1, forState: .Highlighted) let dequeB: Deque<Int> = Deque<Int>()
dequeB.insertAtBack(4)
// BUTTON 1 button. dequeB.insertAtBack(5)
let btn2: FlatButton = FlatButton() dequeB.insertAtBack(6)
btn2.pulseColor = MaterialColor.teal.lighten3
btn2.pulseFill = true while !dequeB.isEmpty {
btn2.pulseScale = false print(dequeB.removeAtBack())
btn2.setTitle("BUTTON 1", forState: .Normal) }
btn2.setTitleColor(MaterialColor.teal.lighten3, forState: .Normal) // Output:
btn2.titleLabel!.font = RobotoFont.regularWithSize(20) // 6
// 5
// BUTTON 2 button. // 4
let btn3: FlatButton = FlatButton()
btn3.pulseColor = MaterialColor.teal.lighten3
btn3.pulseFill = true
btn3.pulseScale = false
btn3.setTitle("BUTTON 2", forState: .Normal)
btn3.setTitleColor(MaterialColor.teal.lighten3, forState: .Normal)
btn3.titleLabel!.font = RobotoFont.regularWithSize(20)
// Add buttons to left side.
cardView.leftButtons = [btn1]
// Add buttons to right side.
cardView.rightButtons = [btn2, btn3]
// To support orientation changes, use MaterialLayout.
view.addSubview(cardView)
cardView.translatesAutoresizingMaskIntoConstraints = false
MaterialLayout.alignFromTop(view, child: cardView, top: 100)
MaterialLayout.alignToParentHorizontally(view, child: cardView, left: 20, right: 20)
``` ```
<a name="imagecardview"></a> <a name="redblacktree"></a>
### ImageCardView ### RedBlackTree
Bold and attractive, ImageCardView is the next step from a CardView. In the Examples folder you will find examples using the ImageCardView. Below are some animations to give you an idea of the possibilities the ImageCardView has to offer. A RedBlackTree is a Balanced Binary Search Tree that maintains insert, remove, update, and search operations in a complexity of O(logn). The GraphKit implementation of a RedBlackTree also includes an order-statistic, which allows the data structure to be accessed using subscripts like an array or dictionary. RedBlackTrees may store unique keys or non-unique key values. Below is an example of its usage.
![MaterialKitImageCardView](http://www.materialkit.io/MK/MaterialKitImageCardView.gif)
```swift ```swift
let imageCardView: ImageCardView = ImageCardView() let rbA: RedBlackTree<Int, Int> = RedBlackTree<Int, Int>(uniqueKeys: true)
// Image. for var i: Int = 1000; 0 < i; --i {
let size: CGSize = CGSizeMake(UIScreen.mainScreen().bounds.width - CGFloat(40), 150) rbA.insert(1, value: 1)
imageCardView.image = UIImage.imageWithColor(MaterialColor.cyan.darken1, size: size) rbA.insert(2, value: 2)
rbA.insert(3, value: 3)
// Title label. }
let titleLabel: UILabel = UILabel() print(rbA.count) // Output: 3
titleLabel.text = "Welcome Back!"
titleLabel.textColor = MaterialColor.white
titleLabel.font = RobotoFont.mediumWithSize(24)
imageCardView.titleLabel = titleLabel
imageCardView.titleLabelInset.top = 100
// Detail label.
let detailLabel: UILabel = UILabel()
detailLabel.text = "It’s been a while, have you read any new books lately?"
detailLabel.numberOfLines = 0
imageCardView.detailLabel = detailLabel
// Yes button.
let btn1: FlatButton = FlatButton()
btn1.pulseColor = MaterialColor.cyan.lighten1
btn1.pulseFill = true
btn1.pulseScale = false
btn1.setTitle("YES", forState: .Normal)
btn1.setTitleColor(MaterialColor.cyan.darken1, forState: .Normal)
// No button.
let btn2: FlatButton = FlatButton()
btn2.pulseColor = MaterialColor.cyan.lighten1
btn2.pulseFill = true
btn2.pulseScale = false
btn2.setTitle("NO", forState: .Normal)
btn2.setTitleColor(MaterialColor.cyan.darken1, forState: .Normal)
// Add buttons to left side.
imageCardView.leftButtons = [btn1, btn2]
// To support orientation changes, use MaterialLayout.
view.addSubview(imageCardView)
imageCardView.translatesAutoresizingMaskIntoConstraints = false
MaterialLayout.alignFromTop(view, child: imageCardView, top: 100)
MaterialLayout.alignToParentHorizontally(view, child: imageCardView, left: 20, right: 20)
``` ```
Remove elements, such as details to create a fresh look for your images. <a name="sortedset"></a>
### SortedSet
![MaterialKitImageCardViewBackgroundImage](http://www.materialkit.io/MK/MaterialKitImageCardViewBackgroundImage.gif) SortedSets are a powerful data structure for algorithm and analysis design. Elements within a SortedSet are unique and insert, remove, and search operations have a complexity of O(logn). The GraphKit implementation of a SortedSet also includes an order-statistic, which allows the data structure to be accessed using an index subscript like an array. Below are examples of its usage.
```swift ```swift
let imageCardView: ImageCardView = ImageCardView() let graph: Graph = Graph()
imageCardView.divider = false
// Image.
imageCardView.image = UIImage(named: "MaterialKitImageCardViewBackgroundImage")
// Title label.
let titleLabel: UILabel = UILabel()
titleLabel.text = "Material Design"
titleLabel.textColor = MaterialColor.white
titleLabel.font = RobotoFont.regularWithSize(24)
imageCardView.titleLabel = titleLabel
imageCardView.titleLabelInset.top = 80
// Star button.
let img1: UIImage? = UIImage(named: "ic_star_grey_darken_2")
let btn1: FlatButton = FlatButton()
btn1.pulseColor = MaterialColor.blueGrey.lighten1
btn1.pulseFill = true
btn1.pulseScale = false
btn1.setImage(img1, forState: .Normal)
btn1.setImage(img1, forState: .Highlighted)
// Favorite button.
let img2: UIImage? = UIImage(named: "ic_favorite_grey_darken_2")
let btn2: FlatButton = FlatButton()
btn2.pulseColor = MaterialColor.blueGrey.lighten1
btn2.pulseFill = true
btn2.pulseScale = false
btn2.setImage(img2, forState: .Normal)
btn2.setImage(img2, forState: .Highlighted)
// Share button.
let img3: UIImage? = UIImage(named: "ic_share_grey_darken_2")
let btn3: FlatButton = FlatButton()
btn3.pulseColor = MaterialColor.blueGrey.lighten1
btn3.pulseFill = true
btn3.pulseScale = false
btn3.setImage(img3, forState: .Normal)
btn3.setImage(img3, forState: .Highlighted)
// Add buttons to right side.
imageCardView.rightButtons = [btn1, btn2, btn3]
// To support orientation changes, use MaterialLayout.
view.addSubview(imageCardView)
imageCardView.translatesAutoresizingMaskIntoConstraints = false
MaterialLayout.alignFromTop(view, child: imageCardView, top: 100)
MaterialLayout.alignToParentHorizontally(view, child: imageCardView, left: 20, right: 20)
```
<a name="navigationbarview"></a> let setA: SortedSet<Bond> = SortedSet<Bond>(elements: graph.searchForBond(types: ["Author"]))
### NavigationBarView let setB: SortedSet<Bond> = SortedSet<Bond>(elements: graph.searchForBond(types: ["Director"]))
One of Material Design's greatest additions to UI is the NavigationBarView. In the Examples folder, you can checkout some code to get you started with this wonderful component. let setC: SortedSet<Entity> = SortedSet<Entity>(elements: graph.searchForEntity(groups: ["Physics"]))
let setD: SortedSet<Entity> = SortedSet<Entity>(elements: graph.searchForEntity(groups: ["Math"]))
![MaterialKitNavigationBarView](http://www.materialkit.io/MK/MaterialKitNavigationBarView.gif) let setE: SortedSet<Entity> = SortedSet<Entity>(elements: graph.searchForEntity(types: ["User"]))
```swift // Union.
let navigationBarView: NavigationBarView = NavigationBarView() print((setA + setB).count) // Output: 3
print(setA.union(setB).count) // Output: 3
// Stylize.
navigationBarView.backgroundColor = MaterialColor.indigo.darken1 // Intersect.
print(setC.intersect(setD).count) // Output: 1
// To lighten the status bar add the "View controller-based status bar appearance = NO"
// to your info.plist file and set the following property. // Subset.
navigationBarView.statusBarStyle = .LightContent print(setD < setC) // true
print(setD.isSubsetOf(setC)) // true
// Title label.
let titleLabel: UILabel = UILabel() // Superset.
titleLabel.text = "MaterialKit" print(setD > setC) // false
titleLabel.textAlignment = .Left print(setD.isSupersetOf(setC)) // false
titleLabel.textColor = MaterialColor.white
titleLabel.font = RobotoFont.regularWithSize(20) // Contains.
navigationBarView.titleLabel = titleLabel print(setE.contains(setA.first!.subject!)) // true
navigationBarView.titleLabelInset.left = 64
// Probability.
// Detail label. print(setE.probabilityOf(setA.first!.subject!, setA.last!.subject!)) // 0.666666666666667
let detailLabel: UILabel = UILabel()
detailLabel.text = "Build Beautiful Software"
detailLabel.textAlignment = .Left
detailLabel.textColor = MaterialColor.white
detailLabel.font = RobotoFont.regularWithSize(12)
navigationBarView.detailLabel = detailLabel
navigationBarView.detailLabelInset.left = 64
// Menu button.
let img1: UIImage? = UIImage(named: "ic_menu_white")
let btn1: FlatButton = FlatButton()
btn1.pulseColor = MaterialColor.white
btn1.pulseFill = true
btn1.pulseScale = false
btn1.setImage(img1, forState: .Normal)
btn1.setImage(img1, forState: .Highlighted)
// Star button.
let img2: UIImage? = UIImage(named: "ic_star_white")
let btn2: FlatButton = FlatButton()
btn2.pulseColor = MaterialColor.white
btn2.pulseFill = true
btn2.pulseScale = false
btn2.setImage(img2, forState: .Normal)
btn2.setImage(img2, forState: .Highlighted)
// Search button.
let img3: UIImage? = UIImage(named: "ic_search_white")
let btn3: FlatButton = FlatButton()
btn3.pulseColor = MaterialColor.white
btn3.pulseFill = true
btn3.pulseScale = false
btn3.setImage(img3, forState: .Normal)
btn3.setImage(img3, forState: .Highlighted)
// Add buttons to left side.
navigationBarView.leftButtons = [btn1]
// Add buttons to right side.
navigationBarView.rightButtons = [btn2, btn3]
// To support orientation changes, use MaterialLayout.
view.addSubview(navigationBarView)
navigationBarView.translatesAutoresizingMaskIntoConstraints = false
MaterialLayout.alignFromTop(view, child: navigationBarView)
MaterialLayout.alignToParentHorizontally(view, child: navigationBarView)
MaterialLayout.height(view, child: navigationBarView, height: 70)
``` ```
<a name="sidenavigationviewcontroller"></a> <a name="sortedmultiset"></a>
### SideNavigationViewController ### SortedMultiSet
A SortedMultiSet is identical to a SortedSet, except that a SortedMultiSet allows non-unique elements. Look at [SortedSet](#sortedset) for examples of its usage.
<a name="sorteddictionary"></a>
### SortedDictionary
As elegant as is effective, the SideNavigationViewController is an excellent way to organize your app. In the Examples directory, there is an example project using this wonderful component. A SortedDictionary is a powerful data structure that maintains a sorted set of keys with value pairs. Keys within a SortedDictionary are unique and insert, remove, update, and search operations have a complexity of O(logn).
![MaterialKitSideNavigationViewController](http://www.materialkit.io/MK/MaterialKitSideNavigationViewController.gif) <a name="sortedmultidictionary"></a>
### SortedMultiDictionary
<a name="captureview"></a> A SortedMultiDictionary is identical to a SortedDictionary, except that a SortedMultiDictionary allows non-unique keys. Below is an example of its usage.
### CaptureView
Add a new dimension of interactivity with CaptureView. CaptureView is a fully functional camera that is completely customizable. ```swift
let graph: Graph = Graph()
let students: Array<Entity> = graph.searchForEntity(types: ["Student"])
![MaterialKitCaptureView](http://www.materialkit.io/MK/MaterialKitCaptureView.jpg) let dict: SortedMultiDictionary<String, Entity> = SortedMultiDictionary<String, Entity>()
Checkout the Examples Programmatic directory for a sample project using this wonderful component. // Do something with an alphabetically SortedMultiDictionary of student Entity Objects.
for student in students {
dict.insert(student["name"] as! String, value: student)
}
```
### License ### License
...@@ -648,7 +533,7 @@ Redistribution and use in source and binary forms, with or without modification, ...@@ -648,7 +533,7 @@ Redistribution and use in source and binary forms, with or without modification,
this list of conditions and the following disclaimer in the documentation this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution. and/or other materials provided with the distribution.
* Neither the name of MaterialKit nor the names of its * Neither the name of GraphKit nor the names of its
contributors may be used to endorse or promote products derived from contributors may be used to endorse or promote products derived from
this software without specific prior written permission. this software without specific prior written permission.
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>FMWK</string> <string>FMWK</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.27.11</string> <string>1.27.12</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</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