The official document links: texturegroup.org/docs/gettin…
Start using Texture
The basic unit of Texture is Node, and ASDisplayNode is an abstraction of UIView and CALayer. It differs from UIKit in that:
Nodes can be drawn asynchronously and are thread-safe, and you can instantiate and configure their hierarchy in asynchronous threads.
To keep the user interface smooth, your App should be rendered at 1/60 of a second frame rate, which means that the main thread has 1/60 of a second to process a frame, which means that the main thread needs to execute all the layout and drawing code in 16 milliseconds, and due to some system-level overhead, Your layout drawing code typically runs for more than 10 milliseconds and can cause frames to drop.
Texture allows you to strip image decoding, text rendering, and other performance-draining UI operations from the main thread to ensure that the main thread responds smoothly to user interactions. It also has other tricks to use, which we’ll cover later.
Node/Node
If you know how to use UIView, then you already know how to use Node. Most of the methods in UIView Node are mapped, and most of the properties of UIView and CALayer are also available. When properties and methods are named differently, such as.clipstobounds and.maskstobounds, Node defaults to UIView, except that Node uses.position instead of.center.
Of course, you can call native properties and methods directly from Node. view or Node. layer, but make sure it executes on the main thread!
Texture already provides a variety of Nodes to replace most of the UIKit components you’re used to, and now you can develop large-scale apps entirely from Texture.
Node Containers /Node Containers
One common mistake you make when integrating Texture into a project is to add Node directly to an existing view. The result is that your Node will flash when rendered.
Instead, you should add nodes to a Node container that manages these nodes. You can think of a Node container as a bridge between UIKit and ASDK.
Layout Engine /Layout Engine
The Texture layout is very powerful and unique to traditional Frame, AutoLayout, etc., but not unfamiliar to front-end workers, it is based on CSS FlexBox. It provides declarations that specify the size of a custom node and the layout of its children, and calculates size and layout asynchronously through the ASLayoutSpec provided for each node when all nodes are rendered simultaneously.
It is similar to UIStackView, but supports lower versions of iOS.
Advanced Developer features
Texture provides a variety of advanced development features not found in UIKit or Foundation, and our developers have found that Texture makes their development more efficient by simplifying their architecture.
Full list coming soon…
What are you talking about?
Integrated Texture
If you’re using Texture for the first time, we recommend you take a look at the ASDKgram example. We’ve written a step-by-step Guide (coming soon) that shows you how to integrate Texture into an App.
What are you talking about?
If you run into any problems, please go to our GitHub or Slack for help.
resources
Live Debug, get updates and communicate with the Core Texture team and 700+ Texture developers in the Slack community by signing up here.
The sample
Check out our sample library. If you’re using Texture for the first time, we recommend you start with ASDKgram. This sample implements the photo Feed using both UIKit and Texture.
- An infinitely scrolling Home Feed that demonstrates the smooth scrolling performance of Texture;
- A fairly large codebase to show how much less code you can cut by designing your App with Texture;
video
- AsyncDisplayKit 2.0: Defining the 7th Abstraction Layer [Pinterest HQ 2016]
- Layout at Scale with AsyncDisplayKit 2.0 [NSMeetup 2016]
- ASCollectionNode [Pinterest HQ 2016]
- AsyncDisplayKit State of the Code [WWDC 2016]
- AsyncDisplayKit 2.0: Intelligent User Interfaces [NSSpain 2015]
- Effortless Responsiveness with AsyncDisplayKit [MCE 2015]
- Asynchronous UI [NSLondon 2014]
Tutorials/articles
- Using AsyncDisplayKit to Develop Responsive UIs in iOS [Ziad Mr. Tamim, 12.29.2016]
- AsyncDisplayKit 2.0 Tutorial: Automatic Layout [Luke Parham, 12.19.2016]
- Tutorial on AsyncDisplayKit 2.0: Getting Started [Luke Parham, 12.5.2016]
- iOS Smooth Scrolling in Buffer for iOS: How (and Why) We Implemented AsyncDisplayKit[Andy Yates, 11.4.2016]
FlexBox layout learning
Texture’s powerful layout system is based on the CSS FlexBox model and these sites are very useful for learning the basics of FlexBox.
- ASStackLayout Game
- Visual Guide to CSS3 Flexbox
- FlexBox Patterns
Install the Texture
Texture can be installed using CocoaPods and Carthage without forgetting to import the header file:
#import <AsyncDisplayKit/AsyncDisplayKit.h>Copy the code
If you’re developing with Swift, you can use the Objective-C Bridging header for bridging, so if you’re having any problems installing, please contact us on GitHub or Slack.
CocoaPods
Using the CocoaPods installation, add the following to your Podfile:
target 'MyApp' do
pod "Texture"
endCopy the code
Exit Xcode completely, open terminal, CD to project directory, and execute the following command:
pod installCopy the code
To update the Texture, open the terminal, CD to the project directory, and execute the following command:
pod update TextureCopy the code
Don’t forget to open with.xcworkspace, not.xcodeProj.
Carthage(Regular installation)
Using Carthage requires creating a Cartfile list, then performing a Carthage update, downloading the dependencies into the Cathage/Checkouts folder, and building them into a folder located in Carthage/Build that the developer must manually integrate into the project.
Texture can also be added to Cartfile via Carthage installation to get the latest release:
github "texturegroup/texture"Copy the code
Or get the trunk:
github "texturegroup/texture" "master"Copy the code
To install the Cartfile, run the following command in the Carthage/Checkouts directory:
carthage updateCopy the code
Make sure the Texture, PINRemoteImage (3.0.0-beta.2), and PINCache are all fetched and built. The Cartfile of the Texture will handle these dependencies automatically.
Open Xcode and drag the required Frameworks to the target-general-Linked Frameworks and Libraries.
Carthage(light)
Texture doesn’t support Carthage’s lighter use. You’ll need to manually add project files because Texture’s dependency on PINCache doesn’t have project files yet.
PINCache is a nested dependency of PINRemoteImage.
Without PINRemoteImage and PINCache, you won’t be able to fully use the Texture image set.
Upgrade to 2.0
The release notes
Read the official release notes on GitHub.
Get the official release candidate
Add the following to your POD file:
pod 'Texture'.'> = 2.0'Copy the code
Execute on terminal:
pod repo update
pod update TextureCopy the code
The test of 2.0
Once you update to 2.0, you’ll see a lot of deprecation warnings. Don’t worry! These warnings are safe because we have bridged all the old apis to test 2.0 before migrating to the new API. If your App fails to build successfully instead of just showing a warning, there may be an error in your project. You have several options:
- Disable Deprecation Warnings in Project Settings;
- Disable warnings as Errors in build Settings of your project;
- Disable deprecation Warnings in the Texture, which requires you to remove the deprecation warnings
ASBaseDefines.h
Change line 74 in to# define ASDISPLAYNODE_WARN_DEPRECATED 0
When your App is up and running, you need to test it to make sure everything works. If you find any problems, try adopting the new API in that area and re-test it.
You might notice a key change:
ASStackLayoutSpec. AlignItems attribute default values change as ASStackLayoutAlignItemsStretch rather than ASStackLayoutAlignItemsStart, this could cause distortion in the UI.
If you have any other questions, please submit a GitHub issue and we’re happy to help you!
Smart preloading
Asynchronous concurrent rendering and FlexBox layouts are already very powerful, but Texture does more than that. Another important aspect is the idea of intelligent preloading.
As mentioned in the Starting Texture section, there are disadvantages to using a node outside the context of a node container. This is because all nodes have an idea of the current interfaceState, which is named interfaceState.
The interfaceState property is constantly updated, and its updates are controlled by the ASRangeController, which in turn is created and maintained internally by all node containers.
Nodes used outside the container are not updated by ASRangeController, so this sometimes causes flickering because the nodes outside the container are rendered again after the node has been rendered to the screen because of the wrong state.
Interface State Ranges
When nodes are added to a scrolling or paging interface, they are typically in one of the following ranges. This means that when scrolling views are scrolled, their interface state is updated as they move.
A node can be in one of the following ranges:
Interface range | describe |
---|---|
Preload | When the node is not yet visible, the node collects external sources, which may be apis or local disks. |
Display | Nodes start rendering, including rasterization of text, image decoding, etc. |
Visible | Nodes are visible and have at least one pixel on the screen. |
ASRangeTuningParameters
The size of each range is referenced to the size of the entire screen. The default size works well in many use cases, and you can also adjust them by setting the range parameters on the scroll node.
In the example image of a scrolling collection above, the user is scrolling down. As you can see, the user scroll direction area (leading direction) is much larger than the user leave direction area (following direction). To maintain optimal use of memory, the two regions swap dynamically when the user changes the scrolling direction. This lets you not worry about changes in the direction of the roll, but only about the size of the leading and trailing areas.
In this diagram, you can see how intelligent preloading works. You can see that in a vertical scrolling container, although some nodes are not yet on the device screen, it has a scope controller, and the off-screen nodes are in the Preload data preparation range and Display render preparation range.
Interface State Callbacks
As the user scrolls, the node switches between these three ranges and reacts appropriately by loading data, rendering, and so on. The node subclasses you create can access this mechanism by implementing the corresponding callback methods.
class TZYNode: ASDisplayNode {
override func didEnterPreloadState(a) {
print("Enter data loading range")}override func didExitPreloadState(a) {
print("Out of data load range")}override func didEnterDisplayState(a) {
print("Enter render range")}override func didExitDisplayState(a) {
print("Out of range")}override func didEnterVisibleState(a) {
print("Come into view")}override func didExitVisibleState(a) {
print("Out of sight")}}Copy the code
Node Containers /Node Containers
Use nodes in node containers
We strongly recommend that you use nodes of Texture in node containers. Texture provides the following node containers:
Nodes in the container | Equivalent to the UIKit |
---|---|
ASCollectionNode | Instead of UICollectionView |
ASPagerNode | Instead of a UIPageViewController |
ASTableNode | Replace the UITableView |
ASViewController | Instead of a UIViewController |
ASNavigationController | Instead of UINavigationController, implement the ASVisibility protocol. |
ASTabBarController | Instead of UITabBarController, implement the ASVisibility protocol. |
Sample code and specific sample projects are highlighted in the documentation for each node container.
Why use node containers
The node container automatically manages its children for intelligent preloading, which means that all layout calculations, data reads, decoding and rendering of the node are done asynchronously, which is why we recommend putting the node into a node container for use. Note that although you can use the node directly without adding the node container, unless you add other callbacks, the node outside the container will only start rendering when the screen appears. As UIKit does, this can cause performance degradation and content flickering.
Node Subclasses /Node Subclasses
One of the main advantages of using nodes on UIKit components is that all nodes are pre-laid out and drawn on the main thread so that the main thread can immediately respond to user interaction events without dealing with control rendering first. Texture provides the following nodes:
node | Equivalent to the UIKit |
---|---|
ASDisplayNode | Instead of UIView, all nodes inherit from ASDisplayNode. |
ASCellNode | Instead of UITableViewCell&UICollectionViewCell, it needs to be used with ASTableNode, ASCollectionNode, and ASPagerNode. |
ASScrollNode | Instead of UIScrollView, this node is useful for creating custom scrollable regions that contain other nodes. |
ASEditableTextNode | UITextView instead. |
ASTextNode | Instead of UILabel. |
ASImageNode | Instead of a UIImage. |
ASNetworkImageNode | Instead of a UIImage. |
ASMultiplexImageNode | Instead of a UIImage. |
ASVideoNode | AVPlayerLayer instead. |
ASVideoPlayerNode | UIMoviePlayer instead. |
ASControlNode | UIControl instead. |
ASButtonNode | Instead of a UIButton. |
ASMapNode | Replace the MKMapView. |
Although roughly equivalent to UIKit components, the Texture node provides more advanced functionality and convenience in general. For example, ASNetworkImageNode can automatically load web images and cache management, and even support progressive JPeGs and animated GIFs.
The AsyncDisplayKitOverview sample application gives a basic implementation of each of the nodes listed above.
Node Inheritance Hierarchy
All Texture nodes inherit from ASDisplayNode.
The original image is in cursive English, view the original image.
The node on the right is an encapsulation of UIKit elements. For example, ASScrollNode encapsulates a UIScrollView, and ASCollectionNode encapsulates a UICollectionView. ASMapNode in liveMapMode is an encapsulation of UIMapView.
LiveMapMode does not appear in this section and the previous section, it is not clear whether it is a clerical error.
Node instance /Subclassing
The most important difference when subclassing is whether you use ASViewController or ASDisplayNode, which sounds obvious, but because there are subtle differences, it’s important to keep this in mind.
ASDisplayNode
While instantiating a node is similar to UIView, there are a few principles that need to be followed to ensure that you are taking full advantage of its capabilities and that the node behaves as expected.
-init
When initNodeBlocks is used, this method is called on the post-stage thread. However, since no other method will run until init completes, this method does not need to be locked.
The most important thing to remember is that the init method must be able to be called on any queue. Most notably, you should never initialize any UIKit objects in a node initialization method, call node.layer node.view.x operations related to view or layer, or add gestures to nodes in this method. These events should be done in the didLoad method.
-didLoad
This method is conceptually similar to the -ViewDidLoad method on UIViewController, it gets called once when the background view is initialized, it’s guaranteed to get called on the main thread, and it’s the proper place to execute any UIKit code, like adding gestures, Change view and Layer, initialize UIKit objects.
-layoutSpecThatFits:
This method defines the layout of the nodes and does a lot of computation on background threads. This method is where you declare, create, and modify the ASLayoutSpec layout description object, which describes the size of the node and the size and position of its children, and is where you place most of the layout code.
The ASLayoutSpec object is mutable until it is returned in this method. After that, the object will be immutable. It is important to note that you do not need to cache the ASLayoutSpec object for later use. We recommend that you recreate the layout description if necessary.
Since it runs on a background thread, you cannot call Node.view or Node.layer and their properties in this method. Also, don’t create other nodes in this method unless you know exactly what you’re doing. Also, overriding this method does not necessarily require calling the super method.
-layout
Calling super in this method computes the layout using the layoutSpec object, and all child nodes compute their size and position.
-Layout is similar in concept to UIViewController’s -ViewwillLayOutSubView, which is a good place to change the Hidden property, modify the View property, and set the background color. You can set the background color in the -layoutSpec: method, but there may be timing issues with this. If you need to use native UIViews, you can set their frames here, but anyway, you can always use -initWithViewBlock: create nodes and adjust them in background threads somewhere else.
This method is called on the main thread, and if you are using ASLayoutSpec, you should not rely too much on this method, because layout on the main thread is highly desirable and requires subclasses of this method less than 1/10.
One important use of -layout is that you need the size of the child nodes to be accurate. For example, when you want a collectionNode to pave the screen, which is not well supported by ASLayoutSpec, the easiest way to do this is to manually set the frame in this method:
subnode.frame = self.boundsCopy the code
If you want the same effect in ASViewController, you can do the same thing in -ViewwillLayOutSubviews, but if your node is instantiated with initWithNode:, it will do so automatically.
ASViewController
ASViewController is a regular UIViewController subclass with special functions for managing nodes. Since it’s a UIViewController subclass, all methods are called on the main thread, and you should create at least one ASViewController on the main thread.
-init
This method is called once at the beginning of the life cycle of the ASViewController. Just like UIViewController initialization, you’d better not call self.view or self.node.view in this method, because this forces the creation of the view. These operations can be done in -viewDidLoad, which can perform access to any view.
The constructor specified by the ASViewController is initWithNode:, a typical constructor would look like this. Notice how the ASViewController node is created before super is called. The ASViewController management node is similar to UIViewController management views, but it is initialized differently:
class TZYVC: ASViewController<ASDisplayNode> {
init() {
let pagerNode = ASPagerNode(a)super.init(node: pagerNode)
pagerNode.setDataSource(self)
pagerNode.setDelegate(self)}required init? (coder aDecoder:NSCoder) {
fatalError("init(coder:) has not been implemented")}}extension TZYVC: ASPagerDataSource {
func numberOfPages(in pagerNode: ASPagerNode) -> Int {
return 10}}extension TZYVC: ASPagerDelegate {}Copy the code
-loadView
We recommend that you do not use this method because it has no particular advantages over -viewDidLoad and has some disadvantages. However, as long as the self.view property is not set to a different value, it is safe to use. Its super method sets its wrapped UIViewController view to node.view of the ASViewController.
-viewDidLoad
This method is executed after -loadView. This is the earliest method in the ASViewController lifecycle that you can access Node. view. You can modify view and Layer or add gestures in this method. It will only be executed once.
So the layout code should not be in this method because it will not be called again when the interface is redrawn. Same thing with this method in UIViewController, it’s not a good idea to put layout code in this method, even if your layout doesn’t change because of the interaction.
-viewWillLayoutSubviews
This method is called at the same time as the -layout of the node. It may be called many times during the life of the ASViewController, when the boundary of the ASViewController node changes, such as rotation, split screen, keyboard popup, etc., or when the view hierarchy changes. This method is called when a child node is added, removed, or changed in size.
Because it’s not called very often, but it means the page needs to be redrawn, all layout code is best placed in this method, even UI code that doesn’t directly depend on size.
-viewWillAppear: / -viewDidDisappear:
ViewWillAppear is called before the ASViewController’s node appears on screen, which is the earliest time that the node appears off screen, viewDidDisappear is called after the controller is removed from the view hierarchy, which is the earliest time that the node disappears off screen, These two methods provide a good time to start or stop controller-related animations, and are a good place to save and log user behavior.
Although these methods may be called multiple times and can execute layout code, these two methods are not called at all times when redrawing is required, and therefore should not be used to execute core layout code except for specific animation Settings.
To be continued
AsyncDisplayKit/Texture