AutoLayout以外の選択肢

Ca8210ff0ece2bb6f9fff5fd0770ea64?s=47 Muukii
March 28, 2018

 AutoLayout以外の選択肢

Ca8210ff0ece2bb6f9fff5fd0770ea64?s=128

Muukii

March 28, 2018
Tweet

Transcript

  1. 2.

    About Me ‣ muukii <Hiroshi Kimura> ‣ iOS Engineer at

    eureka, Inc. ‣ Pairs Global Team ‣ GitHub : @muukii ‣ https://muukii.me ☕ ⌚
  2. 3.
  3. 5.

    ίʔυͰAutoLayoutॻ͘ͳΒ › SnapKit/SnapKit › PureLayout/PureLayout › robb/Cartography <= Couples ͱ

    Pairs ೔ຊ൛Ͱ࢖༻த › stevestreza/Relayout › freshOS/Stevia › roberthein/TinyConstraints › nakiostudio/EasyPeasy <= ࠓͷͱ͜Ζ͓ؾʹೖΓͰւ֎൛PairsͰར༻த › Raizlabs/Anchorage › and more
  4. 11.

    1. AutoLayout͕ϘτϧωοΫʹͳΔέʔε › εΫϩʔϧ͢ΔUI › ϦετܥͷUI (UICollectionView/UITableView)ͷCellͷϨΠΞ΢τʹ࢖༻͞ Ε͍ͯΔ࣌ › ྫ

    : iOSͷ௨஌ηϯλʔ (࠷ۙͷσόΠεͩͱΘ͔ΓͮΒ͍͔΋) › εΫϩʔϧ࣌ʹCellͷத਎ͷϨΠΞ΢τ͕஗͍ͱද͕ࣔ஗ΕΔ › ϑϨʔϜ͕མͪΔ › δϟϯϓ͍ͯ͠ΔΑ͏ʹݟ͑Δ › ໨Ͱ௥͏ͷ͕େม
  5. 14.

    UI͕ߴ଎ʹಈ࡞͢ΔͨΊʹ͸ʁ › ը໘ͷϦϑϨογϡϨʔτ60Hz => ΠϕϯτϧʔϓͰϒϩοΫͯ͠ྑ͍࣌ؒ͸ 16ms (1000ms / 60) ›

    16msΛ௒͍͑ͯ͘ͱϑϨʔϜ͕ͲΜͲΜམ͍ͪͯ͘(υϩοϓϑϨʔϜ) › ͜ͷؒʹUIKitࣗମͷॲཧ΋ೖΔͷͰࢲ͕ͨͪॻ͘ίʔυ͸10ms͙Β͍ʹ͸͍ͨ͠ ΋ͷ › ࠷ۙͷiPad Pro͸120HzʹͳͬͯΔͷͰɺ΋ͬͱ଎͘͠ͳ͍ͱσΟεϓϨΠͷՁ஋ ͸ൃش͞Εͳ͍ɻૢ࡞ʹΑΔεΫϩʔϧͷ଎͞ʹCellͷද͕ࣔ௥͍͔ͭͳ͚Ε͹ͳ Βͳ͍ɻ ͦ΋ͦ΋
  6. 29.
  7. 30.

    Nodeͷछྨ › ASDisplayNode : NSObject › ASTextNode : ASDisplayNode -

    UILabelͷ୅ΘΓ › ASImageNode : ASDisplayNode - UIImageViewͷ୅ΘΓ › ASButtonNode : ASDisplayNode - UIButtonͷ୅ΘΓ › ASCellNode : ASDisplayNode - UICollectionViewCell/UITableViewCellͷ୅ ΘΓ › and more… Texture
  8. 32.

    ڻ͘΄Ͳͷ࠷దԽ › ՄೳͳݶΓόοΫάϥ΢ϯυεϨουͰॲཧΛߦ͏ › UIͷϨεϙϯε଎౓͕࠷େԽ › UILabel΍UIImageView͸࢖ΘΕͣʹϨΠϠʔʹϨϯμϦϯά › λοϓ൑ఆͷඞཁͷͳ͍΋ͷ͸CALayerͱͯ͠දࣔ (layerBacking)

    (UIViewΑΓϝϞϦফඅ͕཈͑ΒΕΔͨΊ) › όοΫάϥ΢ϯυͰϝϞϦղ์Λߦ͏Ωϡʔ (releaseʹ΋CPUίετ͕͔͔ΔͨΊ) › Nodeʹهड़ͨ͠ϨΠΞ΢τ͸όοΫάϥ΢ϯυͰαΠζܭࢉ͕Մೳ › ConcurrentͰ࣮ߦ͞ΕΔͨΊɺNode͕࣋ͭσʔλ͕ଞεϨουʹґଘ͍ͯ͠ͳ͚Ε͹ɺCPUͷίΞ͕ϑ ϧͰ࢖͑Δ › iPhoneXͳΒ6ݸCellಉ࣌ʹܭࢉ Texture
  9. 34.
  10. 35.
  11. 37.

    Texture // Textureʹͳ͚ͬͨͲModuleͷ໊લ͸ݹ͍·· import AsyncDisplayKit class CardNode : ASDisplayNode {

    } TextureͰ͸UIViewͷ୅ΘΓʹ ASDisplayNodeͷαϒΫϥεΛ࡞੒͠·͢ɻ
  12. 38.

    import AsyncDisplayKit class CardNode : ASDisplayNode { private let imageNode:

    ASImageNode = .init() private let titleNode: ASTextNode = .init() private let detailNode: ASTextNode = .init() } ίϯϙʔωϯτΛఆٛ
  13. 39.

    class CardNode : ASDisplayNode { … init(image: UIImage, title: String,

    detail: String) { super.init() titleNode.attributedText = NSAttributedString( string: title, attributes: […] ) detailNode.attributedText = NSAttributedString( string: detail, attributes: […] ) imageNode.image = image 
 addSubnode(imageNode)
 addSubnode(titleNode) addSubnode(detailNode) // addSubnodeͷ୅ΘΓʹ `automaticallyManagesSubnodes = true` Ͱ΋Α͍ } }
  14. 40.

    class CardNode : ASDisplayNode { … override func layoutSpecThatFits(_ constrainedSize:

    ASSizeRange) -> ASLayoutSpec { // ⭐ ͜͜ʹϨΠΞ΢τΛهड़͢Δ } }
  15. 41.

    override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec { return ASRatioLayoutSpec(

    ratio: 1.6, child: ASBackgroundLayoutSpec( child: ASInsetLayoutSpec( insets: .init(top: 8, left: 8, bottom: 8, right: 8), child: ASStackLayoutSpec( direction: .vertical, spacing: 8, justifyContent: .end, alignItems: .start, children: [ titleNode, detailNode, ] ) ), background: imageNode ) ) }
  16. 42.

    override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec { return ASRatioLayoutSpec(

    ratio: 1.6, child: ASBackgroundLayoutSpec( child: ASInsetLayoutSpec( insets: .init(top: 8, left: 8, bottom: 8, right: 8), child: ASStackLayoutSpec( direction: .vertical, spacing: 8, justifyContent: .end, alignItems: .start, children: [ titleNode, detailNode, ] ) ), background: imageNode ) ) }
  17. 43.

    let info = ASStackLayoutSpec( direction: .vertical, spacing: 8, justifyContent: .end,

    alignItems: .start, children: [ titleNode, detailNode, ] ) Vertical
  18. 45.

    class CardNode : ASDisplayNode { … override func layoutSpecThatFits(_ constrainedSize:

    ASSizeRange) -> ASLayoutSpec { return ASRatioLayoutSpec( ratio: 1.6, // ॎ௕ͷΧʔυͰදࣔ͢ΔͨΊbodyͷΞεϖΫτൺΛࢦఆ͢Δ child: body ) } }
  19. 46.

    let node = CardNode( image: UIImage(named: "sample")!, title: "Lorem Ipsum",

    detail: "Lorem Ipsum……" ) view.addSubnode(node) let layout = node.calculateLayoutThatFits( ASSizeRange( min: .init(width: 0.0, height: 0), max: .init(width: 240.0, height: .infinity) ) ) node.frame.size = layout.size In ViewController ࣮ࡍɺ͜͏͍͏ίʔυ͸͋·Γॻ͔ͳ͍Ͱ͢ɻ CardNodeΛॳظԽ ViewController.viewʹaddSubnode nodeͷαΠζܭࢉΛߦ͏ αΠζͷRangeΛ༩͑Δ UIView.sizeThatFitsͷײ֮
  20. 47.
  21. 48.

    let insetInfo = ASInsetLayoutSpec( insets: UIEdgeInsets( top: 8, left: 8,

    bottom: 8, right: 8 ), child: info ) let info = ASStackLayoutSpec( direction: .vertical, spacing: 8, justifyContent: .end, alignItems: .start, children: [ titleNode, detailNode, ] )
  22. 49.

    let body = ASBackgroundLayoutSpec( child: info, background: imageNode ) let

    body = ASBackgroundLayoutSpec( child: insetInfo, background: imageNode )
  23. 50.
  24. 51.

    override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec { return ASRatioLayoutSpec(

    ratio: 1.6, child: ASBackgroundLayoutSpec( child: ASInsetLayoutSpec( insets: .init(top: 8, left: 8, bottom: 8, right: 8), child: ASStackLayoutSpec( direction: .vertical, spacing: 8, justifyContent: .end, alignItems: .start, children: [ titleNode, detailNode, ] ) ), background: imageNode ) ) } શ෦·ͱΊΔͱ
  25. 52.

    DispatchQueue.global().async { let layout = node.calculateLayoutThatFits( ASSizeRange( min: .init(width: 0.0,

    height: 0), max: .init(width: 240.0, height: .infinity) ) ) DispatchQueue.main.async { node.frame.size = layout.size } } όοΫάϥ΢ϯυͰαΠζܭࢉ
  26. 54.

    ·ͱΊ › ͜ͷݱঢ়ʹରͯ͠ɺFacebook,Instagram,PinterestͷΑ͏ͳαʔϏε͸ϓϩμΫτʹ͓ ͍ͯAutoLayoutͷ࢖༻Λආ͚͓ͯΓɺͦΕͧΕ͕UIύϑΥʔϚϯεΛ࠷େԽ͢ΔOSS Λެ։͍ͯ͠Δ › Pinterest - Texture ›

    Facebook - ComponentKit, ReactNative, Texture › Instagram - IGListKit (ͪΐͬͱझࢫ͸ҧ͏͚Ͳ) › ͜ͷঢ়گʹରͯ͠ɺࠓޙApple͕औΔUIKit΁ͷߟָ͕͑͠ΈͰ͢ɻAutoLayoutؤுͬ ͯཉ͍͠Ͱ͢Ͷʂ
  27. 55.