Q. Textureは部分的に導入できますか?

Ca8210ff0ece2bb6f9fff5fd0770ea64?s=47 Muukii
September 13, 2018

Q. Textureは部分的に導入できますか?

巷で噂となっているPinterestによって開発されている、UIが猛烈に高速化されるTexture(AsyncDisplayKit)ですが、
非常に巨大なフレームワークであり、UIKitをラップする形でAPIが提供されています。
既存のアプリで「UIが重い!Textureを入れて速くしたい!」「でも途中から導入できるものなの?」という問題に対し、
実際のところ、導入は可能なのか?どのように?についてお話しします。

Ca8210ff0ece2bb6f9fff5fd0770ea64?s=128

Muukii

September 13, 2018
Tweet

Transcript

  1. 2.

    ☕ ⌚ About Me • Muukii <Hiroshi Kimura> • iOS

    Engineer at eureka, Inc. • Pairs Global Team • GitHub : @muukii
  2. 3.
  3. 5.

    4PVUI,PSFB Japan Taiwan No.1 2017 release No.1 !5 1BJSTʹ͍ͭͯ ల։ࠃ

    ̐ͭͷϓϥοτϑΥʔϜ CONFIDENTIAL INFORMATION: Not for Public Distribution - Do Not Copy
  4. 6.
  5. 7.
  6. 13.

    What is the Texture? Textureʹ͍ͭͯ • UIॲཧΛߴ଎ԽɾඇಉظԽ͢Δ͜ͱʹΑͬͯಈ͖Λ׈Β͔ʹ͢ΔϥΠϒϥϦ • ݹ͍୺຤Ͱ΋60fpsग़͢͜ͱ͕໨త •

    ⚠ ϨΠΞ΢τ͚ͩͷϥΠϒϥϦͰ͸ͳ͍ • UIKitΛશମతʹϥοϓͯ͠໨తΛ࣮ݱ͢ΔΞϓϩʔν • ެ։͞Εͨ࣌ͷهࣄ • https://www.infoq.com/jp/news/2014/11/facebook-asyncdisplaykit-ios
  7. 18.

    ༷ʑͳߴ଎ԽॲཧΛ࣋ͭ • ՄೳͳݶΓόοΫάϥ΢ϯυεϨουͰॲཧΛߦ͏ • UIͷϨεϙϯε଎౓͕࠷େԽ • UILabel΍UIImageView͸࢖ΘΕͣʹView or Layer ʹ

    Render • λοϓ൑ఆͷඞཁͷͳ͍΋ͷ͸CALayerͱͯ͠දࣔͰ͖Δ (isLayerBacked) • όοΫάϥ΢ϯυͰϝϞϦղ์Λߦ͏Ωϡʔ (releaseʹ΋ίετ͕͔͔ΔͨΊ) • ϨΠΞ΢τͷαΠζܭࢉ͸όοΫάϥ΢ϯυͰฒߦͰ࣮ߦՄೳ • CPUίΞͷଟ͍୺຤΄Ͳ༗ར Textureʹ͍ͭͯ
  8. 19.
  9. 40.
  10. 41.
  11. 42.
  12. 47.

    In UIKit Create Card View final class CardView : UIView

    { private let imageView: UIImageView = .init() private let titleLabel: UILabel = .init() private let detailLabel: UILabel = .init() }
  13. 49.

    In Texture Create Card View final class CardNode : ASDisplayNode

    { private let imageNode: ASImageNode = .init() private let titleNode: ASTextNode = .init() private let detailNode: ASTextNode = .init() }
  14. 51.

    Set initial values init(image: UIImage, title: String, detail: String) {

    super.init() automaticallyManagesSubnodes = true titleNode.attributedText = ... detailNode.attributedText = ... imageNode.image = ... } class CardNode
  15. 54.

    ͜ΕΒΛ૊Έ߹ΘͤͯϨΠΞ΢τΛ࡞Γ্͛Δ ASLayoutSpec • ASWrapperLayoutSpec • ASStackLayoutSpec • ASInsetLayoutSpec • ASOverlayLayoutSpec

    • ASBackgroundLayoutSpec • ASCenterLayoutSpec • ASRatioLayoutSpec • ASRelativeLayoutSpec • ASAbsoluteLayoutSpec
  16. 55.

    let imageSpec = ASRatioLayoutSpec(ratio: 1, child: imageNode) let body =

    ASStackLayoutSpec( direction: .vertical, spacing: 8, justifyContent: .end, alignItems: .start, children: [ imageSpec, titleNode, detailNode ] ) return ASInsetLayoutSpec( insets: .init(top: 8, left: 8, bottom: 8, right: 8), child: body )
  17. 56.
  18. 58.

    Card Title Detail let body = ASStackLayoutSpec( direction: .vertical, spacing:

    8, justifyContent: .end, alignItems: .start, children: [ imageSpec, titleNode, detailNode ] ) child: imageNode ) Image 1 : 1
  19. 59.

    Image Card Title Detail return ASInsetLayoutSpec( insets: .init( top: 8,

    left: 8, bottom: 8, right: 8 ), child: body ) detailNode ] )
  20. 61.

    Create Node Object Use Component let node = CardNode( image:

    UIImage(named: "sample")!, title: "Lorem Ipsum...", detail: "Lorem Ipsum..." ) addSubview(node.view)
  21. 62.

    Calculate size that fits range ( Available in background thread

    ) node.frame.size = layout.size Use Component let layout = node.layoutThatFits( ASSizeRange( min: .init(width: 0.0, height: 250), max: .init(width: 240.0, height: .infinity) ) )
  22. 63.
  23. 66.
  24. 72.

    Initialize ASCollectionNode UICollectionView -> ASCollectionNode let collectionNode: ASCollectionNode = {

    let layout = UICollectionViewFlowLayout() let node = ASCollectionNode(collectionViewLayout: layout) return node }()
  25. 73.

    Add ASCollectionView of ASCollectionNode to view UICollectionView -> ASCollectionNode override

    func viewDidLoad() { let collectionView = collectionNode.view view.addSubview(collectionView) // Setup AutoLayout to CollectionView }
  26. 78.

    Return CellNode factory closure func collectionNode(_ collectionNode: ASCollectionNode, nodeBlockForItemAt indexPath:

    IndexPath) -> ASCellNodeBlock { return { // Call on Background Thread CardNode.init(...) } } UICollectionView -> ASCollectionNode
  27. 79.

    Return constrained size for CellNode func collectionNode(_ collectionNode: ASCollectionNode, constrainedSizeForItemAt

    indexPath: IndexPath) -> ASSizeRange { return ASSizeRange( min: CGSize(width: collectionNode.bounds.width, height: 0), max: CGSize(width: collectionNode.bounds.width, height: .infinity) ) } UICollectionView -> ASCollectionNode
  28. 80.

    Return constrained size for CellNode func collectionNode(_ collectionNode: ASCollectionNode, constrainedSizeForItemAt

    indexPath: IndexPath) -> ASSizeRange { return ASSizeRange( min: CGSize(width: collectionNode.bounds.width, height: 0), max: CGSize(width: collectionNode.bounds.width, height: .infinity) ) } UICollectionView -> ASCollectionNode Width = CollectionNode.width
 Height = 0 ... infinity
  29. 81.
  30. 84.

    ΞΠςϜ͕େྔʹଘࡏ͢ΔϦετ (1ສ~ Λ௒͑ΔΞΠςϜ) Texture͕޲͔ͳ͍έʔε • ΧϝϥϩʔϧͷදࣔͳͲ • શͯͷCellNode͕ੜ੒͞ΕΔͷͰϝϞϦΛѹഭ͢Δ • ASCollectionGalleryLayoutDelegateͱ͍͏΋ͷ͕͋Δ͕ɺஈ֊తʹCellNode

    Λ࡞Δͱ͍͏ΞϓϩʔνͰ͋Γɺ࠷ऴతͳϝϞϦ࢖༻ྔʹมΘΓ͸ͳ͍ • ͜ͷ৔߹͸UICollectionViewΛ࢖༻ͯ͠ϝϞϦ࢖༻Λ཈͑Δ޻෉Λߦ͍ͳ͕Βର ࡦͨ͠ํ͕ྑ͍