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

AutoLayout以外の選択肢

Muukii
March 28, 2018

 AutoLayout以外の選択肢

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ؤுͬ ͯཉ͍͠Ͱ͢Ͷʂ