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

Андрей Рычков – Жизнь без AutoLayout

CocoaHeads
December 08, 2017

Андрей Рычков – Жизнь без AutoLayout

В своем докладе Андрей Рычков обозначил проблемы AutoLayout и рассмотрел различные альтернативы, которые помогут их решить.

CocoaHeads

December 08, 2017
Tweet

More Decks by CocoaHeads

Other Decks in Programming

Transcript

  1. L I F E W I T H O U

    T 
 A U TO L AY O U T Andrei Rychkov 1
  2. P L A N 1. AutoLayout system & its problems

    2. Manual layout 3. Existing solutions 2
  3. 3

  4. 4

  5. 5

  6. 6

  7. 7 redView.trailing = 1.0 * blueView.leading + 8.0 redView.leading =

    1.0 * superview.leading + 0.0 … redView.width = 2.0 * blueView.width + 0.0 }
  8. A U T O L AY O U T P

    R O S • Interface Builder • Declarative style • Reaction to internal changes • Reaction to external changes 8
  9. A U T O L AY O U T C

    O N S • Interface Builder • Performance • Black box • Non-deterministic behaviour 9
  10. 10

  11. P E R F O R M A N C

    E T E S T S • iPhone 7 • iOS 11 • Release mode • Optimisation turned on • UICollectionView 11
  12. Layout time (ms) 0 125 250 375 500 Number of

    cells 10 20 30 40 50 60 70 80 90 100 Auto Layout UIStackView 12
  13. 14

  14. override func layoutSubviews() { viewA.frame = CGRect( x: 100, y:

    150, width: 100, height: 100 ) viewB.frame = CGRect( x: 100, y: viewA.frame.maxY + 8, width: 100, height: 50 ) } 15
  15. M A N U A L L AY O U

    T P R O S • Power • Flexibility 16
  16. M A N U A L L AY O U

    T C O N S • Hard to read • Hard to maintain • No reaction to internal or external changes • No RTL 17
  17. Layout time (ms) 0 125 250 375 500 Number of

    cells 10 20 30 40 50 60 70 80 90 100 Auto Layout UIStackView Manual 18
  18. C O M M O N G O A L

    S • Appropriate performance • Easy to understand • Easy to maintain 19
  19. 20

  20. L AY O U T K I T H I

    S T O RY • 2015, December – LinkedIn redesign • Customers experienced delays • Profiling revealed the issue – AutoLayout • Developers optimised main thread code • Still not enough! • 2016, June - LayoutKit open sourced 21
  21. protocol Layout { func measurement(within maxSize: CGSize) -> LayoutMeasurement func

    arrangement( within rect: CGRect, measurement: LayoutMeasurement) -> LayoutArrangement var needsView: Bool { get } func makeView() -> View func configure(baseTypeView: View) var flexibility: Flexibility { get } } 22
  22. B A S I C L AY O U T

    S • LabelLayout • ButtonLayout • SizeLayout • InsetLayout • StackLayout 23
  23. 24

  24. 25

  25. let imageLayout = SizeLayout<UIImageView>( width: 80, height: 80, alignment: .center)

    { imageView in imageView.image = UIImage(named: "scarlet_sm") imageView.layer.cornerRadius = 40 imageView.layer.masksToBounds = true } 26
  26. let heroNameLayout = LabelLayout( text: "Spider-Man", font: .systemFont(ofSize: 40) )

    let realNameLayout = LabelLayout( text: "Ben Reilly", font: .systemFont(ofSize: 24)) { label in label.textColor = .darkGray } 27
  27. let insetLayout = InsetLayout( insets: UIEdgeInsets(top: 8, left: 8, bottom:

    8, right: 8), sublayout: StackLayout( axis: .horizontal, spacing: 8, sublayouts: [ imageLayout, labelsLayout ] ) ) insetLayout.arrangement().makeViews(in: view) 29
  28. 30

  29. L AY O U T K I T P R

    O S • Declarative • No containers • Separate layout object • Asynchronous calculations 31
  30. L AY O U T K I T C O

    N S • Duplication • Layout updated – hierarchy recreated • Action handling is hard 32
  31. Layout time (ms) 0 125 250 375 500 Number of

    cells 10 20 30 40 50 60 70 80 90 100 Auto Layout UIStackView Manual LayoutKit 33
  32. Y O G A • Cross-platform layout engine created by

    Facebook • Written in C • Implements FlexBox • YogaKit – Objective-C implementation 35
  33. @interface UIView (Yoga) @property (nonatomic, readonly, strong) YGLayout *yoga; -

    (void)configureLayoutWithBlock:(YGLayoutConfigurationBlock)block @end 36
  34. • FlexDirection • JustifyContent • AlignItems • AlignContent Y O

    G A P R O P E R T I E S • AlignSelf • FlexGrow • FlexShrink 37
  35. let imageView = UIImageView(image: UIImage(named: "ultimate_sm")) imageView.layer.masksToBounds = true imageView.layer.cornerRadius

    = 40 addSubview(imageView) let labelsContainer = UIView() addSubview(labelsContainer) let heroNameLabel = UILabel() heroNameLabel.font = UIFont.systemFont(ofSize: 40) heroNameLabel.text = "Spider-Man" labelsContainer.addSubview(heroNameLabel) let realNameLabel = UILabel() realNameLabel.font = UIFont.systemFont(ofSize: 24) realNameLabel.textColor = .darkGray realNameLabel.text = "Miles Morales" labelsContainer.addSubview(realNameLabel) 38
  36. heroNameLabel.configureLayout { layout in layout.isEnabled = true } realNameLabel.configureLayout {

    layout in layout.isEnabled = true layout.marginTop = 2 } 39 labelsContainer.configureLayout { layout in layout.isEnabled = true layout.marginStart = 8 }
  37. configureLayout { layout in layout.isEnabled = true layout.flexDirection = .row

    layout.alignItems = .center layout.padding = 8 } imageView.configureLayout { layout in layout.isEnabled = true layout.width = 80 layout.aspectRatio = 1.0 } 40
  38. 42

  39. Y O G A K I T P R O

    S • Know FlexBox = know Yoga • Unique alignment for each view in a container • Unique spacing for each view in a container 43
  40. Y O G A K I T C O N

    S • No reaction to external & internal changes • No spacing property for container view • Not native implementation 44
  41. Layout time (ms) 0 10 20 30 40 Number of

    cells 10 20 30 40 50 60 70 80 90 100 Manual LayoutKit YogaKit 45
  42. 46

  43. T E X T U R E • Developed by

    Facebook as AsyncDisplayKit • Used in Paper • Main purpose – free the main thread • Now maintained by Pinterest 47
  44. • Abstraction over UIView • Thread-safe • Mostly has same

    methods and properties • Has the same common subclasses N O D E 48
  45. private let heroNameNode: ASTextNode = { let node = ASTextNode()

    node.attributedText = NSAttributedString( string: "Spider-Man", attributes: [ .font: UIFont.systemFont(ofSize: 40), .foregroundColor: UIColor.black ] ) return node }() 49
  46. private let realNameNode: ASTextNode = { let node = ASTextNode()

    node.attributedText = NSAttributedString( string: "Otto Octavius", attributes: [ .font: UIFont.systemFont(ofSize: 24), .foregroundColor: UIColor.darkGray ] ) return node }() 50
  47. private let imageNode: ASImageNode = { let imageNode = ASImageNode()

    imageNode.image = UIImage(named: “superior_sm”) imageNode.clipsToBounds = true imageNode.cornerRadius = 40 imageNode.style.width = ASDimensionMake(80) imageNode.style.height = ASDimensionMake(80) return imageNode }() 51
  48. override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec { return ASInsetLayoutSpec(

    insets: UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8), child: ASStackLayoutSpec( direction: .horizontal, spacing: 8, justifyContent: .start, alignItems: .center, children: [ imageNode, ASStackLayoutSpec( direction: .vertical, spacing: 2, justifyContent: .start, alignItems: .stretch, children: [ heroNameNode, realNameNode ] ) ] ) ) } 52
  49. 53

  50. T E X T U R E P R O

    S • Constantly 60 FPS • Can be used in UIView hierarchy • Many conveniences • Immutable layouts 54
  51. T E X T U R E C O N

    S • Highly depends on UIKit • Must think about thread safety • Not Auto Layout friendly • Large dependency 55
  52. Layout time (ms) 0 125 250 375 500 Number of

    cells 10 20 30 40 50 60 70 80 90 100 Auto Layout UIStackView Manual LayoutKit YogaKit Texture 56
  53. C O N C L U S I O N

    • Don’t extensively use UIStackView • Think about constraints you made • Use manual layout when needed • Not enough? Make background measurements 57
  54. Layout time (ms) 0 1000 2000 3000 4000 UIStackView Auto

    Layout YogaKit Manual Layout LayoutKit Texture 1 0 0 0 C E L L S , I P H O N E 7 58
  55. W H Y N O T U I TA B

    L E V I E W ? 59
  56. T H A N K S F O R Y

    O U R AT T E N T I O N a_rychkov 60