Upgrade to Pro — share decks privately, control downloads, hide ads and more …

AutoLayout以外の選択肢

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.
Avatar for Muukii Muukii
March 28, 2018

 AutoLayout以外の選択肢

Avatar for Muukii

Muukii

March 28, 2018
Tweet

More Decks by Muukii

Other Decks in Programming

Transcript

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

    eureka, Inc. ‣ Pairs Global Team ‣ GitHub : @muukii ‣ https://muukii.me ☕ ⌚
  2. ίʔυͰAutoLayoutॻ͘ͳΒ › SnapKit/SnapKit › PureLayout/PureLayout › robb/Cartography <= Couples ͱ

    Pairs ೔ຊ൛Ͱ࢖༻த › stevestreza/Relayout › freshOS/Stevia › roberthein/TinyConstraints › nakiostudio/EasyPeasy <= ࠓͷͱ͜Ζ͓ؾʹೖΓͰւ֎൛PairsͰར༻த › Raizlabs/Anchorage › and more
  3. 1. AutoLayout͕ϘτϧωοΫʹͳΔέʔε › εΫϩʔϧ͢ΔUI › ϦετܥͷUI (UICollectionView/UITableView)ͷCellͷϨΠΞ΢τʹ࢖༻͞ Ε͍ͯΔ࣌ › ྫ

    : iOSͷ௨஌ηϯλʔ (࠷ۙͷσόΠεͩͱΘ͔ΓͮΒ͍͔΋) › εΫϩʔϧ࣌ʹCellͷத਎ͷϨΠΞ΢τ͕஗͍ͱද͕ࣔ஗ΕΔ › ϑϨʔϜ͕མͪΔ › δϟϯϓ͍ͯ͠ΔΑ͏ʹݟ͑Δ › ໨Ͱ௥͏ͷ͕େม
  4. UI͕ߴ଎ʹಈ࡞͢ΔͨΊʹ͸ʁ › ը໘ͷϦϑϨογϡϨʔτ60Hz => ΠϕϯτϧʔϓͰϒϩοΫͯ͠ྑ͍࣌ؒ͸ 16ms (1000ms / 60) ›

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

    UILabelͷ୅ΘΓ › ASImageNode : ASDisplayNode - UIImageViewͷ୅ΘΓ › ASButtonNode : ASDisplayNode - UIButtonͷ୅ΘΓ › ASCellNode : ASDisplayNode - UICollectionViewCell/UITableViewCellͷ୅ ΘΓ › and more… Texture
  6. ڻ͘΄Ͳͷ࠷దԽ › ՄೳͳݶΓόοΫάϥ΢ϯυεϨουͰॲཧΛߦ͏ › UIͷϨεϙϯε଎౓͕࠷େԽ › UILabel΍UIImageView͸࢖ΘΕͣʹϨΠϠʔʹϨϯμϦϯά › λοϓ൑ఆͷඞཁͷͳ͍΋ͷ͸CALayerͱͯ͠දࣔ (layerBacking)

    (UIViewΑΓϝϞϦফඅ͕཈͑ΒΕΔͨΊ) › όοΫάϥ΢ϯυͰϝϞϦղ์Λߦ͏Ωϡʔ (releaseʹ΋CPUίετ͕͔͔ΔͨΊ) › Nodeʹهड़ͨ͠ϨΠΞ΢τ͸όοΫάϥ΢ϯυͰαΠζܭࢉ͕Մೳ › ConcurrentͰ࣮ߦ͞ΕΔͨΊɺNode͕࣋ͭσʔλ͕ଞεϨουʹґଘ͍ͯ͠ͳ͚Ε͹ɺCPUͷίΞ͕ϑ ϧͰ࢖͑Δ › iPhoneXͳΒ6ݸCellಉ࣌ʹܭࢉ Texture
  7. Texture // Textureʹͳ͚ͬͨͲModuleͷ໊લ͸ݹ͍·· import AsyncDisplayKit class CardNode : ASDisplayNode {

    } TextureͰ͸UIViewͷ୅ΘΓʹ ASDisplayNodeͷαϒΫϥεΛ࡞੒͠·͢ɻ
  8. import AsyncDisplayKit class CardNode : ASDisplayNode { private let imageNode:

    ASImageNode = .init() private let titleNode: ASTextNode = .init() private let detailNode: ASTextNode = .init() } ίϯϙʔωϯτΛఆٛ
  9. 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` Ͱ΋Α͍ } }
  10. class CardNode : ASDisplayNode { … override func layoutSpecThatFits(_ constrainedSize:

    ASSizeRange) -> ASLayoutSpec { // ⭐ ͜͜ʹϨΠΞ΢τΛهड़͢Δ } }
  11. 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 ) ) }
  12. 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 ) ) }
  13. let info = ASStackLayoutSpec( direction: .vertical, spacing: 8, justifyContent: .end,

    alignItems: .start, children: [ titleNode, detailNode, ] ) Vertical
  14. class CardNode : ASDisplayNode { … override func layoutSpecThatFits(_ constrainedSize:

    ASSizeRange) -> ASLayoutSpec { return ASRatioLayoutSpec( ratio: 1.6, // ॎ௕ͷΧʔυͰදࣔ͢ΔͨΊbodyͷΞεϖΫτൺΛࢦఆ͢Δ child: body ) } }
  15. 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ͷײ֮
  16. 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, ] )
  17. let body = ASBackgroundLayoutSpec( child: info, background: imageNode ) let

    body = ASBackgroundLayoutSpec( child: insetInfo, background: imageNode )
  18. 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 ) ) } શ෦·ͱΊΔͱ
  19. 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 } } όοΫάϥ΢ϯυͰαΠζܭࢉ
  20. ·ͱΊ › ͜ͷݱঢ়ʹରͯ͠ɺFacebook,Instagram,PinterestͷΑ͏ͳαʔϏε͸ϓϩμΫτʹ͓ ͍ͯAutoLayoutͷ࢖༻Λආ͚͓ͯΓɺͦΕͧΕ͕UIύϑΥʔϚϯεΛ࠷େԽ͢ΔOSS Λެ։͍ͯ͠Δ › Pinterest - Texture ›

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