Share
Embed
UIColor Anatomy
iOSDC Japan 2020 #iosdc
「大解剖!UIColorファミリー」発表資料です。
https://fortee.jp/iosdc-japan-2020/proposal/8617aa4c-5386-4629-abf4-3e93ebfe2962
Shigure Shimotori
September 21, 2020
Transcript
64 slides
-
UIColor var red: CGFloat var green: CGFloat var blue: CGFloat
ม? init(white:alpha:) init(cgColor:) ❌ 10 -
͠UIColor͕୯ମͰଘࡏ͍ͯͨ͠Β(1/2) class UIColor { private let redComponent: CGFloat? private let
greenComponent: CGFloat? private let blueComponent: CGFloat? private let whiteComponent: CGFloat? private let alphaComponent: CGFloat? private let provider: ((UITraitCollection) -> UIColor)? private let image: UIImage? 以下略 12 -
͠UIColor͕୯ମͰଘࡏ͍ͯͨ͠Β(2/2) func withAlphaComponent() -> UIColor { if /*RGBで表現されているとき*/ { }
else if /*色空間がdisplay P3のとき*/ { } else if /*パターンイメージを使うとき*/ { } else if /*dynamic colorのとき*/ { 以下略 13 -
࣮ࡍͷUIColor͜Μͳײ͡ʁ UIColor public init(red: CGFloat, ..., alpha: CGFloat) { return
UIDeviceRGBColor() } public init(patternImage: CGFloat) { return UIDynamicPatternColor() } var cgColor: CGColor { get } UIDeviceRGBColor UIDynamicPatternColor let redComponent: CGFloat override var cgColor: CGColor { /*適切な処理*/ } let image: UIImage override var cgColor: CGColor { /*適切な処理*/ } RGB୲ ύλʔϯΠϝʔδ୲ 17 ɿਖ਼֬Ͱ͋Γ·ͤΜ -
৭ͷܾఆํ๏͕͍ͬͺ͍ʂ • init(white:alpha:) • init(red:green:blue:alpha:) / init(hue:saturation:brightness:alpha:) • init(displayP3Red:green:blue:alpha:) •
init(named:) / init(named:in:compatibleWith:) • init(dynamicProvider:) • init(ciColor:) • init(cgColor:) • init(patternImage:) • init(_:) ※SwiftUI.ColorɻiOS14.0ʙ શ෦ҧ͏αϒΫϥε͕ฦͬͯ͘Δ ʢͪΖΜݟ͔͚public class UIColorʣ 18 గਖ਼ʢ2020/09/20ʣ init(_:)طଘͷΫϥεΛฦ༷͢ɻ -
ͦͷલʹɿUIColorͷཪଆΛ͢Δखஈ • class-dump • Objective CͷϔομΛ͚Δπʔϧ • Method swizzlingɺXcodeͷSymbolic Breakpoint
• ಛఆͷϝιου͕ݺΕͨॠؒΛั·͑Δ • ԿΛ͍ͯ͠Δ͔ͪΐͬͱΘ͔Δ • object_getClass(_:) • ܕ໊ͷऔಘ • type(of:)ͩͱ͏·͘औΕͳ͍ 21 -
class-dumpͰ͍ͯΈͨ UIKitCore.framework/UIDeviceRGBColor.hʢҰ෦ൈਮʣ #import <UIKitCore/UIColor.h> __attribute__((visibility("hidden"))) @interface UIDeviceRGBColor : UIColor {
double redComponent; double greenComponent; double blueComponent; double alphaComponent; struct CGColor *_cachedColor; } - (_Bool)getWhite:(double *)arg1 alpha:(double *)arg2; Copyright (C) 1997-2019 Steve Nygard. 22 -
2-3. UI(Cached)DeviceRGBColor • RGBͰࢦఆ͞ΕΔ৭ͷͨΊͷΫϥε • RGBAίϯϙʔωϯτΛड͚औΓɺอ͓࣋ͯ͘͠ • init(red:green:blue:alpha:)Ͱ࡞ͬͨͱ͖UIDeviceRGBColor • init(hue:saturation:brightness:alpha:)͜Ε
• UIColor.redUIColor.greenUICachedDeviceRGBColor • Apple͕༻ҙͯ͘͠ΕͨRGBͷ৭ͷ͏ͪɺstatic colorͰ͋Δͷ 26 -
7. UIDynamicColor • dynamic colorͷ • iOSʹ͓͍ͯdynamicͱʮtraitͷมԽʹԠͯ͡ಈతʹมΘΔʯͱ͍͏͜ͱ • var _isDynamic:
Bool { get } ͕ਅ • ͜Ε͕ਅͳΒtraitͷมԽʹै͢ΔΒ͍͠ 31 -
9. UIDynamicCatalogColor • Asset Catalog init(named:) ͔ΒಘΒΕΔ • 1ͭͰDark ModeରԠͷ৭Λ࡞ͬͯ͋Δͱશͯͷ৭͕͜ͷΫϥεͰදݱ͞ΕΔ
ʢstatic color͔͠ͳ͍߹static color༻ͷΫϥεΛ͍͚Δʣ 33 -
12. UIDynamicAppDefinedColor • ରԠ͢ΔΠχγϟϥΠβͳ͠ • ྫ͑UIDynamicProviderColorΛarchive & unarchive͢Δͱ͜ͷܕʹͳΔ • [UITraitCollection:
UIColor] ͷ͔ͨͪͰه͢Δ • ଞʹಇ͍͍ͯΔͱ͜Ζ͕͋ͬͨΒڭ͍͑ͯͩ͘͞ 36 -
14. UICIColor • init(ciColor:)ͰಘΒΕΔΫϥε • CIColorΛड͚औͬͯอ࣋͢Δ͔ΒUICIColor • CI = CoreImage.framework
• ड͚औͬͨCIColorΛ෦ʹӅ͍࣋ͬͯ͠Δ • var ciColor: CIColor { get } ͦͷ··ฦ͚ͩ͢ͷॲཧΛ͍ͯ͠ΔΈ͍ͨ 39 -
15. UICGColor • init(cgColor:)ͰಘΒΕΔΫϥε • ෦ʹCGColorΛӅ͍࣋ͬͯ͠Δ • var cgColor: CGColor
{ get } ͦͷ··ฦ͚ͩ͢ • UICGColorαϒΫϥεΛ࣋ͭ 40 -
16-17. UI(Cached)PatternCGColor • init(cgColor:)ͰಘΒΕΔΫϥεͦͷ2 • PatternͳCGColorͷͨΊͷΫϥε • ڪΒ͘ var pattern:
CGPattern? { get } Λ͍࣋ͬͯΔΑ͏ͳCGColor • खͬऔΓૣ͍ྫɿUIColor.init(cgColor: UIColor.init(patternImage: image).cgColor) • CachedΫϥεΛ࣋ͭʢUICachedPatternCGColorʣ 41 -
UIPatternCGColorΛ࡞Δ let drawPattern: CGPatternDrawPatternCallback = { info, context in let
subunit = CGFloat(20.0) context.setFillColor(red: 0.5, green: 0, blue: 0, alpha: 1) context.fill(CGRect(x: 0, y: 0, width: subunit, height: subunit)) context.setFillColor(red: 1, green: 0.3, blue: 0.3, alpha: 1) context.fill(CGRect(x: subunit, y: subunit, width: subunit, height: subunit)) context.setFillColor(red: 0.7, green: 0.3, blue: 0, alpha: 1) context.fill(CGRect(x: 0, y: subunit, width: subunit, height: subunit)) context.setFillColor(red: 0.7, green: 0.3, blue: 0, alpha: 1) context.fill(CGRect(x: subunit, y: 0, width: subunit, height: subunit)) } var callbacks = CGPatternCallbacks(version: 0, drawPattern: drawPattern, releaseInfo: nil) let pattern = CGPattern(info: nil, bounds: CGRect(x: 0, y: 0, width: 1, height: 1), matrix: CGAffineTransform(a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0), xStep: 40, yStep: 40, tiling: .constantSpacing, isColored: true, callbacks: &callbacks)! let color = UIColor(cgColor: CGColor(patternSpace: CGColorSpace(patternBaseSpace: nil)!, pattern: pattern, components: [1, 1, 1, 1])!) ࣈదͰ͢ 42 -
DataܕΛհͯ͠৭σʔλΛ෮ݩͰ͖ͪΌͬͨ Cocoa.NSColor→Data→UIColor let color = Cocoa.NSColor(calibratedWhite: 0.5, alpha: 0.5) let
colorData = try! NSKeyedArchiver.archivedData( withRootObject: color, requiringSecureCoding: true ) try! colorData.write(to: URL(fileURLWithPath: 略)) let data = try! Data(contentsOf: URL(fileURLWithPath: 略)) let color = try! NSKeyedUnarchiver.unarchivedObject( ofClasses: [UIColor.self], from: data ) // ここでUIKit.NSColor.init(coder:)が呼ばれる print(color) // Optional(UIExtendedGrayColorSpace 0.5 0.5) 45 -
• ·ͣαϒΫϥεΛ࡞Δ • ϓϩύςΟϝιουΛܧঝͯ͠ઐ༻ͷॲཧΛ࣮͓ͯ͘͠ ྫ͑͜Μͳײ͡ (1/2) @implementation MyColor: UIColor -
(instancetype _Nonnull)initWithMyProperty:略 { 略 return self; } - (CGColorRef)CGColor { // 必要なプロパティやメソッドを継承 return 略; } 略 @end 49 -
• UIColorʹ࡞༻ͷΠχγϟϥΠβΛ࣋ͨͤΔ • privateͳαϒΫϥεͷΠϯελϯεΛ࡞͢ΔखஈΛ༻ҙ͢Δ ྫ͑͜Μͳײ͡ (2/2) @implementation UIColor(MyColor) // UIColorにイニシャライザを持たせる
- (UIColor * _Nonnull)initWithMyProperty:略 { return [[MyColor alloc] initWithMyProperty:略]; } @end 50 -
ޙ͚ͰαϒΫϥεΛ࡞͢Δ߹ͷқ • UIColorԼʹ࡞Δɿ؆୯ͳͷͳΒOK • ܧঝΛΕͨϝιουϓϩύςΟ͕͋Δͱ࠷ѱΫϥογϡ͢ΔͷͰҙ • SwiftͰͷ࣮ແཧʢHAKATA.swiftͰͷൃදΛݟͯͶʣ • privateͳαϒΫϥεͷԼʹ͚ͭΔɿແཧ •
खग़͠Ͱ͖ͳ͍ • dynamic colorpattern colorΛ࡞Δɿ࣮࣭ແཧ • ϓϩύςΟ͕privateͳͷͰ͍͡ΔͱౖΒΕͦ͏ 51 -
αϒΫϥεʹࢧ͑ΒΕͨϝιου&ϓϩύςΟ • withAlphaComponent(_:) • resolvedColor(with:) • cgColor, ciColor • set(),
setFill(), setStroke() • getHue(ུ) / getRed(ུ) / getWhite(ུ) • isEqual(to:) ⚠αϒΫϥε͝ͱʹಈ࡞͕ҟͳΔ͔⚠ 55 -
withAlphaComponent(_:) • UIPlaceholderColorಛఆͷ৭Λࢦ͍ͯ͠ͳ͍ͷͰΫϥογϡ • static colorͰ୯७ʹalpha componentΛ্ॻ͖͢ΕOK • ݩͱಉ͡Ϋϥε͕Γͱͯ͠ฦ͞ΕΔ •
alpha componentҎ֎มߋ͞Εͳ͍ • dynamic colorղܾͷͨͼʹalpha componentΛ্ॻ͖͢Δඞཁ͕͋Δ • ͭ·ΓUIDynamicModifiedColor͕ཁΔ • ͜ͷϝιουΛ࣮ߦͯ͠ݩͷUIDynamicColorҡ࣋͞ΕΔ 56 -
cgColorɺ resolvedColor(with:) ৭ͷղܾ • UIPlaceholderColorಛఆͷ৭Λࢦ͍ͯ͠ͳ͍ͷͰΫϥογϡ • dynamic colorʹͱͬͯಛఆͷҰ৭ʹܾఆ͢Δૢ࡞ • cgColorUITraitCollection.currentΛ͍ͬͯΔΑ͏ʹݟ͑Δ
• ྫ: layer.borderColor = dynamicColor.cgColor ࠷ॳ͚ͩਖ਼͍͠৭Ͱදࣔ͞ΕΔ • resolvedColor(with:)Ͱ͋Ε༩͑ͨUITraitCollectionͰ 57 -
isEqual(to:) • UIPlaceholderColorಛఆͷ৭Λࢦ͍ͯ͠ͳ͍ͷͰΫϥογϡ • ಉ͡αϒΫϥεͰɺϓϩύςΟ͕ͳΒਅʁ • ྫɿUIColor.whiteͱUIColor(white: 1, alpha: 1)ਅ
• ྫɿUIColor(red: 1, green: 1, blue: 1, alpha: 1)ͱUIColor(white: 1, alpha: 1)ِ • UICIColorͱUICGColorͱͷఆِʹͳΔ • UIDynamicProviderColorಉҰੑఆ͕ਅͰͳ͚ΕఆਅʹͳΒͳ͍ • UIDynamicAppDefinedColorʹ͢Εఆ͕ਅʹͳΕΔ 58 -
ͪΐͬͱʹཱ͔ͭ͠Εͳ͍tips • XCTAssertEqualͰUIColorΛςετ͢Δͱ͖ɺಉ͡αϒΫϥεͰఆ͠Α͏ • ҧ͏αϒΫϥεಉ࢜ͰequalʹͳΒͳ͍ͷͰςετ͕௨Βͳ͍ ❌ UIDeviceRGBColorͷനͱUICachedDeviceWhiteColorͷന XCTAssertEqual(UIColor(red: 1, green:
1, blue: 1, alpha: 1), UIColor.white) ✅ UI(Cached)DeviceWhiteColorಉ࢜ XCTAssertEqual(UIColor(white: 1, alpha: 1), UIColor.white) 59 -
ࢀߟจݙͱ͔໘നͦ͏ͳϖʔδͱ͔ • Randomizing UIColor with Method Swizzling | Jonathan Cole
• ʲIOS ARCʳ UIColor͕ϝϞϦʹ͍ͬͯΔΑ͏ͳؾ͕͢Δ – ඥ͚ͳʑ • Patterns • Core Graphics Tutorial: Patterns | raywenderlich.com • iOS ൌགྷapp∍നࣜ - ࡥ • nygard/class-dump: Generate Objective-C headers from Mach-O files. • nst/RuntimeBrowser: Objective-C Runtime Browser, for Mac OS X and iOS 63