Skip to Content

What is texture in Swift?

What is texture in Swift?

Texture is an important concept in iOS development with Swift. It allows developers to build smooth, high-performance user interfaces. Texture provides a graphical user interface (GUI) framework that can render complex layouts and animations at a high frame rate.

Some key benefits of using Texture include:

  • Smooth scrolling of complex layouts – Texture uses an asynchronous rendering engine that moves image processing off the main thread. This allows for smooth scrolling at 60 frames per second.
  • Flexible layout system – Texture offers a YAML-based layout language called ASTextNode that is more flexible than Auto Layout.
  • Integration with AsyncDisplayKit – Texture was originally built on top of AsyncDisplayKit, so it inherits features like node containment graphs and interface state pre-rendering.
  • Multi-threading – Texture uses concurrent queues to move image processing, text measurement and layout calculation off the main thread when possible.

In this article, we’ll take an in-depth look at how texture works in iOS development with Swift. We’ll cover:

Texture under the hood

– How Texture achieves high performance rendering
– The node hierarchy system
– Layout specifications with ASTextNode

Getting started with Texture

– Setting up a Texture project
– Creating and configuring nodes
– Building user interface layouts

Advanced Texture techniques

– Animations and transitions
– Integrating Texture with existing UIKit code
– Debugging and performance tuning

So let’s dive in and explore the world of high-performance user interfaces with Texture!

Texture Under the Hood

Texture is able to deliver smooth, high FPS rendering of complex interfaces by taking advantage of multiple technologies under the hood:

Pre-Rendering

Texture pre-renders as much of the interface as possible before it is displayed on screen. This includes text measurement, image loading and view layout. By doing this work offscreen, Texture reduces the amount of work needed on the main thread.

Async Rendering

Texture employs an asynchronous rendering engine to move image processing and text measurement off the main thread when possible. This allows the main thread to focus on UI updates and responding to user input.

Containment Graphs

The interface is organized into a hierarchy of nodes. This hierarchy is tracked using a containment graph which allows optimized delivery of display updates. Nodes only redraw when their content changes.

Concurrent Queues

Texture manages much of its background work using Grand Central Dispatch queues. This allows operations like image decoding and text measurement to be parallelized across all available CPU cores.

By leveraging these technologies, Texture provides a smooth user experience even with large, complex layouts. Next we’ll look at the node hierarchy at the heart of Texture.

Node Hierarchy

Texture interfaces are constructed using a hierarchy of nodes. These nodes include:

ASDisplayNode

The base node class in Texture is ASDisplayNode. This node provides the basic rendering capabilities backed by the asynchronous rendering engine. All other texture nodes inherit from ASDisplayNode.

ASTextNode

For rendering text, Texture provides the ASTextNode class. This includes features like text measurement, drawing and sizing. ASTextNode helps ensure smooth scrolling of text heavy interfaces.

ASImageNode

For displaying images, Texture includes the ASImageNode class. It handles image loading, decoding and display allowing images to be rendered at a high frame rate.

ASViewController

ASTextureController can be used as a drop-in replacement for UIViewController within a Texture interface. It provides life cycle management for the node hierarchy.

ASLayoutSpec

The layout of nodes is defined using ASLayoutSpec subclasses. These specs describe the organization of nodes and can implement advanced layout logic.

The node hierarchy forms the core structure of a Texture interface. Next we’ll look at how layouts are defined.

Layout Specifications

Texture uses a declarative YAML-based language called ASTextNode for defining node layouts. This provides a flexible and concise way to describe complex interfaces.

Some key advantages of ASTextNode include:

  • More powerful than Auto Layout – ASTextNode provides flexible spacing, alignment, sizing and organization logic.
  • Declarative syntax – The YAML syntax clearly defines the interface structure.
  • Reusable layouts – Common layouts can be defined once and reused.
  • Strong typing – The node class is part of the layout definition which enables typing.
  • Thread-safe – ASTextNode layouts can be calculated off the main thread.

Here is an example ASTextNode file defining a simple profile layout:


ProfileLayout:
  - ASStackLayoutSpec: 
    children: 
      - ASImageNode:
        image: profile_picture

      - ASStackLayoutSpec:
        direction: vertical
        children:
          - ASTextNode: 
            text: John Appleseed

          - ASTextNode:
            text: San Francisco, CA        

The declarative style keeps layouts easy to visualize while allowing powerful functionalities.

Now that we’ve seen how Texture works under the hood and how layouts are defined, let’s look at getting started with Texture in an iOS app.

Getting Started with Texture

It’s straightforward to add Texture to a new or existing iOS project. Here are the key steps:

1. Install Texture Dependencies

Texture relies on AsyncDisplayKit and YAML. These can easily be added via CocoaPods:

pod 'Texture', '~> 3.0.0' 
pod 'AsyncDisplayKit', '~> 3.0.0'

This will install Texture, AsyncDisplayKit and the YAML parsing libraries.

2. Subclass ASDisplayNode

Create a custom node subclass to build your UI. Commonly this is done for an entire screen:

class ProfileNode: ASDisplayNode {

  // UI Initialization here
  
}

3. Define the Layout

Use ASTextNode to define the layout for your node. This can be loaded from an external YAML file.

let layout = try! ASTextNode(file: "profile_layout.yaml") 

4. Init the Node Hierarchy

Initialize the root node and recursively build the node hierarchy using the defined layout:

let profileNode = ProfileNode()
profileNode.automaticallyManagesSubnodes = true
profileNode.layoutSpec = layout

This will construct the full node tree.

5. Render the Interface

Finally, render the root node into the view hierarchy:

view.addSubnode(profileNode)

And that’s it! Texture will now render the interface. Next let’s look at some advanced techniques.

Advanced Texture Techniques

Now that we’ve covered the basics, let’s explore some more advanced capabilities of Texture:

Animations

Texture provides a number of built-in animations including fade, scale, slide, and more. Just set properties like:

node.alpha = 0
UIView.animate(withDuration: 0.5) {
  node.alpha = 1 
}

And Texture handles animating the change smoothly.

Custom Transitions

You can build custom interactive transition animations between nodes using the ASTransition API:

let transition = CATransition()
transition.type = .fade
   
node.transitionLayout(with: transition, 
                     shouldMeasureAsync: false,
                     measurementCompletion: nil) 

This implements a fade transition between layouts.

Integration with UIKit

Texture nodes can be embedded within UIKit views and vice versa. This allows incrementally adding Texture to an existing app.

let textureNode = ASDisplayNode()
let uiView = UIView()

view.addSubview(uiView)
uiView.addSubnode(textureNode)

The two frameworks can interoperate smoothly.

Debugging

Texture provides debugging tools like ASLayoutSpec logging, visual flagging of nodes, and performance profiling to help build robust apps.

Pre-Caching

Texture provides API like .allocateUnloadRecursive and .recursiveForkOfSubnodes to preload and cache node hierarchies optimizing memory usage.

These are just a few of the more advanced capabilities of Texture. It’s designed to handle real world complexity and performance demands.

When to Use Texture

Here are some good candidates for using Texture:

– Apps with complex, dynamic layouts
– Interfaces with highly interactive animations
– Long lists or tables with scrolling
– Situations where UIKit performance is insufficient
– Apps already using AsyncDisplayKit

Texture delivers the most value for complex interfaces with dynamic content. It integrates well alongside UIKit allowing incremental adoption.

Conclusion

Texture provides a powerful framework for building smooth iOS interfaces. With its asynchronous rendering, node hierarchy, and ASTextNode layout language it makes easy work of complex layouts.

Texture allows developers to build more dynamic apps with 60fps performance, even on older devices. While newer iPhones get even faster, users continue to hold onto devices for 3+ years. Texture helps ensure a quality experience regardless of hardware age.

The node containment graph, multi-threaded rendering, flexible layouts and comprehensive animations unlock new possibilities. Texture delivers as a robust GUI solution for apps where responsiveness matters.