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

Александр Зимин (Uberchord Engineering), Интерфейс по кусочкам: эффективное взаимодействие между iOS разработчиком и дизайнером, CodeFest 2017

CodeFest
February 01, 2018

Александр Зимин (Uberchord Engineering), Интерфейс по кусочкам: эффективное взаимодействие между iOS разработчиком и дизайнером, CodeFest 2017

https://2017.codefest.ru/lecture/1192

С каждым месяцем появляется все больше новых подходов, архитектурных паттернов и библиотек для разработки мобильных приложений. В то же время очень мало разговоров о работе с UI и передачу ресурсов от дизайнера к разработчику. В этом докладе Александр поделится лучшими практиками взаимодействия iOS разработчиков и дизайнеров в их команде с примерами из реальной жизни.

CodeFest

February 01, 2018
Tweet

More Decks by CodeFest

Other Decks in Technology

Transcript

  1. План • Проблемы • Цвета и шрифты • Передача ассетов

    • Свизлинг для дизайна • Планы на будущее
  2. extension UIColor { enum ColorType: String { case gray =

    "8C8C8C" case darkGray = "6C6C6C" } convenience init(_ colorType: ColorType) { self.init(hexString: colorType.rawValue) } }
  3. extension UIColor { enum ComponentType { case navigationBar case separator

    var colorType: ColorType { switch self { case .navigationBar: return .gray case .separator: return .darkGray } } } convenience init(componentType: ComponentType) { self.init(componentType.colorType) } }
  4. extension UIColor { enum ComponentType { case navigationBar case separator

    var colorType: ColorType { switch self { case .navigationBar: return .gray case .separator: return .darkGray } } } convenience init(componentType: ComponentType) { self.init(componentType.colorType) } } Не может содержать HEX строк!
  5. extension UIFont { enum FontType { case gothamProMedium(size: CGFloat) case

    gothamPro(size: CGFloat) } convenience init(_ fontType: FontType) { switch fontType { case let .gothamProMedium(size): self.init(name: "GothamPro-Medium", size: size)! case let .gothamPro(size): self.init(name: "GothamPro", size: size)! } } }
  6. private var swizzleTextValue: Void = { swizzleMethods(objectClass: UILabel.self, originalSelector: #selector(setter:

    UILabel.text), swizzledSelector: #selector(UILabel.setStaticText(_:))) }() extension UILabel { open override class func initialize() { _ = swizzleTextValue } @objc fileprivate func setStaticText(_ text: String?) { setStaticText(text) // You actions } }
  7. private var swizzleTextValue: Void = { swizzleMethods(objectClass: UILabel.self, originalSelector: #selector(setter:

    UILabel.text), swizzledSelector: #selector(UILabel.setStaticText(_:))) }() extension UILabel { open override class func initialize() { _ = swizzleTextValue } @objc fileprivate func setStaticText(_ text: String?) { setStaticText(text) // You actions } }
  8. private var swizzleTextValue: Void = { swizzleMethods(objectClass: UILabel.self, originalSelector: #selector(setter:

    UILabel.text), swizzledSelector: #selector(UILabel.setStaticText(_:))) }() extension UILabel { open override class func initialize() { _ = swizzleTextValue } @objc fileprivate func setStaticText(_ text: String?) { setStaticText(text) // You actions } } Плохо!
  9. extension UILabel { static func swizzleText() { _ = swizzleTextValue

    } @objc fileprivate func setStaticText(_ text: String?) { setStaticText(text) // You actions } }
  10. extension UILabel { static func swizzleText() { _ = swizzleTextValue

    } // ... } • Вызывать swizzleText(): • Где нибудь в AppDelegate или его проксировании • Вызывать в load() у UILabel в Obj-c
  11. let value = clock() for i in 0..<1000000 { cell.textLabel?.text

    = "\(i)" } let result = Double(clock() - value) print(result)
  12. До свизлинга Плосле свизлинга 2463609.0 2665523.0 2238332.0 2565639.0 2240086.0 2560924.0

    2278225.0 2579298.0 2247269.0 2561646.0 2246613.0 2563499.0 2228041.0 2571111.0 15%
  13. private var swizzleTextValue: Void = { swizzleMethods(objectClass: UILabel.self, originalSelector: #selector(setter:

    UILabel.text), swizzledSelector: #selector(UILabel.setLocalizedText(_:))) }()
  14. extension UILabel { static func swizzleText() { _ = swizzleTextValue

    } @objc fileprivate func setLocalizedText(_ text: String?) { if let text = text, !isInsideButton { setLocalizedText(text.tripleLengthPseudolanguage) } else { setLocalizedText(text) } } private var isInsideButton: Bool { let superview = self.superview return superview is UIButton } }
  15. @implementation UINavigationItem (AZTitleConfiguration) + (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken,

    ^{ SwizzleInstanceMethod(self, @selector(setTitle:), @selector(az_setTitleWithConfiguration:)); }); } @end
  16. // We setup view with our own label, because we

    want to use kern spacing and other appearance staf - (void)az_setTitleWithConfiguration:(NSString *)title { if (title == nil) { title = @""; } [self az_setTitleWithConfiguration:[title uppercaseString]]; NSDictionary *attributes = [[UINavigationBar appearance] titleTextAttributes]; NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:[title uppercaseString] attributes:attributes]; // … fill self.titleView if already UILabel UILabel *titleLabel = [UILabel new]; titleLabel.attributedText = attributedString; [titleLabel sizeToFit]; self.titleView = titleLabel; }
  17. // We setup view with our own label, because we

    want to use kern spacing and other appearance staf - (void)az_setTitleWithConfiguration:(NSString *)title { if (title == nil) { title = @""; } [self az_setTitleWithConfiguration:[title uppercaseString]]; NSDictionary *attributes = [[UINavigationBar appearance] titleTextAttributes]; NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:[title uppercaseString] attributes:attributes]; // … fill self.titleView if already UILabel UILabel *titleLabel = [UILabel new]; titleLabel.attributedText = attributedString; [titleLabel sizeToFit]; self.titleView = titleLabel; }
  18. // We setup view with our own label, because we

    want to use kern spacing and other appearance staf - (void)az_setTitleWithConfiguration:(NSString *)title { if (title == nil) { title = @""; } [self az_setTitleWithConfiguration:[title uppercaseString]]; NSDictionary *attributes = [[UINavigationBar appearance] titleTextAttributes]; NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:[title uppercaseString] attributes:attributes]; // … fill self.titleView if already UILabel UILabel *titleLabel = [UILabel new]; titleLabel.attributedText = attributedString; [titleLabel sizeToFit]; self.titleView = titleLabel; }
  19. // We setup view with our own label, because we

    want to use kern spacing and other appearance staf - (void)az_setTitleWithConfiguration:(NSString *)title { if (title == nil) { title = @""; } [self az_setTitleWithConfiguration:[title uppercaseString]]; NSDictionary *attributes = [[UINavigationBar appearance] titleTextAttributes]; NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:[title uppercaseString] attributes:attributes]; // … fill self.titleView if already UILabel UILabel *titleLabel = [UILabel new]; titleLabel.attributedText = attributedString; [titleLabel sizeToFit]; self.titleView = titleLabel; } if ([self.titleView isKindOfClass:[UILabel class]]) { UILabel *label = (UILabel*)self.titleView; label.attributedText = attributedString; return; }
  20. @implementation NSLayoutConstraint (UCConstraintBuild) - (void)setScreenWidthPercent:(CGFloat)screenWidthPercent { self.constant = round([self screenBounds].size.width

    * screenWidthPercent); } - (CGFloat)screenWidthPercent { return (self.constant / [self screenBounds].size.width); } @end
  21. { "colors": [ { "name": "lightWhite", "color": "F5F5F5" } ],

    "fonts": [ { "name": "bold", "fontName": "ProximaNova-Extrabld" } ] }
  22. "styles": { "text.default": { "font.size": 20, "font.name": "SFUIText-Light", "textColor": "red"

    }, "text.title": { "parents": ["text.default"], "font.name": "bold", "textColor": "$themeColor" } }
  23. extension UILabel: Stylable { func apply(style: Style) { // ...

    } } label.apply(style: Styles.Text.Title)
  24. @objc protocol Foo { init() } final class Bar: Foo

    { init() {} deinit { print("destroying") } } let x: Foo.Type = Bar.self _ = x.init()
  25. @objc protocol Foo { init() } final class Bar: Foo

    { init() {} deinit { print("destroying") } } let x: Foo.Type = Bar.self _ = x.init()
  26. protocol Foo { init() } final class Bar: Foo {

    init() {} deinit { print("destroying") } } let x: Foo.Type = Bar.self _ = x.init()