diff --git a/docs/_docs/automatic-subnode-mgmt.md b/docs/_docs/automatic-subnode-mgmt.md
index 7432c180c..8ef16a6b6 100755
--- a/docs/_docs/automatic-subnode-mgmt.md
+++ b/docs/_docs/automatic-subnode-mgmt.md
@@ -14,14 +14,16 @@ When enabled, ASM means that your nodes no longer require `addSubnode:` or `remo
Consider the following intialization method from the PhotoCellNode class in ASDKgram sample app. This ASCellNode
subclass produces a simple social media photo feed cell.
-In the "Original Code" we see the familiar `addSubnode:` calls in bold. In the "Code with ASM" (switch at top right of code block) these have been removed and replaced with a single line that enables ASM.
+In the "Original Code" we see the familiar `addSubnode:` calls in bold. In the "Code with ASM" these have been removed and replaced with a single line that enables ASM.
By setting `.automaticallyManagesSubnodes` to `YES` on the `ASCellNode`, we _no longer_ need to call `addSubnode:` for each of the `ASCellNode`'s subnodes. These `subNodes` will be present in the node hierarchy as long as this class' `layoutSpecThatFits:` method includes them.
-
+
+
Original code
+
- Code with ASM
- Original Code
+ Objective-C
+ Swift
@@ -57,8 +59,50 @@ By setting `.automaticallyManagesSubnodes` to `YES` on the `ASCellNode`, we _no
return self;
}
+
+class PhotoCellNode {
+ private let photoModel: PhotoModel
+
+ private let userAvatarImageNode = ASNetworkImageNode()
+ private let photoImageNode = ASNetworkImageNode()
+ private let userNameTextNode = ASTextNode()
+ private let photoLocationTextNode = ASTextNode()
-
+ init(photo: PhotoModel) {
+ photoModel = photo
+
+ super.init()
+
+ userAvatarImageNode.URL = photo.ownerUserProfile.userPicURL
+ addSubnode(userAvatarImageNode)
+
+ photoImageNode.URL = photo.URL
+ addSubnode(photoImageNode)
+
+ userNameTextNode.attributedText = poto.ownerUserProfile.usernameAttributedString(fontSize: fontSize)
+ addSubnode(userNameTextNode)
+
+ photo.location.reverseGeocodeLocation { [weak self] location in
+ if locationModel == self?.photoModel.location {
+ self?.photoLocationTextNode.attributedText = photo.locationAttributedString(fontSize: fontSize)
+ self?.setNeedsLayout()
+ }
+ }
+ addSubnode(photoLocationTextNode)
+ }
+}
+
+
+
+
+
Code with ASM
+
+
+ Objective-C
+ Swift
+
+
+
- (instancetype)initWithPhotoObject:(PhotoModel *)photo;
{
self = [super init];
@@ -89,6 +133,37 @@ By setting `.automaticallyManagesSubnodes` to `YES` on the `ASCellNode`, we _no
return self;
}
+
+class PhotoCellNode {
+ private let photoModel: PhotoModel
+
+ private let userAvatarImageNode = ASNetworkImageNode()
+ private let photoImageNode = ASNetworkImageNode()
+ private let userNameTextNode = ASTextNode()
+ private let photoLocationTextNode = ASTextNode()
+
+ init(photo: PhotoModel) {
+ photoModel = photo
+
+ super.init()
+
+ automaticallyManagesSubnodes = true
+
+ userAvatarImageNode.URL = photo.ownerUserProfile.userPicURL
+
+ photoImageNode.URL = photo.URL
+
+ userNameTextNode.attributedText = poto.ownerUserProfile.usernameAttributedString(fontSize: fontSize)
+
+ photo.location.reverseGeocodeLocation { [weak self] location in
+ if locationModel == self?.photoModel.location {
+ self?.photoLocationTextNode.attributedText = photo.locationAttributedString(fontSize: fontSize)
+ self?.setNeedsLayout()
+ }
+ }
+ }
+}
+
@@ -105,7 +180,10 @@ An
ASLayoutSpec
completely describes the UI of a view in your app b
Consider the abreviated `layoutSpecThatFits:` method for the `ASCellNode` subclass above.
-
SwiftObjective-C
+
+Objective-C
+Swift
+
@@ -153,7 +231,47 @@ Consider the abreviated `layoutSpecThatFits:` method for the `ASCellNode` subcla
+override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
+ let headerSubStack: ASStackLayoutSpec = .vertical()
+ headerSubStack.style.flexShrink = 1
+
+ if photoLocationLabel.attributedText != nil {
+ headerSubStack.children = [userNameLabel, photoLocationLabel]
+ } else {
+ headerSubStack.children = [userNameLabel]
+ }
+ userAvatarImageNode.style.preferredSize = CGSize(width: userImageHeight, height: userImageHeight) // constrain avatar image frame size
+
+ let spacer = ASLayoutSpec()
+ spacer.style.flexGrow = 1
+
+ let avatarInsets = UIEdgeInsets(top: horizontalBuffer, left: 0, bottom: horizontalBuffer, right: horizontalBuffer)
+ let avatarInset = ASInsetLayoutSpec(insets: avatarInsets, child: userAvatarImageNode)
+
+ let headerStack: ASStackLayoutSpec = .horizontal()
+ headerStack.alignItems = .center // center items vertically in horizontal stack
+ headerStack.justifyContent = .start // justify content to the left side of the header stack
+ headerStack.children = [avatarInset, headerSubStack, spacer]
+
+ // header inset stack
+ let insets = UIEdgeInsets(top: 0, left: horizontalBuffer, bottom: 0, right: horizontalBuffer)
+ let headerWithInset = ASInsetLayoutSpec(insets: insets, child: headerStack)
+
+ // footer inset stack
+ let footerInsets = UIEdgeInsets(top: verticalBuffer, left: horizontalBuffer, bottom: verticalBuffer, right: horizontalBuffer)
+ let footerWithInset = ASInsetLayoutSpec(insets: footerInsets, child: photoCommentsNode)
+
+ // vertical stack
+ let cellWidth = constrainedSize.max.width
+ photoImageNode.style.preferredSize = CGSize(width: cellWidth, height: cellWidth) // constrain photo frame size
+
+ let verticalStack: ASStackLayoutSpec = .vertical()
+ verticalStack.alignItems = .stretch // stretch headerStack to fill horizontal space
+ verticalStack.children = [headerWithInset, photoImageNode, footerWithInset]
+
+ return verticalStack
+}
diff --git a/docs/_docs/button-node.md b/docs/_docs/button-node.md
index 2dcbd030e..11eb6ca95 100755
--- a/docs/_docs/button-node.md
+++ b/docs/_docs/button-node.md
@@ -22,7 +22,7 @@ If you've used `-setTitle:forControlState:` then you already know how to set up
[buttonNode setTitle:@"Button Title Normal" withFont:nil withColor:[UIColor blueColor] forState:ASControlStateNormal];
-button.setTitle("Button Title Normal", withFont: nil, withColor: UIColor.blueColor(), forState: .Normal)
+buttonNode.setTitle("Button Title Normal", with: nil, with: .blue, for: .normal)
@@ -37,7 +37,7 @@ If you need even more control, you can also opt to use the attributed string ver
[self.buttonNode setAttributedTitle:attributedTitle forState:ASControlStateNormal];
-buttonNode.setAttributedTitle(attributedTitle, for: [])
+buttonNode.setAttributedTitle(attributedTitle, for: .normal)
@@ -54,7 +54,7 @@ Again, analagous to UIKit, you can add sets of target-action pairs to respond to
[buttonNode addTarget:self action:@selector(buttonPressed:) forControlEvents:ASControlNodeEventTouchUpInside];
-button.addTarget(self, action: #selector(buttonPressed(_:)), forControlEvents: .TouchUpInside)
+buttonNode.addTarget(self, action: #selector(buttonPressed), forControlEvents: .touchUpInside)
@@ -72,8 +72,8 @@ self.buttonNode.contentVerticalAlignment = ASVerticalAlignmentTop;
self.buttonNode.contentHorizontalAlignment = ASHorizontalAlignmentMiddle;
-buttonNode.contentVerticalAlignment = .Top
-buttonNode.contentHorizontalAlignment = .Middle
+buttonNode.contentVerticalAlignment = .top
+buttonNode.contentHorizontalAlignment = .middle
diff --git a/docs/_docs/cell-node.md b/docs/_docs/cell-node.md
index 85c626a8d..5bf99b5ee 100755
--- a/docs/_docs/cell-node.md
+++ b/docs/_docs/cell-node.md
@@ -42,20 +42,20 @@ For example, say you already have a view controller written that manages an `AST
return [[AnimalTableNodeController alloc] initWithAnimals:animals];
} didLoadBlock:nil];
- node.preferredFrameSize = pagerNode.bounds.size;
+ node.style.preferredSize = pagerNode.bounds.size;
return node;
}
-func pagerNode(pagerNode: ASPagerNode!, nodeAtIndex index: Int) -> ASCellNode! {
+func pagerNode(_ pagerNode: ASPagerNode, nodeAt index: Int) -> ASCellNode {
let animals = allAnimals[index]
let node = ASCellNode(viewControllerBlock: { () -> UIViewController in
return AnimalTableNodeController(animals: animals)
- }, didLoadBlock: nil)
+ }, didLoad: nil)
- node.preferredFrameSize = pagerNode.bounds.size
+ node.style.preferredSize = pagerNode.bounds.size
return node
}
@@ -86,20 +86,20 @@ Alternatively, if you already have a `UIView` or `CALayer` subclass that you'd l
return [[SomeAnimalView alloc] initWithAnimal:animal];
}];
- node.preferredFrameSize = pagerNode.bounds.size;
+ node.style.preferredSize = pagerNode.bounds.size;
return node;
}
-func pagerNode(pagerNode: ASPagerNode!, nodeAtIndex index: Int) -> ASCellNode! {
+func pagerNode(_ pagerNode: ASPagerNode, nodeAt index: Int) -> ASCellNode {
let animal = animals[index]
let node = ASCellNode { () -> UIView in
return SomeAnimalView(animal: animal)
}
- node.preferredFrameSize = pagerNode.bounds.size
+ node.style.preferredSize = pagerNode.bounds.size
return node
}
diff --git a/docs/_docs/containers-ascollectionnode.md b/docs/_docs/containers-ascollectionnode.md
index 4cad85a80..676bac3bb 100755
--- a/docs/_docs/containers-ascollectionnode.md
+++ b/docs/_docs/containers-ascollectionnode.md
@@ -64,12 +64,58 @@ It is recommended that you use the node block version of the method so that your
As noted in the previous section:
- - ASCollectionNodes do not utilize cell resuse.
+ - ASCollectionNodes do not utilize cell reuse.
- Using the "nodeBlock" method is preferred.
- It is very important that the returned node blocks are thread-safe.
- ASCellNodes can be used by ASTableNode, ASCollectionNode and ASPagerNode.
+### Node Block Thread Safety Warning
+
+It is very important that node blocks be thread-safe. One aspect of that is ensuring that the data model is accessed _outside_ of the node block. Therefore, it is unlikely that you should need to use the index inside of the block.
+
+Consider the following `-collectionNode:nodeBlockForItemAtIndexPath:` method.
+
+
+
SwiftObjective-C
+
+
+- (ASCellNodeBlock)collectionNode:(ASCollectionNode *)collectionNode nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath
+{
+ PhotoModel *photoModel = [_photoFeed objectAtIndex:indexPath.row];
+
+ // this may be executed on a background thread - it is important to make sure it is thread safe
+ ASCellNode *(^cellNodeBlock)() = ^ASCellNode *() {
+ PhotoCellNode *cellNode = [[PhotoCellNode alloc] initWithPhoto:photoModel];
+ cellNode.delegate = self;
+ return cellNode;
+ };
+
+ return cellNodeBlock;
+}
+
+
+
+func tableNode(_ collectionNode: ASCollectionNode, nodeBlockForItemAt indexPath: IndexPath) -> ASCellNodeBlock {
+ guard photoFeed.count > indexPath.row else { return { ASCellNode() } }
+
+ let photoModel = photoFeed[indexPath.row]
+
+ // this may be executed on a background thread - it is important to make sure it is thread safe
+ let cellNodeBlock = { () -> ASCellNode in
+ let cellNode = PhotoCellNode(photo: photoModel)
+ cellNode.delegate = self
+ return cellNode
+ }
+
+ return cellNodeBlock
+}
+
+
+
+
+In the example above, you can see how the index is used to access the photo model before creating the node block.
+
### Replacing a UICollectionViewController with an ASViewController
AsyncDisplayKit does not offer an equivalent to UICollectionViewController. Instead, you can use the flexibility of ASViewController to recreate any type of UI...ViewController.
diff --git a/docs/_docs/containers-asnodecontroller.md b/docs/_docs/containers-asnodecontroller.md
index c1c5c272b..987f21092 100755
--- a/docs/_docs/containers-asnodecontroller.md
+++ b/docs/_docs/containers-asnodecontroller.md
@@ -60,7 +60,25 @@ All of this logic can be removed from where it previously existed in the "view"
- // Click the "Edit on GitHub" button at the bottom of this page to contribute the swift code for this section. Thanks!
+final class PhotoCellNodeController: ASNodeController {
+
+ override func loadNode() {
+ self.node = PhotoCellNode(photoObject: photoModel)
+ }
+
+ override func didEnterPreloadState() {
+ super.didEnterPreloadState()
+
+ let commentFeedModel = photoModel.commentFeed
+ commentFeedModel.refreshFeedWithCompletionBlock { [weak self] newComments in
+ // load comments for photo
+ if commentFeedModel.numberOfItemsInFeed > 0 {
+ self?.node.photoCommentsNode.updateWithCommentFeedModel(commentFeedModel)
+ self?.node.setNeedsLayout()
+ }
+ }
+ }
+}
@@ -102,7 +120,22 @@ Next, we add a mutable array to the `PhotoFeedNodeController` to store our node
- // Click the "Edit on GitHub" button at the bottom of this page to contribute the swift code for this section. Thanks!
+final class PhotoFeedNodeController: PhotoFeedBaseController {
+
+ let photoFeed: PhotoFeedModel
+ let tableNode: ASTableNode = ASTableNode()
+ var photoCellNodeControllers: [PhotoCellNodeController] = []
+
+ init() {
+ super.init(node: tableNode)
+
+ navigationItem.title = "ASDK"
+ navigationController.isNavigationBarHidden = true
+
+ tableNode.dataSource = self
+ tableNode.delegate = self
+ }
+}
@@ -140,7 +173,25 @@ To use this node controller, we modify our table row insertion logic to create a
- // Click the "Edit on GitHub" button at the bottom of this page to contribute the swift code for this section. Thanks!
+func insertNewRowsInTableNode(newPhotos: [PhotoFeedModel]) {
+ let section = 0
+ var indexPaths: [NSIndexPath] = []
+ let newTotalNumberOfPhotos = photoFeed.numberOfItemsInFeed
+ let firstRow = newTotalNumberOfPhotos - newPhotos.count
+
+ (firstRow..// create photoCellNodeControllers for the new photos
+ let cellController = PhotoCellNodeController()
+ cellController.photoModel = photoFeed[row]
+ photoCellNodeControllers.append(cellController)
+
+ // include this index path in the insert rows call for the table
+ let path = IndexPath(row: row, section: section)
+ indexPaths.append(path)
+ }
+
+ tableNode.insertRows(at: indexPaths, with: .none)
+}
@@ -169,7 +220,16 @@ Don't forget to modify the table data source method to return the node controlle
- // Click the "Edit on GitHub" button at the bottom of this page to contribute the swift code for this section. Thanks!
+func tableNode(_ tableNode: ASTableNode, nodeBlockForRowAt indexPath: IndexPath) -> ASCellNodeBlock {
+ let cellController = photoCellNodeControllers[indexPath.row]
+ // this will be executed on a background thread - important to make sure it's thread safe
+ let cellNodeBlock = { () -> ASCellNode in
+ let cellNode = cellController.node
+ return cellNode
+ }
+
+ return cellNodeBlock
+}
diff --git a/docs/_docs/containers-astablenode.md b/docs/_docs/containers-astablenode.md
index 509b58ce0..8227da117 100755
--- a/docs/_docs/containers-astablenode.md
+++ b/docs/_docs/containers-astablenode.md
@@ -22,7 +22,7 @@ nextPage: containers-ascollectionnode.html
-override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
+func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
@@ -41,7 +41,7 @@ with your choice of **_one_** of the following methods
-override func tableNode(tableNode: ASTableNode, nodeForRowAtIndexPath indexPath: NSIndexPath) -> ASCellNode
+func tableNode(_ tableNode: ASTableNode, nodeForRowAt indexPath: IndexPath) -> ASCellNode
@@ -60,14 +60,14 @@ or
-override func tableNode(tableNode: ASTableNode, nodeBlockForRowAtIndexPath indexPath: NSIndexPath) -> ASCellNodeBlock
+func tableNode(_ tableNode: ASTableNode, nodeBlockForRowAt indexPath: IndexPath) -> ASCellNodeBlock
-It is recommended that you use the node block version of these methods so that your collection node will be able to prepare and display all of its cells concurrently. This means that all subnode initialization methods can be run in the background. Make sure to keep 'em thread safe.
+It is recommended that you use the node block version of these methods so that your table node will be able to prepare and display all of its cells concurrently. This means that all subnode initialization methods can be run in the background. Make sure to keep 'em thread safe.
These two methods, need to return either an `ASCellNode` or an `ASCellNodeBlock`. An `ASCellNodeBlock` is a block that creates a `ASCellNode` which can be run on a background thread. Note that `ASCellNodes` are used by `ASTableNode`, `ASCollectionNode` and `ASPagerNode`.
@@ -101,10 +101,10 @@ An `ASTableNode` is assigned to be managed by an `ASViewController` in its `-ini
-func initWithModel(models: Array<Model>) {
- let tableNode = ASTableNode(style:.Plain)
+init(models: [Model]) {
+ let tableNode = ASTableNode(style: .plain)
- super.initWithNode(tableNode)
+ super.init(node: tableNode)
self.models = models
self.tableNode = tableNode
@@ -122,8 +122,6 @@ It is very important that node blocks be thread-safe. One aspect of that is ensu
Consider the following `-tableNode:nodeBlockForRowAtIndexPath:` method from the `PhotoFeedNodeController.m` file in the ASDKgram sample app.
-In the example below, you can see how the index is used to access the photo model before creating the node block.
-
SwiftObjective-C
@@ -144,24 +142,25 @@ In the example below, you can see how the index is used to access the photo mode
-func tableNode(tableNode: UITableNode!, nodeBlockForRowAtIndexPath indexPath: NSIndexPath) -> ASCellNodeBlock! {
- guard photoFeed.count > indexPath.row else { return nil }
-
- let photoModel = photoFeed[indexPath.row]
-
- // this may be executed on a background thread - it is important to make sure it is thread safe
- let cellNodeBlock = { () -> ASCellNode in
- let cellNode = PhotoCellNode(photo: photoModel)
- cellNode.delegate = self;
- return ASCellNode()
- }
-
- return cellNodeBlock
+func tableNode(_ tableNode: ASTableNode, nodeBlockForRowAt indexPath: IndexPath) -> ASCellNodeBlock {
+ guard photoFeed.count > indexPath.row else { return { ASCellNode() } }
+
+ let photoModel = photoFeed[indexPath.row]
+
+ // this may be executed on a background thread - it is important to make sure it is thread safe
+ let cellNodeBlock = { () -> ASCellNode in
+ let cellNode = PhotoCellNode(photo: photoModel)
+ cellNode.delegate = self
+ return cellNode
+ }
+
+ return cellNodeBlock
}
+In the example above, you can see how the index is used to access the photo model before creating the node block.
### Accessing the ASTableView
@@ -194,7 +193,7 @@ override func viewDidLoad() {
super.viewDidLoad()
tableNode.view.allowsSelection = false
- tableNode.view.separatorStyle = .None
+ tableNode.view.separatorStyle = .none
tableNode.view.leadingScreensForBatching = 3.0 // default is 2.0
}
diff --git a/docs/_docs/debug-tool-ASRangeController.md b/docs/_docs/debug-tool-ASRangeController.md
index 38fc48023..fcc2d124d 100755
--- a/docs/_docs/debug-tool-ASRangeController.md
+++ b/docs/_docs/debug-tool-ASRangeController.md
@@ -36,7 +36,7 @@ The
let node = ASDisplayNode()
-node.backgroundColor = UIColor.orangeColor()
+node.backgroundColor = .orange
node.bounds = CGRect(x: 0, y: 0, width: 100, height: 100)
print("Underlying view: \(node.view)")
@@ -51,7 +51,7 @@ NSLog(@"Backing layer: %@", node.layer);
let node = ASDisplayNode()
node.clipsToBounds = true // not .masksToBounds
-node.borderColor = UIColor.blueColor() //layer name when there is no UIView equivalent
+node.borderColor = UIColor.blue.cgColor // layer name when there is no UIView equivalent
print("Backing layer: \(node.layer)")
@@ -78,10 +78,10 @@ ASDisplayNode *node = [ASDisplayNode alloc] initWithViewBlock:^{
-let node = ASDisplayNode(viewBlock: { () -> UIView! in
- let view = SomeView();
- return view
-})
+let node = ASDisplayNode { () -> UIView in
+ let view = SomeView()
+ return view
+}
diff --git a/docs/_docs/layout-transition-api.md b/docs/_docs/layout-transition-api.md
index 0198f088d..1af89390d 100755
--- a/docs/_docs/layout-transition-api.md
+++ b/docs/_docs/layout-transition-api.md
@@ -190,7 +190,7 @@ It is imperative to call `completeTransition:` on the context object once your a
Note that there hasn't been a use of `addSubnode:` or `removeFromSupernode` during the transition. AsyncDisplayKit's layout transition API analyzes the differences in the node hierarchy between the old and new layout, implicitly performing node insertions and removals via Automatic Subnode Management.
-Nodes are inserted before your implementation of `animateLayoutTransition:` is called and this is a good place to manually manage the hierarchy before you begin the animation. Removals are preformed in `didCompleteLayoutTransition:` after you call `completeTransition:` on the context object. If you need to manually perform deletions, override `didCompleteLayoutTransition:` and perform your custom operations. Note that this will override the default behavior and it is recommended to either call `super` or walk through the `removedSubnodes` getter in the context object to perform the cleanup.
+Nodes are inserted before your implementation of `animateLayoutTransition:` is called and this is a good place to manually manage the hierarchy before you begin the animation. Removals are performed in `didCompleteLayoutTransition:` after you call `completeTransition:` on the context object. If you need to manually perform deletions, override `didCompleteLayoutTransition:` and perform your custom operations. Note that this will override the default behavior and it is recommended to either call `super` or walk through the `removedSubnodes` getter in the context object to perform the cleanup.
Passing `NO` to `transitionLayoutWithAnimation:` will still run through your `animateLayoutTransition:` and `didCompleteLayoutTransition:` implementations with the `[context isAnimated]` property set to `NO`. It is your choice on how to handle this case — if at all. An easy way to provide a default implementation this is to call super:
diff --git a/docs/_docs/layout2-conversion-guide.md b/docs/_docs/layout2-conversion-guide.md
index 7d120645e..564f2778a 100755
--- a/docs/_docs/layout2-conversion-guide.md
+++ b/docs/_docs/layout2-conversion-guide.md
@@ -405,10 +405,22 @@ Use `-[ASDisplayNode layoutThatFits:]` instead to get an `ASLayout` and call `si
CGSize size = [displayNode measure:CGSizeMake(100, 100)];
// 2.0:
-ASLayout *layout = [displayNode layoutThatFits:ASSizeMake(CGSizeZero, CGSizeMake(100, 100))];
+// Creates an ASSizeRange with min and max sizes.
+ASLayout *layout = [displayNode layoutThatFits:ASSizeRangeMake(CGSizeZero, CGSizeMake(100, 100))];
+// Or an exact size
+// ASLayout *layout = [displayNode layoutThatFits:ASSizeRangeMake(CGSizeMake(100, 100))];
CGSize size = layout.size;
+// 1.x
+let size = displayNode.measure(CGSize(width: 100, height: 100))
+
+// 2.0:
+// Creates an ASSizeRange with min and max sizes.
+let layout = displayNode.layoutThatFits(ASSizeRange(min: CGSizeZero, max: CGSize(width: 100, height: 100)))
+// Or an exact size
+// let layout = displayNode.layoutThatFits(ASSizeRangeMake(CGSize(width: 100, height: 100)))
+let size = layout.size
diff --git a/docs/_docs/layout2-layoutspec-types.md b/docs/_docs/layout2-layoutspec-types.md
index 3e3281c1e..f5ac3ea75 100755
--- a/docs/_docs/layout2-layoutspec-types.md
+++ b/docs/_docs/layout2-layoutspec-types.md
@@ -85,7 +85,8 @@ they will be resolved again, causing justifyContent and alignItems to be updated
Thus, it is preferred to those properties.
- `justifyContent`. The amount of space between each child.
- `alignItems`. Orientation of children along cross axis.
-- `baselineRelativeArrangement`. If `YES` the vertical spacing between two views is measured from the last baseline of the top view to the top of the bottom view.
+- `flexWrap`. Whether children are stacked into a single or multiple lines. Defaults to single line.
+- `alignContent`. Orientation of lines along cross axis if there are multiple lines.
@@ -130,7 +131,7 @@ override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec
-Flexbox works the same way in AsyncDisplayKit as it does in CSS on the web, with a few exceptions. The defaults are different, there is no `flex` parameter and `flexGrow` and `flexShrink` only supports a boolean value.
+Flexbox works the same way in AsyncDisplayKit as it does in CSS on the web, with a few exceptions. For example, the defaults are different and there is no `flex` parameter. See Web Flexbox Differences for more information.
@@ -242,7 +243,7 @@ override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec
let backgroundNode = ASDisplayNodeWithBackgroundColor(UIColor.blue)
let foregroundNode = ASDisplayNodeWithBackgroundColor(UIColor.red)
- return ASBackgroundLayoutSpec(child: backgroundNode, background: backgroundNode)
+ return ASBackgroundLayoutSpec(child: foregroundNode, background: backgroundNode)
}
diff --git a/docs/_docs/layout2-quickstart.md b/docs/_docs/layout2-quickstart.md
index 11f6a1f1f..96c7726ee 100755
--- a/docs/_docs/layout2-quickstart.md
+++ b/docs/_docs/layout2-quickstart.md
@@ -30,7 +30,7 @@ AsyncDisplayKit's layout system is centered around two basic concepts:
### Layout Specs
-A layout spec, short for "layout specification", has no physical presence. Instead, layout specs act as containers for other layout elements by understanding how these children layout elments relate to each other.
+A layout spec, short for "layout specification", has no physical presence. Instead, layout specs act as containers for other layout elements by understanding how these children layout elements relate to each other.
AsyncDisplayKit provides several subclasses of `ASLayoutSpec`, from a simple layout specification that insets a single child, to a more complex layout specification that arranges multiple children in varying stack configurations.
@@ -62,7 +62,7 @@ Some elements have an "intrinsic size" based on their immediately available cont
- `ASTextNode`
- `ASButtonNode`
-All other nodes either do not have an intrinsic size or lack an intrinsic size until their external resource is loaded. For example, an `ASNetworkImageNode` does not know its size until the image has been downloaded from the URL. These sorts of elments inlcude
+All other nodes either do not have an intrinsic size or lack an intrinsic size until their external resource is loaded. For example, an `ASNetworkImageNode` does not know its size until the image has been downloaded from the URL. These sorts of elements include
- `ASVideoNode`
- `ASVideoPlayerNode`
@@ -73,7 +73,7 @@ These nodes that lack an initial intrinsic size must have an initial size set fo
### Layout Debugging
-Calling `-asciiArtString` on any `ASDisplayNode` or `ASLayoutSpec` returns an ascii-art representation of the object and its children. Optionally, if you set the `.debugName` on any node or layout spec, that will also included in the ascii art. An example is seen below.
+Calling `-asciiArtString` on any `ASDisplayNode` or `ASLayoutSpec` returns an ascii-art representation of the object and its children. Optionally, if you set the `.debugName` on any node or layout spec, that will also be included in the ascii art. An example is seen below.
diff --git a/docs/_docs/layout2-web-flexbox-differences.md b/docs/_docs/layout2-web-flexbox-differences.md
index 641e59530..d31285e22 100755
--- a/docs/_docs/layout2-web-flexbox-differences.md
+++ b/docs/_docs/layout2-web-flexbox-differences.md
@@ -18,4 +18,4 @@ Layoutables don't have a padding or margin property. Instead wrapping a layoutab
### Missing features
-Certain features like `flexWrap` on a `ASStackLayoutSpec` are not supported currently. See
Layout Properties for the full list of properties that are supported.
\ No newline at end of file
+Certain features are not supported currently. See
Layout Properties for the full list of properties that are supported.
diff --git a/docs/_docs/text-node.md b/docs/_docs/text-node.md
index 1210a5120..24b1fbaed 100755
--- a/docs/_docs/text-node.md
+++ b/docs/_docs/text-node.md
@@ -20,7 +20,7 @@ NSDictionary *attrs = @{ NSFontAttributeName: [UIFont fontWithName:@"HelveticaNe
NSAttributedString *string = [[NSAttributedString alloc] initWithString:@"Hey, here's some text." attributes:attrs];
_node = [[ASTextNode alloc] init];
-_node.attributedString = string;
+_node.attributedText = string;
@@ -28,7 +28,7 @@ let attrs = [NSFontAttributeName: UIFont(name: "HelveticaNeue", size: 12.0)]
let string = NSAttributedString(string: "Hey, here's some text.", attributes: attrs)
node = ASTextNode()
-node.attributedString = string
+node.attributedText = string
@@ -46,15 +46,15 @@ In any case where you need your text node to fit into a space that is smaller th
_textNode = [[ASTextNode alloc] init];
-_textNode.attributedString = string;
-_textNode.truncationAttributedString = [[NSAttributedString alloc]
+_textNode.attributedText = string;
+_textNode.truncationAttributedText = [[NSAttributedString alloc]
initWithString:@"¶¶¶"];
textNode = ASTextNode()
-textNode.attributedString = string
-textNode.truncationAttributedString = NSAttributedString(string: "¶¶¶")
+textNode.attributedText = string
+textNode.truncationAttributedText = NSAttributedString(string: "¶¶¶")
@@ -86,20 +86,22 @@ NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithS
NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle | NSUnderlinePatternDot),
}
range:[blurb rangeOfString:@"placekitten.com"]];
-_textNode.attributedString = string;
+_textNode.attributedText = string;
+textNode.linkAttributeNames = [kLinkAttributeName]
+
let blurb: NSString = "kittens courtesy placekitten.com 😸"
let attributedString = NSMutableAttributedString(string: blurb as String)
attributedString.addAttribute(NSFontAttributeName, value: UIFont(name: "HelveticaNeue-Light", size: 16.0)!, range: NSRange(location: 0, length: blurb.length))
attributedString.addAttributes([kLinkAttributeName: NSURL(string: "http://placekitten.com/")!,
- NSForegroundColorAttributeName: UIColor.grayColor(),
- NSUnderlineStyleAttributeName: (NSUnderlineStyle.StyleSingle.rawValue | NSUnderlineStyle.PatternDashDot.rawValue)],
- range: blurb.rangeOfString("placekitten.com"))
-textNode.attributedString = attributedString
+ NSForegroundColorAttributeName: UIColor.gray,
+ NSUnderlineStyleAttributeName: (NSUnderlineStyle.styleSingle.rawValue | NSUnderlineStyle.patternDashDot.rawValue)],
+ range: blurb.range(of: "placekitten.com"))
+textNode.attributedText = attributedString
@@ -127,10 +129,11 @@ Conforming to `ASTextNodeDelegate` allows your class to react to various events
-func textNode(textNode: ASTextNode, tappedLinkAttribute attribute: String, value: AnyObject, atPoint point: CGPoint, textRange: NSRange) {
- guard let url = value as? NSURL else { return }
+func textNode(_ textNode: ASTextNode, tappedLinkAttribute attribute: String, value: Any, at point: CGPoint, textRange: NSRange) {
+ guard let url = value as? URL else { return }
- UIApplication.sharedApplication().openURL(url)
+ // the link was tapped, open it
+ UIApplication.shared.openURL(url)
}