Address
:
[go:
up one dir
,
main page
]
Include Form
Remove Scripts
Accept Cookies
Show Images
Show Referer
Rotate13
Base64
Strip Meta
Strip Title
Session Cookies
More Web Proxy on the site http://driver.im/
Submit Search
iOS UI Component API Design
•
9 likes
•
17,754 views
Brian Gesiak
Follow
1 of 60
Download now
Downloaded 10 times
More Related Content
iOS UI Component API Design
1.
UIコンポーネントAPIデザイン 「パラメータ・オブジェクト」パターン Brian Gesiak 2014年4月9日 Research Student,
The University of Tokyo @modocache #potatotips
2.
内容 • 課題:カスタマイズ用のAPIをどう提供するか • 細かいところまでカスタマイズしたい •
継承より組み立てを好む • 解決策:設定オブジェクト • 設定オブジェクト ! • 課題:コールバックのAPI • ブロックやdelegateメソッドのパラメータが確定し てしまうとなかなか変えられない • 解決策:パラメータ・オブジェクト
3.
カスタマイズ用のAPIの一例 JVFloatLabeledTextField
4.
カスタマイズ用のAPIの一例 JVFloatLabeledTextField
5.
カスタマイズ用のAPIの一例 JVFloatLabeledTextField
6.
カスタマイズ用のAPIの一例 JVFloatLabeledTextField @interface JVFloatLabeledTextField :
UITextField ! @property (nonatomic, strong) NSNumber *floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelActiveTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, assign) NSInteger animateEvenIfNotFirstResponder UI_APPEARANCE_SELECTOR; ! @end
7.
カスタマイズ用のAPIの一例 JVFloatLabeledTextField @interface JVFloatLabeledTextField :
UITextField ! @property (nonatomic, strong) NSNumber *floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelActiveTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, assign) NSInteger animateEvenIfNotFirstResponder UI_APPEARANCE_SELECTOR; ! @end
8.
カスタマイズ用のAPIの一例 JVFloatLabeledTextField @interface JVFloatLabeledTextField :
UITextField ! @property (nonatomic, strong) NSNumber *floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelActiveTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, assign) NSInteger animateEvenIfNotFirstResponder UI_APPEARANCE_SELECTOR; ! @end
9.
カスタマイズ用のAPIの一例 JVFloatLabeledTextField @interface JVFloatLabeledTextField :
UITextField ! @property (nonatomic, strong) NSNumber *floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelActiveTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, assign) NSInteger animateEvenIfNotFirstResponder UI_APPEARANCE_SELECTOR; ! @end
10.
継承するのか? 継承より組み立てを好む
11.
継承するのか? • JVFloatLabeledTextFieldはUITextFieldのサブクラス 継承より組み立てを好む
12.
継承するのか? • JVFloatLabeledTextFieldはUITextFieldのサブクラス • 機能がほしければこのクラスを使うしかない 継承より組み立てを好む
13.
継承するのか? • JVFloatLabeledTextFieldはUITextFieldのサブクラス • 機能がほしければこのクラスを使うしかない •
機能を追加したければサブクラスを新たに定義す るしかない 継承より組み立てを好む
14.
継承するのか? • JVFloatLabeledTextFieldはUITextFieldのサブクラス • 機能がほしければこのクラスを使うしかない •
機能を追加したければサブクラスを新たに定義す るしかない • JVFloatLabeledTextFieldは継承ヒエラルキーに自分 をねじ込んでいる 継承より組み立てを好む
15.
継承するのか? • JVFloatLabeledTextFieldはUITextFieldのサブクラス • 機能がほしければこのクラスを使うしかない •
機能を追加したければサブクラスを新たに定義す るしかない • JVFloatLabeledTextFieldは継承ヒエラルキーに自分 をねじ込んでいる 継承より組み立てを好む • カテゴリーだったら、どのUITextFieldでも使える
16.
@interface JVFloatLabeledTextField :
UITextField ! @property (nonatomic, strong) NSNumber *floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelActiveTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, assign) NSInteger animateEvenIfNotFirstResponder UI_APPEARANCE_SELECTOR; ! @end 継承するのか? 継承より組み立てを好む
17.
@interface JVFloatLabeledTextField :
UITextField ! @property (nonatomic, strong) NSNumber *floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelActiveTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, assign) NSInteger animateEvenIfNotFirstResponder UI_APPEARANCE_SELECTOR; ! @end 継承するのか? 継承より組み立てを好む
18.
@interface JVFloatLabeledTextField :
UITextField ! @property (nonatomic, strong) NSNumber *floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelActiveTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, assign) NSInteger animateEvenIfNotFirstResponder UI_APPEARANCE_SELECTOR; ! @end 継承するのか? 継承より組み立てを好む
19.
@interface JVFloatLabeledTextField :
UITextField ! @property (nonatomic, strong) NSNumber *floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelActiveTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, assign) NSInteger animateEvenIfNotFirstResponder UI_APPEARANCE_SELECTOR; ! @end 継承するのか? 継承より組み立てを好む @interface UITextField (JVFloatLabeledTextField)
20.
@interface JVFloatLabeledTextField :
UITextField ! @property (nonatomic, strong) NSNumber *floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelActiveTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, assign) NSInteger animateEvenIfNotFirstResponder UI_APPEARANCE_SELECTOR; ! @end 継承するのか? 継承より組み立てを好む @interface UITextField (JVFloatLabeledTextField)
21.
@interface JVFloatLabeledTextField :
UITextField ! @property (nonatomic, strong) NSNumber *floatingLabelYPadding UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIFont *floatingLabelFont UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, strong) UIColor *floatingLabelActiveTextColor UI_APPEARANCE_SELECTOR; @property (nonatomic, assign) NSInteger animateEvenIfNotFirstResponder UI_APPEARANCE_SELECTOR; ! @end 継承するのか? 継承より組み立てを好む objc_setAssociatedObject @interface UITextField (JVFloatLabeledTextField)
22.
継承するのか? 継承より組み立てを好む
23.
継承するのか? 継承より組み立てを好む static void *JVFloatingLabelYPaddingKey
= &JVFloatingLabelYPaddingKey; ! - (void)setFloatingLabelYPadding:(NSNumber *)floatingLabelYPadding { objc_setAssociatedObject(self, JVFloatingLabelYPaddingKey, floatingLabelYPadding, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } ! - (NSNumber *)floatingLabelYPadding { return objc_getAssociatedObject(self, JVFloatingLabelYPaddingKey); } ! /// Add custom setters and getters for all properties
24.
継承するのか? 継承より組み立てを好む static void *JVFloatingLabelYPaddingKey
= &JVFloatingLabelYPaddingKey; ! - (void)setFloatingLabelYPadding:(NSNumber *)floatingLabelYPadding { objc_setAssociatedObject(self, JVFloatingLabelYPaddingKey, floatingLabelYPadding, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } ! - (NSNumber *)floatingLabelYPadding { return objc_getAssociatedObject(self, JVFloatingLabelYPaddingKey); } ! /// Add custom setters and getters for all properties
25.
継承するのか? 継承より組み立てを好む static void *JVFloatingLabelYPaddingKey
= &JVFloatingLabelYPaddingKey; ! - (void)setFloatingLabelYPadding:(NSNumber *)floatingLabelYPadding { objc_setAssociatedObject(self, JVFloatingLabelYPaddingKey, floatingLabelYPadding, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } ! - (NSNumber *)floatingLabelYPadding { return objc_getAssociatedObject(self, JVFloatingLabelYPaddingKey); } ! /// Add custom setters and getters for all properties
26.
継承するのか? 継承より組み立てを好む static void *JVFloatingLabelYPaddingKey
= &JVFloatingLabelYPaddingKey; ! - (void)setFloatingLabelYPadding:(NSNumber *)floatingLabelYPadding { objc_setAssociatedObject(self, JVFloatingLabelYPaddingKey, floatingLabelYPadding, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } ! - (NSNumber *)floatingLabelYPadding { return objc_getAssociatedObject(self, JVFloatingLabelYPaddingKey); } ! /// Add custom setters and getters for all properties
27.
継承するのか? 継承より組み立てを好む static void *JVFloatingLabelYPaddingKey
= &JVFloatingLabelYPaddingKey; ! - (void)setFloatingLabelYPadding:(NSNumber *)floatingLabelYPadding { objc_setAssociatedObject(self, JVFloatingLabelYPaddingKey, floatingLabelYPadding, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } ! - (NSNumber *)floatingLabelYPadding { return objc_getAssociatedObject(self, JVFloatingLabelYPaddingKey); } ! /// Add custom setters and getters for all properties
28.
継承するのか? 継承より組み立てを好む static void *JVFloatingLabelYPaddingKey
= &JVFloatingLabelYPaddingKey; ! - (void)setFloatingLabelYPadding:(NSNumber *)floatingLabelYPadding { objc_setAssociatedObject(self, JVFloatingLabelYPaddingKey, floatingLabelYPadding, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } ! - (NSNumber *)floatingLabelYPadding { return objc_getAssociatedObject(self, JVFloatingLabelYPaddingKey); } ! /// Add custom setters and getters for all properties
29.
継承するのか? 継承より組み立てを好む static void *JVFloatingLabelYPaddingKey
= &JVFloatingLabelYPaddingKey; ! - (void)setFloatingLabelYPadding:(NSNumber *)floatingLabelYPadding { objc_setAssociatedObject(self, JVFloatingLabelYPaddingKey, floatingLabelYPadding, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } ! - (NSNumber *)floatingLabelYPadding { return objc_getAssociatedObject(self, JVFloatingLabelYPaddingKey); } ! /// Add custom setters and getters for all properties スケールしない
30.
設定オブジェクト カスタマイズ用のパラメータを束ねる
31.
設定オブジェクト カスタマイズ用のパラメータを束ねる
32.
設定オブジェクト カスタマイズ用のパラメータを束ねる
33.
設定オブジェクト カスタマイズ用のパラメータを束ねる
34.
設定オブジェクト カスタマイズ用のパラメータを束ねる
35.
設定オブジェクトの一例 MDCSwipeToChoose
36.
設定オブジェクトの一例 MDCSwipeToChoose
37.
設定オブジェクトの一例 MDCSwipeToChoose MDCSwipeOptions *options =
[MDCSwipeOptions new]; options.delegate = self; options. *state){ switch (state.direction) { case MDCSwipeDirectionLeft: self.webView.alpha = 0.5f - state.thresholdRatio; break; case MDCSwipeDirectionRight: self.webView.alpha = 0.5f + state.thresholdRatio; break; case MDCSwipeDirectionNone: self.webView.alpha = 0.5f; break; } }; ! [self.webView mdc_swipeToChooseSetup:options];
38.
設定オブジェクトの一例 MDCSwipeToChoose MDCSwipeOptions *options =
[MDCSwipeOptions new]; options.delegate = self; options. *state){ switch (state.direction) { case MDCSwipeDirectionLeft: self.webView.alpha = 0.5f - state.thresholdRatio; break; case MDCSwipeDirectionRight: self.webView.alpha = 0.5f + state.thresholdRatio; break; case MDCSwipeDirectionNone: self.webView.alpha = 0.5f; break; } }; ! [self.webView mdc_swipeToChooseSetup:options];
39.
設定オブジェクトの一例 MDCSwipeToChoose MDCSwipeOptions *options =
[MDCSwipeOptions new]; options.delegate = self; options. *state){ switch (state.direction) { case MDCSwipeDirectionLeft: self.webView.alpha = 0.5f - state.thresholdRatio; break; case MDCSwipeDirectionRight: self.webView.alpha = 0.5f + state.thresholdRatio; break; case MDCSwipeDirectionNone: self.webView.alpha = 0.5f; break; } }; ! [self.webView mdc_swipeToChooseSetup:options];
40.
設定オブジェクトの一例 MDCSwipeToChoose MDCSwipeOptions *options =
[MDCSwipeOptions new]; options.delegate = self; options. *state){ switch (state.direction) { case MDCSwipeDirectionLeft: self.webView.alpha = 0.5f - state.thresholdRatio; break; case MDCSwipeDirectionRight: self.webView.alpha = 0.5f + state.thresholdRatio; break; case MDCSwipeDirectionNone: self.webView.alpha = 0.5f; break; } }; ! [self.webView mdc_swipeToChooseSetup:options];
41.
設定オブジェクトの一例 MDCSwipeToChoose MDCSwipeOptions *options =
[MDCSwipeOptions new]; options.delegate = self; options. *state){ switch (state.direction) { case MDCSwipeDirectionLeft: self.webView.alpha = 0.5f - state.thresholdRatio; break; case MDCSwipeDirectionRight: self.webView.alpha = 0.5f + state.thresholdRatio; break; case MDCSwipeDirectionNone: self.webView.alpha = 0.5f; break; } }; ! [self.webView mdc_swipeToChooseSetup:options];
42.
設定オブジェクトの一例 MDCSwipeToChoose MDCSwipeOptions *options =
[MDCSwipeOptions new]; options.delegate = self; options. *state){ switch (state.direction) { case MDCSwipeDirectionLeft: self.webView.alpha = 0.5f - state.thresholdRatio; break; case MDCSwipeDirectionRight: self.webView.alpha = 0.5f + state.thresholdRatio; break; case MDCSwipeDirectionNone: self.webView.alpha = 0.5f; break; } }; ! [self.webView mdc_swipeToChooseSetup:options];
43.
設定オブジェクトの一例 MDCSwipeToChoose MDCSwipeOptions *options =
[MDCSwipeOptions new]; options.delegate = self; options. *state){ switch (state.direction) { case MDCSwipeDirectionLeft: self.webView.alpha = 0.5f - state.thresholdRatio; break; case MDCSwipeDirectionRight: self.webView.alpha = 0.5f + state.thresholdRatio; break; case MDCSwipeDirectionNone: self.webView.alpha = 0.5f; break; } }; ! [self.webView mdc_swipeToChooseSetup:options];
44.
設定オブジェクトの一例 MDCSwipeToChoose MDCSwipeOptions *options =
[MDCSwipeOptions new]; options.delegate = self; options. *state){ switch (state.direction) { case MDCSwipeDirectionLeft: self.webView.alpha = 0.5f - state.thresholdRatio; break; case MDCSwipeDirectionRight: self.webView.alpha = 0.5f + state.thresholdRatio; break; case MDCSwipeDirectionNone: self.webView.alpha = 0.5f; break; } }; ! [self.webView mdc_swipeToChooseSetup:options];
45.
設定オブジェクトの一例 MDCSwipeToChoose MDCSwipeOptions *options =
[MDCSwipeOptions new]; options.delegate = self; options. *state){ switch (state.direction) { case MDCSwipeDirectionLeft: self.webView.alpha = 0.5f - state.thresholdRatio; break; case MDCSwipeDirectionRight: self.webView.alpha = 0.5f + state.thresholdRatio; break; case MDCSwipeDirectionNone: self.webView.alpha = 0.5f; break; } }; ! [self.webView mdc_swipeToChooseSetup:options];
46.
設定オブジェクトの一例 MDCSwipeToChoose MDCSwipeOptions *options =
[MDCSwipeOptions new]; options.delegate = self; options. *state){ switch (state.direction) { case MDCSwipeDirectionLeft: self.webView.alpha = 0.5f - state.thresholdRatio; break; case MDCSwipeDirectionRight: self.webView.alpha = 0.5f + state.thresholdRatio; break; case MDCSwipeDirectionNone: self.webView.alpha = 0.5f; break; } }; ! [self.webView mdc_swipeToChooseSetup:options];
47.
パラメータ・オブジェクト ブロックのシグネチャの変化を回避する
48.
options.
*view, MDCSwipeDirection direction, CGFloat thresholdRatio){ if (direction == MDCSwipeDirectionLeft) { NSLog(@"Panning to the left..."); } }; パラメータ・オブジェクト ブロックのシグネチャの変化を回避する
49.
options.
*view, MDCSwipeDirection direction, CGFloat thresholdRatio){ if (direction == MDCSwipeDirectionLeft) { NSLog(@"Panning to the left..."); } }; パラメータ・オブジェクト ブロックのシグネチャの変化を回避する
50.
options.
*view, MDCSwipeDirection direction, CGFloat thresholdRatio){ if (direction == MDCSwipeDirectionLeft) { NSLog(@"Panning to the left..."); } }; パラメータ・オブジェクト ブロックのシグネチャの変化を回避する
51.
options.
*view, MDCSwipeDirection direction, CGFloat thresholdRatio){ if (direction == MDCSwipeDirectionLeft) { NSLog(@"Panning to the left..."); } }; パラメータ・オブジェクト ブロックのシグネチャの変化を回避する
52.
options.
*view, MDCSwipeDirection direction, CGFloat thresholdRatio){ if (direction == MDCSwipeDirectionLeft) { NSLog(@"Panning to the left..."); } }; パラメータ・オブジェクト ブロックのシグネチャの変化を回避する options. *state){ MDCSwipeDirection direction = state.direction;
53.
options.
*view, MDCSwipeDirection direction, CGFloat thresholdRatio){ if (direction == MDCSwipeDirectionLeft) { NSLog(@"Panning to the left..."); } }; パラメータ・オブジェクト ブロックのシグネチャの変化を回避する options. *state){ MDCSwipeDirection direction = state.direction;
54.
パラメータ・オブジェクト APIの微調整、バージョニングが可能 @interface MDCPanState :
NSObject ! @property (nonatomic, strong) UIView *view; @property (nonatomic, assign) MDCSwipeDirection direction; @property (nonatomic, assign) CGFloat thresholdRatio; ! @end
55.
パラメータ・オブジェクト APIの微調整、バージョニングが可能 @interface MDCPanState :
NSObject ! @property (nonatomic, strong) UIView *view; @property (nonatomic, assign) MDCSwipeDirection direction; @property (nonatomic, assign) CGFloat thresholdRatio; ! @end DEPRECATED_ATTRIBUTE;
56.
options.
*view, MDCSwipeDirection direction, CGFloat thresholdRatio){ if (direction == MDCSwipeDirectionLeft) { NSLog(@"Panning to the left..."); } }; options. *state){ MDCSwipeDirection direction = state.direction; パラメータ・オブジェクト サポートしないパラメータを少しずつ排除
57.
options.
*view, MDCSwipeDirection direction, CGFloat thresholdRatio){ if (direction == MDCSwipeDirectionLeft) { NSLog(@"Panning to the left..."); } }; options. *state){ MDCSwipeDirection direction = state.direction; パラメータ・オブジェクト サポートしないパラメータを少しずつ排除
58.
options.
*view, MDCSwipeDirection direction, CGFloat thresholdRatio){ if (direction == MDCSwipeDirectionLeft) { NSLog(@"Panning to the left..."); } }; options. *state){ MDCSwipeDirection direction = state.direction; パラメータ・オブジェクト サポートしないパラメータを少しずつ排除
59.
要約 • 継承に頼らないUIコンポーネントを好む • 設定オブジェクトで、クリーンなカスタマイズ用の APIを提供できる •
パラメータ・オブジェクトというデザイン・パター ンは、シグネチャの変化を未然に防ぐ • 特にブロックのパラメータに有用
60.
ご参考までに • 本日のスライド • http://modocache.io/ios-ui-component-api-design •
ぜひフォローして下さい • Twitter: @modocache • GitHub: https://github.com/modocache • JVFloatLabeledTextField • https://github.com/jverdi/JVFloatLabeledTextField • MDCSwipeToChoose(おいらに☆を!) • https://github.com/modocache/MDCSwipeToChoose • 「パラメータ・オブジェクト」デザイン・パターン(英語) • http://c2.com/cgi/wiki?ParameterObject
Download