ãæµ·å¤äºæ¥åãã®iOSã¢ããªã±ã¼ã·ã§ã³éçºãæ å½ãã¦ãã西山(@yuseinishiyama)ã§ããã¯ãã¯ãããã¯ç¾å¨ãæµ·å¤è¤æ°ã«å½ã«åãã¦ãµã¼ãã¹ãå±éãã¦ãã¾ãã
ãXcodeã«ã¯Interface Builderã¨å¼ã°ããããªãããªGUIãæã£ããã¶ã¤ã³ãã¼ã«ãä»å±ãã¦ããããããç¨ãã¦ç»é¢ã®ã¬ã¤ã¢ã¦ããæ§æãããã¨ã主æµã¨ãªã£ã¦ãã¾ããå¼ç¤¾ããã°ã§ããiOSéçºã§storyboardã¨xibããã¾ã使ãåãããã©ã¯ãã£ã¹çã®è¨äºã§ãGUIãã¼ã¹ã®ã¬ã¤ã¢ã¦ãã«ã¤ãã¦è§¦ãã¦ãã¾ããããããç¾å¨ç§ãæ å½ãã¦ããããã¸ã§ã¯ãã§ã¯ãInterface Builderãç¨ããã«ãã¬ã¤ã¢ã¦ãã®å¤§åãã³ã¼ãã§è¨è¿°ãã¦ãã¾ãã
ãä»åã¯ãã³ã¼ããã¼ã¹ã®ã¬ã¤ã¢ã¦ããå®è£ ãã¦ããä¸ã§å¾ãç¥è¦ãã以ä¸ã®3ã¤ã®é¨åã«åãã¦å ±æãããã¨æãã¾ãã
- Interface Builderãç¨ããã¬ã¤ã¢ã¦ãã¨ã³ã¼ããã¼ã¹ã®ã¬ã¤ã¢ã¦ãã®æ¯è¼
- ã³ã¼ããã¼ã¹ã®ã¬ã¤ã¢ã¦ãã®ãã¡ãªããã¸ã®å¯¾å¦
- ã³ã¼ããã¼ã¹ã®ã¬ã¤ã¢ã¦ãã®å®è£
ãã¡ãªã¿ã«ãå½è©²ããã¸ã§ã¯ãããµãã¼ããã¦ããiOSãã¼ã¸ã§ã³ã¯iOS7以ä¸ã§ãããã®ãããiOS8以éã§ãããµãã¼ããããªãæ©è½ã«ã¤ãã¦ã¯è§¦ãã¾ãããã¾ããæ¢åã®Objective-Cã¢ããªã±ã¼ã·ã§ã³ãSwiftã§æ¸ãæãã話ã§ã触ãã¾ããããæ®ã©ã®ã³ã¼ããSwiftã§è¨è¿°ãã¦ãããããä»åæ²è¼ãããµã³ãã«ã³ã¼ããå ¨ã¦Swiftã¨ãã¾ããã
Interface Builderãç¨ããã¬ã¤ã¢ã¦ãã¨ã³ã¼ããã¼ã¹ã®ã¬ã¤ã¢ã¦ãã®æ¯è¼
ãæ¬ç¯ã§ã¯Interface Builderãç¨ããã¬ã¤ã¢ã¦ãã¨ã³ã¼ããã¼ã¹ã®ã¬ã¤ã¢ã¦ãã¨ãæ¯è¼ããããããã®ã¡ãªããã«ã¤ãã¦èª¬æãã¾ãã
Interface Builderãå©ç¨ããã¬ã¤ã¢ã¦ãã®ã¡ãªãã
ãInterface Builderãå©ç¨ãã¦ã¬ã¤ã¢ã¦ããçµããã¨ã«ã¯ä»¥ä¸ã®ã¡ãªãããããã¾ãã
- ç»é¢é·ç§»ãã°ã©ãã£ã«ã«ã«ç¢ºèªã§ãã
- ã¬ã¤ã¢ã¦ãã®çµæãã²ã¨ç®ã§åãã
- ããã°ã©ãã³ã°çµé¨ã®ç¡ã人ã§ãã£ã¦ã容æã«ãã©ã¡ã¼ã¿ã調æ´ã§ãã
æ¬é ã§ã¯ãããããã«ã¤ãã¦èª¬æãã¾ãã
ç»é¢é·ç§»ãã°ã©ãã£ã«ã«ã«ç¢ºèªã§ãã
ãStoryboardä¸ã«ã¯è¤æ°ã®ViewControllerãé ç½®ãããã¨ãå¯è½ã§ãããã®ãããè¤æ°ã®ç»é¢éã®é·ç§»ãã³ã¼ããèªã¾ãã¨ãææ¡ãããã¨ãã§ãã¾ãã
ã¬ã¤ã¢ã¦ãã®çµæãã²ã¨ç®ã§åãã
ãGUIãå©ç¨ãã¦ã¬ã¤ã¢ã¦ããè¡ããããå®è£ ããªããå®è¡æã®ã¬ã¤ã¢ã¦ãã確èªãããã¨ãã§ãã¾ãããã®ãããã¬ã¤ã¢ã¦ãã夿´ãã度ã«ãã¢ããªã±ã¼ã·ã§ã³ãBuild&Runãã¦çµæã確èªããå¿ è¦ãããã¾ããã
ããã°ã©ãã³ã°çµé¨ã®ç¡ã人ã§ãã£ã¦ã容æã«ãã©ã¡ã¼ã¿ã調æ´ã§ãã
ããã¼ã¸ã³ã夿´ããããèæ¯è²ã夿´ãããããéã«ãã½ã¼ã¹ã³ã¼ãã夿´ããå¿ è¦ãããã¾ãããGUIä¸ã®ãã©ã¡ã¼ã¿ã調æ´ããã ãã§ãããã®å¤ã夿´ã§ããã®ã§ãããã°ã©ãã³ã°çµé¨ã®ç¡ããã¶ã¤ãã¼ããã£ã¬ã¯ã¿ã¼ã®äººã§ããã¶ã¤ã³ã夿´ãããã¨ãå¯è½ã§ãã
ã³ã¼ããã¼ã¹ã®ã¬ã¤ã¢ã¦ãã®ã¡ãªãã
ã䏿¹ã§ãã³ã¼ããã¼ã¹ã®ã¬ã¤ã¢ã¦ãã«ã¯ä»¥ä¸ã®ã¡ãªãããããã¾ãã
- ViewControllerãé©åã«åæåã§ãã
- ã³ã¼ãã®å¤æ´ãã¬ãã¥ã¼ãããã
- 宿°ãç¨ãã¦ãä¸è²«ãããã¶ã¤ã³ããªã·ã¼ãé©ç¨ã§ãã
- è¦ç´ ã®å¤æ´ã«æè»ã«å¯¾å¿ã§ãã
- è¦ç´ ã®è¨å®ã«é¢ããã³ã¼ãã忣ããªã
æ¬é ã§ã¯ãããããã«ã¤ãã¦èª¬æãã¾ãã
ViewControllerãé©åã«åæåã§ãã
ãStoryboardããViewControllerãåæåãã¦ããã®ViewControllerã¸ã¨ç»é¢é·ç§»ããã±ã¼ã¹ãèãã¦ã¿ã¾ãããã
// StoryboardããåæåãããViewController class DetailViewControllerFromStoryboard: UIViewController { var recipe: Recipe! // (çç¥) } class MasterViewController: UIViewController { // (çç¥) // Storyboardã®ã¤ã³ã¹ã¿ã³ã¹å let storyboard = UIStoryboard(name: "Main", bundle: nil) // StoryboardããViewControllerãã¤ã³ã¹ã¿ã³ã¹å let vc = storyboard.instantiateViewControllerWithIdentifier("Detail") as! DetailViewControllerFromStoryboard // é·ç§»å ã®ããããã£ãè¨å® vc.recipe = Recipe() // ç»é¢é·ç§» navigationController?.pushViewController(vc, animated: true) // (çç¥) }
ããã®ã³ã¼ãã«ã¯2ã¤ã®åé¡ç¹ãããã¾ãã1ã¤ã¯é·ç§»å
ã®ViewControllerã®ããããã£recipe
ãImplicitlyUnwrappedOptional<Wrapped>
ã¨ãã¦å®£è¨ããã¦ããç¹ã«ããã¾ãã
ãä¸è¨ã®ã³ã¼ãã«ããã¦ãrecipe
ã¯å¿
é ã®(常ã«å¤ãåå¨ãããã¨ãæå¾
ããã¦ãã)ããããã£ã§ããããããStoryboardããViewControllerãã¤ã³ã¹ã¿ã³ã¹åããå ´åãã¤ã³ã¹ã¿ã³ã¹åã®æç¹ã§ã¯ãViewControllerã®æã¤ããããã£ãåæåãããã¨ãã§ãã¾ããããã®ãããå¿
é ã®ããããã£ã§ãã£ã¦ããã¤ã³ã¹ã¿ã³ã¹åããå¾ã«ä»£å
¥ããå¿
è¦ãããã¾ãã
let vc: DetailViewControllerFromStoryboard = ... vc.recipe = Recipe()
ãã¤ã¾ããããã§ã¯ä»¥ä¸ã®2ã¤ãæºããå¿ è¦ãããã¾ãã
recipe
ã䏿çã«nil
ã«ãªããã¨ã許容ããrecipe
ãå¿ é ã®ããããã£ã§ãããã¨ã表ç¾ãã
ãããã¦ããã®ä¸¡æ¹ãæºããã«ã¯ãããããã£ãImplicitlyUnwrappedOptional<Wrapped>
ã¨ãã¦å®£è¨ããå¿
è¦ãããã¾ããããã¯ãIBOutlet
ã¨ãã¦ãStoryboardä¸ã®è¦ç´ ãã³ã¼ãã¨æ¥ç¶ããéã«èªåçæãããã³ã¼ãã«é¢ãã¦ãåæ§ã§ãã
@IBOutlet weak var label: UILabel!
ãããããImplicitlyUnwrappedOptional<Wrapped>
ã使ã以ä¸ãæ½å¨çã«ã¯ã¯ã©ãã·ã¥ããå¯è½æ§ãããã¾ããä¾ãã°ãrecipe
ããããã£ã«å¤ã代å
¥ããã«ç»é¢é·ç§»ãã¦ãã¾ãããã®å¾ããã®ããããã£ã«ã¢ã¯ã»ã¹ããã°ã¯ã©ãã·ã¥ãã¦ãã¾ãã¾ãã
let vc: DetailViewControllerFromStoryboard = ... // recipeããããã£ãè¨å®ãå¿ãã¦ãã navigationController?.pushViewController(vc, animated: true)
ããã1ã¤ã®åé¡ç¹ã¯ãas!
ãç¨ããå¼·å¶çãªãã£ã¹ããçºçãã¦ããç¹ã§ããããã¯ãinstantiateViewControllerWithIdentifier(_:)
ã®æ»ãå¤ã®åãUIViewController
ãªã®ã§ãå
·ä½çãªåã¸ã¨ãã£ã¹ãããå¿
è¦ãããããã§ãããã¡ããããã®ã³ã¼ããæ½å¨çã«ã¯ã¯ã©ãã·ã¥ã®å¯è½æ§ãããã¾ããViewControllerã®IDã®æå®ãééã£ãå ´åãªã©ãå
¸åçãªã¯ã©ãã·ã¥ã®ä¾ã¨ãªãã§ãããã
// typo: Detail -> Deteil let vc = storyboard.instantiateViewControllerWithIdentifier("Deteil") as! DetailViewControllerFromStoryboard
ãSwiftã¯éçåä»ããnull許容æ§ã®ã³ã³ããã¼ã«ã«ãã£ã¦ãå®è¡æã®ã¨ã©ã¼ãæ¸ãããã³ã¼ãã®èª¤ããã§ããã ãã³ã³ãã¤ã«æã«æ¤åºããããã¨ãæå³ãã¦ããè¨èªã§ãã䏿¹ã§ãStoryboardãç¨ããViewControllerã®ã¤ã³ã¹ã¿ã³ã¹åã¯ãããã°ã©ãããæ°ãã¤ããªãã¨ã¯ã©ãã·ã¥ããå¯è½æ§ãããã¨ããç¹ã§ãSwiftã®å®å ¨æ§ãæãã¦ããã¨è¨ãã¾ãããã®ãã¨ã¯ãInterface Builderãå ã ã¯Objective-Cã¨ããè¨èªã®åçãªç¹æ§ãæå¤§éã«æ´»ããããã¼ã«ã§ããã¨ãããã¨ãèããã¨ãå½ããåããããã¾ããã
ã䏿¹ã§ãInterface Builderãç¨ããã«ãã³ã¼ãã ãã§ViewControllerãåæåããå ´åã®ã³ã¼ãã¯æ¬¡ã®ããã«ãªãã¾ãã
class DetailViewControllerWithoutStoryboard: UIViewController { let recipe: Recipe init(recipe: Recipe) { self.recipe = recipe super.init(nibName: nil, bundle: nil) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } class MasterViewController: UIViewController { // (çç¥) let recipe = Recipe() let vc = DetailViewControllerWithoutStoryboard(recipe: recipe) navigationController?.pushViewController(vc, animated: true) // (çç¥) }
ãé常ã®ã¤ãã·ã£ã©ã¤ã¶ãå©ç¨ã§ããã®ã§ãããããã£recipe
ãå¿
é ã®ããããã£ã§ãã¤å代å
¥ä¸å¯è½ã§ããã¨ãããã¨ãå¼·å¶ãããã¨ãã§ãã¦ãã¾ãã
let recipe: Recipe init(recipe: Recipe) { self.recipe = recipe super.init(nibName: nil, bundle: nil) }
ãã¡ãªã¿ã«ãinit(nibName:bundle:)
ã¯UIViewController
ã®æå®ã¤ãã·ã£ã©ã¤ã¶ã§ãã
ã³ã¼ãã®å¤æ´ãã¬ãã¥ã¼ãããã
ãStoryboardã¯åãªãXMLã§ããããã®æ§é ãé常ã«è¤éã§ãããããã¬ã¤ã¢ã¦ãã®å¤æ´ããã£ãéã«ãå·®åãè¦ãã ãã§ãã®æå³ãæ±²ããã¨ã¯å®¹æã§ã¯ããã¾ãããã¾ããæå³çã«ç·¨éãã¦ããªãç®æãåæã«æ´æ°ããããã¨ããããã¨ããç¹ãåé¡ã§ããæ¬¡ã®ã¹ã¯ãªã¼ã³ã·ã§ããã¯ãããå¶ç´ã®å¤ãStoryboardä¸ã§12ãã10ã«å¤æ´ããå ´åã®å·®åã§ãã
ã䏿¹ã§ãã³ã¼ãã§ããã°å¤æ´ç®æã®ãã§ãã¯ã¯å®¹æã§ããæ¬¡ã®ã¹ã¯ãªã¼ã³ã·ã§ããã¯ãããå¶ç´ã®å¤ãã³ã¼ãä¸ã§12ãã10ã«å¤æ´ããå ´åã®å·®åã§ãããuserNameLabel
ã¨ããã©ãã«ã®æ«å°¾ã®ã¹ãã¼ã¹ã12ãã10ã«å¤æ´ããããã¨ãããã¨ãæããã«è¦ã¦ã¨ãã¾ãã
ãã¡ãªã¿ã«ãã³ã¼ãä¸ã§ã®å¶ç´ã®è¨å®ãç°¡æ½ã«è¡ãããã«ãPureLayoutã¨ããã©ã¤ãã©ãªã使ç¨ãã¦ãã¾ãããã®ã©ã¤ãã©ãªã«é¢ãã¦ã¯å¾è¿°ãã¾ãã
宿°ãç¨ãã¦ä¸è²«ãããã¶ã¤ã³ããªã·ã¼ãé©ç¨ã§ãã
ãInterface Builderãç¨ãã¦ã¬ã¤ã¢ã¦ããæ§æããå ´åãã¬ã¤ã¢ã¦ãéã§å ±éã®å¤ãè¨å®ãããã¨ãã§ãã¾ãããããããã³ã¼ããã¼ã¹ã®ã¬ã¤ã¢ã¦ãã§ããã°ã宿°ãå®ç¾©ãã¦ããããããè¤æ°ã®ã¬ã¤ã¢ã¦ãéã§å ±æãããã¨ãå¯è½ã§ãã
struct Constant { struct Inset { static let S: CGFloat = 8 static let M: CGFloat = 12 static let L: CGFloat = 18 } struct CornerRadius { static let S: CGFloat = 3 static let L: CGFloat = 5 } // (çç¥) }
ããã®ããã«å®æ°ãå®ç¾©ãã¦ããã°ãããªã·ã¼ã夿´ãããå ´åããã®å®æ°ã®å¤ã夿´ããã ãã§å¤æ´ãå ¨ä½ã«é©ç¨ã§ãã¾ããä¾ãã°ããã¢ããªå ¨ä½ã§ä½ç½æããã£ã¨æ¬²ãããã¨ãªãã°ããã®å®æ°ã®å¤ã大ããããã°è¯ãã§ãããã
è¦ç´ ã®å¤æ´ã«æè»ã«å¯¾å¿ã§ãã
ãã¬ã¤ã¢ã¦ããå®è£
ãã¦ããéä¸ã§ãViewè¦ç´ ã®åã夿´ããããªãã±ã¼ã¹ãããããããã¾ãããä¾ãã°ãå½åã¯UIButton
ã§å®è£
ãã¦ãããã®ããããè¤éãªã¬ã¤ã¢ã¦ãã«ãªã£ãããUIView
ã¨ãµããã¥ã¼ã§ç½®ãæããå ´åãªã©ãããã«ãããã¾ããInterface Builderã§ã¬ã¤ã¢ã¦ããè¡ã£ã¦ããå ´åããã®ãããªã±ã¼ã¹ã§ã¯ãä¸åº¦å
ã®è¦ç´ ãåé¤ãã¦ãããæ°ããªè¦ç´ ã追å ããããä¸åº¦å¶ç´ãè¨å®ãç´ãã¨ãããã¨ãæ±ãããã¾ããããããã³ã¼ããã¼ã¹ã®ã¬ã¤ã¢ã¦ãã§ããã°ãåç´ã«åãå¤ããã ãã§å¯¾å¿ã§ãã¾ãã
è¦ç´ ã®è¨å®ã«é¢ããã³ã¼ãã忣ããªã
ãInterface Builderãç¨ããã°ãGUIä¸ã§Viewè¦ç´ ã®ããããã£ãä¾ãã°èæ¯è²ããã©ã³ããªã©ãè¨å®ã§ãããã¨ã¯æ¢ã«èª¬æãã¾ãããããããå®éã®ã¢ããªã±ã¼ã·ã§ã³ã§ã¯ããããã®å¤ãåçã«ãªããã¨ãé »ç¹ã«ããã¾ãããã®ãããªã±ã¼ã¹ã§ã¯ãã³ã¼ãä¸ã§Viewè¦ç´ ã®ããããã£ãè¨å®ããªããã°ãªãããçµæã¨ãã¦ããããããããã£ã¯Interface Builderã§è¨å®ãããããããããã£ã¯ã³ã¼ãã§è¨å®ããã¦ãããã¨ãããããªç¶æ³ãçºçãã¾ãããããªã£ã¦ããã¨ãæçµçãªè¦ãç®ãã©ãã§æ±ºå®ããã®ãåãããªãç¶æ³ãçã¾ãã¦ãã¾ãã¾ããç¹ã«ãInterface Builderã§è¨å®ããä¸å¿ è¦ãªå¤ãã³ã¼ãã§ä¸æ¸ãããã¦ãããããã¨ãæ··ä¹±ãæãã¾ãã
ãã³ã¼ããã¼ã¹ã§ã¬ã¤ã¢ã¦ããã¦ããã°ããã¥ã¼ã«å¯¾ãã¦é©ç¨ãããå ¨ã¦ã®è¨å®ãã³ã¼ãããææ¡ã§ãã¾ãããã¥ã¼ã®è¨å®ã«é¢ããã³ã¼ãã§ViewControllerãæ±æããããã¨ãå«ãå¾åãããã¾ãããSwiftã§ã¯ããããã£ã®åæåã«å¼ãå©ç¨ã§ããã®ã§ã以ä¸ã®ããã«Viewè¦ç´ ã®åæåã«é¢ããã³ã¼ããä¸ç®æã«ã¾ã¨ããã°ãViewControllerã®å¯èªæ§ãä¸ãããã¨ãããã¾ããã
ãæ¬¡ã®ããã«ã¯ãã¼ã¸ã£ãå©ç¨ãã¦ããããã£ãåæåããã°ããããã¡ãªviewDidLoad()
ã®è¥å¤§åãé²ããã¨ãã§ãã¾ãã
final class DetailViewController: UIViewController { // ã¯ãã¼ã¸ã£ãå©ç¨ãã¦ãããããã£ãåæå // ã©ãã«ã®è¨å®ãä¸ç®æã«ã¾ã¨ã¾ã£ã¦ãã private var descriptionLabel: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false label.font = ... label.textColor = ... label.numberOfLines = ... return label }() // (çç¥) }
ã³ã¼ããã¼ã¹ã®ã¬ã¤ã¢ã¦ãã®ãã¡ãªããã¸ã®å¯¾å¦
ãåç¯ã§ãInterface Builderãå©ç¨ããã¬ã¤ã¢ã¦ãã«ã¯æ¬¡ã®ãããªã¡ãªããããããã¨ã説æãã¾ããã
- ç»é¢é·ç§»ãã°ã©ãã£ã«ã«ã«ç¢ºèªã§ãã
- ã¬ã¤ã¢ã¦ãã®çµæãã²ã¨ç®ã§åãã
- ããã°ã©ãã³ã°çµé¨ã®ç¡ã人ã§ãã£ã¦ã容æã«ãã©ã¡ã¼ã¿ã調æ´ã§ãã
ãè£ãè¿ãã°ãã³ã¼ããã¼ã¹ã®ã¬ã¤ã¢ã¦ãã«ã¯æ¬¡ã®ãããªãã¡ãªããããããã¨ãåããã¾ãã
- ç»é¢é·ç§»ãã°ã©ãã£ã«ã«ã«ç¢ºèªã§ããªã
- ã¬ã¤ã¢ã¦ãã®çµæãã²ã¨ç®ã§åãããªã
- ããã°ã©ãã³ã°çµé¨ã®ç¡ã人ã容æã«ãã©ã¡ã¼ã¿ã調æ´ã§ããªã
ãæ¬èª¬ã§ã¯ããããã®ãã¡ãªããã«ã©ã®ããã«å¯¾å¦ãã¦ããããã¨ãããã¨ã«ã¤ãã¦èª¬æãã¾ãã
ç»é¢é·ç§»ãã°ã©ãã£ã«ã«ã«ç¢ºèªã§ããªããã¨ã¸ã®å¯¾å¦
ãããç¨åº¦ã®è¦æ¨¡ã®ããã¸ã§ã¯ãã«ãªãã¨ããã®ç»é¢é·ç§»ã¯å¤§å¤è¤éã«ãªãã¾ããåãç»é¢ã«ãè¤æ°ã®ç®æããé·ç§»ããããç»é¢é·ç§»æã«ããã²ã¼ã·ã§ã³ã³ã³ããã¼ã©ã®ã¹ã¿ãã¯ãæä½ããããã¨ãã£ãç¶æ³ã«ãªããã¨ãçããããã¾ããããããããè¤éãªç»é¢é·ç§»ã«ãªã£ã¦ããã¨ãStoryboardã使ã£ã¦ã°ã©ãã£ã«ã«ã«è¡¨ç¾ããã¨ãã¦ãããã¾ãè¦èªæ§ãé«ãããã¾ãããããã£ã¦è¤éã«ãªãã管çãé£ãããªãå¯è½æ§ããããã¾ãã
ãæ å½ãã¦ããããã¸ã§ã¯ããããã§ã«ç»é¢é·ç§»ãè¤éã«ãªãã¤ã¤ããã¾ããã¾ããããªãå¤§è¦æ¨¡ã«ãªãå¯è½æ§ãããããã¸ã§ã¯ããªã®ã§ãStoryboardãå©ç¨ããç»é¢é·ç§»ã®ç®¡çã«ã¯ãã¾ãæå¾ ãã¦ãã¾ããã
ã¬ã¤ã¢ã¦ãã®çµæãã²ã¨ç®ã§ããããªããã¨ã¸ã®å¯¾å¦
ãã¬ã¤ã¢ã¦ãã®çµæãå®è¡ããã¾ã§åãããªããã¨ã¯ãã³ã¼ããã¼ã¹ã®ã¬ã¤ã¢ã¦ãã®æå¤§ã®æ¬ ç¹ã¨è¨ããããå¾ã¾ãããã¨ããã§ãã¬ã¤ã¢ã¦ãã®çµæãå®è¡ããã¾ã§åãããªããã¨ããåé¡ã¯ä»¥ä¸2ã¤ã®åé¡ã¸ã¨åè§£ã§ãã¾ãã
- ç¹å®ã®ç»é¢ãã¢ããªã±ã¼ã·ã§ã³ã®å ¨ä½åãææ¡ã§ããªã
- ã¬ã¤ã¢ã¦ãã®ãããã°ãå°é£
ãå½è©²ããã¸ã§ã¯ãã§ã¯ãZeplinã¨ãããã¼ã«ãç¨ãã¦ã¬ã¤ã¢ã¦ãã管çãã¦ããã®ã§ãåè ã«é¢ãã¦ã¯åé¡ã«ãªãã¾ãããZeplinã確èªããã°ãã¬ã¤ã¢ã¦ãã®å ¨ä½åã確èªã§ããããã§ãã
ã以ä¸ã¯ãZeplinä¸ã§è¡¨ç¤ºããã¦ããã¬ã¤ã¢ã¦ãã®ä¾ã§ãããã¼ã¸ã³ãã©ãã«ã®ãã©ã³ãçã®ããããã£ã表示ããã¦ãããã¨ãåããã¾ããåºæ¬çã«ã¬ã¤ã¢ã¦ãã«é¢ãã使¥ã¯ããããæ£è§£ã®ç¶æ ã¨ãã¦ããããå®ç¾ãã使¥ã«ãªãã¾ã(誤解ãæããªãããã«è£è¶³ãã¦ããã¨ãããã¯ãã¶ã¤ã³ãããããã¦ã³ã§æ±ºå®ãããã¨ããæå³ã§ã¯ããã¾ãããå½ç¶ã¨ã³ã¸ãã¢ããã¶ã¤ã³ã®æ®µéããè°è«ã«åå ãã¾ãããæçµçã«æ±ºå®ãããã¬ã¤ã¢ã¦ãããZeplinä¸ã«å±éãããã¨ããæå³ã§ã)ã
ãå¾è ã«é¢ãã¦ã¯ã確ãã«ãã³ã¼ããè¦ãã ãã§æçµçãªçµæãæ³åããã®ã¯å®¹æã§ã¯ãªãã®ã§ããããã°ããéã¯ä½åº¦ãBuild&Runãç¹°ãè¿ããã¨ã«ãªããä½è¨ãªæéãæ¶è²»ãã¾ããããããXcode7+Swift2ã«ãªã£ã¦ããã³ã³ãã¤ã«æéã大ããæ¹åãããã®ã§ããããããã©ã¤ã¢ã³ãã¨ã©ã¼ã¯ç¾å®çãªæéå ã«è¡ããããã«ãªãã¾ããã
ãã¾ããAutoLayoutãã©ãããããµã¼ããã¼ãã£ã¼ã©ã¤ãã©ãªã使ç¨ããã°ãå¹¾åãç´æçã«ã³ã¼ããè¨è¿°ãããã¨ãå¯è½ãªã®ã§ãæ £ãã¦ããã°ãå®è¡ãã¦ç¢ºèªããªãã¨ãæ£ããã¬ã¤ã¢ã¦ãã®ã³ã¼ããæ¸ããã¨ãã§ããããã«ãªãã¾ãã
ããã°ã©ãã³ã°çµé¨ã®ç¡ã人ã容æã«ãã©ã¡ã¼ã¿ã調æ´ã§ããªããã¨ã¸ã®å¯¾å¦
ãããã°ã©ãã³ã°çµé¨ã®ç¡ã人ã«ãããã¶ã¤ã³èª¿æ´ãå¯è½ã§ãããã¨ãããã¨ã¯ããã¶ã¤ãã¼ãç´æ¥ã¬ã¤ã¢ã¦ããä¿®æ£ãããããªããã¸ã§ã¯ãã§ã¯å½ç¶éè¦ã§ããããGUIã«ããã¬ã¤ã¢ã¦ããæ¡ç¨ããçç±ã§ãæãè¯ãè³ã«ããã®ãããããããã¾ããã
ã䏿¹ã§ãç§ãæ å½ãã¦ããããã¸ã§ã¯ãã§ã¯ãç´æ¥ãã¶ã¤ãã¼ããã¶ã¤ã³ãä¿®æ£ãããããªã±ã¼ã¹ã¯ã»ã¨ãã©ããã¾ããããªããªãããã¶ã¤ã³ããå®è£ ã¾ã§ã®ããã¼ã次ã®ããã«ãªã£ã¦ããããã§ã(ãã¶ã¤ã³ã®å¤æ´ãããå ´åããåºæ¬çã«ã¯åæ§ã®ããã¼ãç¹°ãè¿ãã¾ã)ã
- SketchãInVisionçã®ãã¼ã«ã§ãããã¿ã¤ãã使(ãã¶ã¤ãã¼)
- ã¨ã³ã¸ãã¢ããããã¿ã¤ãã確èªããä¸ã§ãã¶ã¤ãã¼ã¨è°è«ãããã¶ã¤ã³ãFixãã(ãã¶ã¤ãã¼ãã¨ã³ã¸ãã¢)
- Zeplinä¸ã§ã¬ã¤ã¢ã¦ãã確èªã§ããããã«ãã(ãã¶ã¤ãã¼)
- Zeplinã確èªãå®è£ ãã(ã¨ã³ã¸ãã¢)
(注:ã«ãã³å ã¯ãã®ä½æ¥ãæ å½ããè·ç¨®)
ãã¾ãããã¶ã¤ãã¼ã¯ãã¶ã¤ã³ãè¡ãã¨åæã«ãããã¶ã¤ã³è¨è¨ããè¡ã£ã¦ãã¾ããããã§ã®ããã¶ã¤ã³è¨è¨ãã¨ã¯ããã¶ã¤ã³ã®æå³ãå ã«ãçµ±ä¸ãããã¶ã¤ã³ããªã·ã¼ãå®ç¾©ãããã¨ãæå³ãã¾ããä¾ãã°ããæç¨¿ã«é¢é£ããã¢ã¯ã·ã§ã³ã«ç´ä»ãããã¿ã³ã®è²ãããListå½¢å¼ã®ãã¥ã¼ã®è¦ªãã¥ã¼ã«å¯¾ããInsetãã¨ãã£ãããã«ãã³ã³ããã¹ãã«å¯¾ãã¦æ±ºããããå¤ãåå¨ãã¾ãããã®ãã¨ããã屿çãªãã¶ã¤ã³ã®å¾®èª¿æ´ãå ¥ããã¨ã¯ããã»ã©å¤ãããã¾ããã
ãããããè¦å ãããå½è©²ããã¸ã§ã¯ãã§ã¯ãããã°ã©ãã³ã°çµé¨ã®ç¡ã人ããã¶ã¤ã³ã®ä¿®æ£ãç´æ¥è¡ããªããã¨ã¯åé¡ã«ãªã£ã¦ãã¾ããã
ã³ã¼ããã¼ã¹ã®ã¬ã¤ã¢ã¦ãã®å®è£ æ¹æ³
ãæ¬ç¯ã§ã¯ã³ã¼ããã¼ã¹ã®ã¬ã¤ã¢ã¦ãã®å®è£ æ¹æ³ã«ã¤ãã¦èª¬æãã¾ãã
ãµã¼ããã¼ãã£ã©ã¤ãã©ãªã使ç¨ãã¦ã¬ã¤ã¢ã¦ãã®ã³ã¼ããç°¡æ½ã«ãã
ãæ¨æºã®æ¹æ³ãç¨ãã¦ãã³ã¼ãã§ãã¥ã¼ã®å¶ç´ãè¨è¿°ããã®ã¯ç°¡åã¨ã¯è¨ãããã³ã¼ããåé·ã«ãªããã¡ã§ãããããããããè§£æ¶ããããã®ãµã¼ããã¼ãã£ã©ã¤ãã©ãªãåå¨ãã¦ãã¾ããä¾ãã°ã以ä¸ã®ã©ã¤ãã©ãªãæåã§ãããã
ãç§ãæ å½ãã¦ããããã¸ã§ã¯ãã§ã¯ãPureLayoutãæ¡ç¨ãã¾ãããPureLayoutãå©ç¨ããã°ãå¶ç´ã«é¢ããã³ã¼ããããªãç°¡æ½ã«è¨è¿°ãããã¨ãã§ãã¾ãã
// imageViewã®æ¨ªå¹ ã«å¯¾ããå¶ç´ãè¨å®ããããã夿°ã«ä»£å ¥ãã var imageWidthConstraint: NSLayoutConstraint imageWidthConstraint = imageView.autoSetDimension( .Width, toSize: 120) // labelã親ãã¥ã¼ã®ä¸å¿ã«é ç½®ãã label.autoCenterInSuperview() // è¤æ°ã®ãã¥ã¼ãy軸æ¹åã«ä¸å¤®æããåºå®ééã§é ç½®ãã let views: NSArray = [view1, view2, view3] views.autoDistributeViewsAlongAxis( .Vertical, alignedTo: .Vertical, withFixedSpacing: Constant.Inset.M)
ã¬ã¤ã¢ã¦ãã«é¢ããããããã£ãã¡ã½ãã
ãæ¬é ã§ã¯ãã³ã¼ããã¼ã¹ã§ã®ã¬ã¤ã¢ã¦ããå®ç¾ããä¸ã§ãéè¦ãªããããã£ãã¡ã½ãããç´¹ä»ãã¾ãã
translatesAutoresizingMaskIntoConstraintsââAutoLayoutã§AutoresizingMaskã表ç¾ãã
ããã®ããããã£ãtrue
ã«ãªã£ã¦ããã¨ãAutoresizingMaskã¨åæ§ã®æåãå®ç¾ããããã®å¶ç´ãèªåçã«è¨å®ããã¾ãããããAutoLayoutãã¼ã¹ã®ã¬ã¤ã¢ã¦ããçµãã®ã§ããã°ããã®ããããã£ãfalse
ã«ããå¿
è¦ãããã¾ãã
ãInterface Builderãç¨ãã¦Viewãçæããã°ããã®å¤ã¯èªåçã«false
ã«è¨å®ãããã®ã§ãããã³ã¼ãã§çæããã¨ããã©ã«ãå¤ã®true
ãè¨å®ããã¦ãã¾ãã¾ãããã®ãããã³ã¼ãã ãã§AutoLayoutãã¼ã¹ã®ãã¥ã¼ãçæããå ´åã¯ããã®é½åº¦ãæç¤ºçã«false
ã代å
¥ããªããã°ãªãã¾ããã
loadViewââviewããããã£ã®åæå
ãã³ã¼ãã ãã§ViewControllerãå®è£
ããå ´åãViewControllerã®view
ããããã£ãã³ã¼ãã§è¨å®ããå¿
è¦ãããã¾ããview
ããããã£ã¯loadView()
å
ã§è¨å®ããå¿
è¦ãããã¾ãã以ä¸ã®ã³ã¼ãã¯ãUITableView
ã®ã¤ã³ã¹ã¿ã³ã¹ãçæããview
ããããã£ã«è¨å®ãã¦ãã¾ãã
final class ViewController : UIViewController { private let tableView: UITableView = { let tableView = UITableView() tableView.separatorStyle = .None return tableView }() override func loadView() { view = tableView } // (çç¥) }
ããã®æãã¹ã¼ãã¼ã¯ã©ã¹ã®loadView()
ãå¼ãã§ã¯ãããªãã¨ãããã¨ã«æ³¨æãã¦ãã ãã(åè : https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/#//apple_ref/occ/instm/UIViewController/loadView)ã
ããããUIViewController
ã®ä¸ã«UITableView
ãé
ç½®ãã¦ããã ãã®Storyboardããããããªå ´åã¯ããã®ããã«è¨è¿°ãã¦ãã¡ã¤ã«æ°ãæ¸ãããã»ããããã¸ã§ã¯ãå
¨ä½ã®è¦éããè¯ããªãããããã¾ããã
viewDidLoadââviewããããã£ã®è¨å®
viewDidLoad()
ã§ã¯view
ããããã£ãåæåããã¦ãããã¨ãä¿è¨¼ããã¦ããã®ã§ãview
ã«å¯¾ããè¨å®ãä¾ãã°addSubview(_:)
ãªã©ã¯ããã§è¡ãã¾ãã
final class ViewController: UIViewController { private let userAvatarImageView : UIImageView = { let imageView = UIImageView() imageView.translatesAutoresizingMaskIntoConstraints = false imageView.contentMode = ... return imageView }() private let userNameLabel: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false label.font = ... label.textColor = ... return label }() private let descriptionTextView: UITextView = { let textView = UITextView() textView.translatesAutoresizingMaskIntoConstraints = false textView.placeholder = ... textView.font = ... textView.textColor = ... return textView }() override func loadView() { view = UIView() } override func viewDidLoad() { super.viewDidLoad() view.addSubview(userAvatarImageView) view.addSubview(userNameLabel) view.addSubview(descriptionTextView) } // (çç¥) }
updateViewConstraints/updateConstraintsââå¶ç´ã®è¨å®
ãå¶ç´ã®è¨å®ã¯ãViewControllerã§ããã°updateViewConstraints()
ã§ãé常ã®Viewã§ããã°updateConstraints()
ã®ä¸ã§è¡ãã¾ããå¶ç´ãéè¤ãã¦è¿½å ãããªãããã«æ³¨æãã¾ãããã
final class ViewController : UIViewController { private var didSetupConstraints = false // (çç¥) override func updateViewConstraints() { func setupConstraints() { imageView.autoPinEdgeToSuperviewEdge( .Top, withInset: Constant.Inset.M) imageView.autoPinEdgeToSuperviewEdge( .Leading, withInset: Constant.Inset.M) } if !didSetupConstraints { setupConstraints() didSetupConstraints = true } // ã¹ã¼ãã¼ã¯ã©ã¹ã®ã¡ã½ããã®å¼ã³å¿ããç¡ãããã«æ³¨æãã super.updateViewConstraints() } // (çç¥) }
requiresConstraintBasedLayoutââAutoLayoutãã¼ã¹ã®Viewã§ãããã¨ãæç¤ºãã
ãããViewãAutoLayoutãã¼ã¹ã®ã¬ã¤ã¢ã¦ããªã®ãã©ããã¯ããã®Viewã«å¯¾ãã¦ããã®å¶ç´ã夿´ãããããªå¦çãå®è¡ãããæç¹ã§æ±ºã¾ãã¾ãããã¨ãã°ãå¶ç´ã追å ãããæãªã©ã§ããããã¯ããã¹ã¦ã®å¶ç´ãupdateConstraints()
ã®å
é¨ã§è¨å®ãã¦ããå ´åããã¤ã¾ã§ãã£ã¦ãupdateConstraints()
ãå¼ã°ããå¶ç´ãè¨å®ãããªããã¨ãããã¨ãæå³ãã¾ãããã®ãããªèªä½ãé¿ããããã«ãAutoLayoutãã¼ã¹ã®UIView
ã®ãµãã¯ã©ã¹ã§ã¯ããã®ã¯ã©ã¹ã¡ã½ããããªã¼ãã¼ã©ã¤ããã¦true
ãè¿ãããã«ãã¾ãããã
override class func requiresConstraintBasedLayout() -> Bool { return true }
ãä¸è¨ã®åé¡ãè§£æ¶ããããã«ãsetNeedsUpdateConstraints()
ãå¼ãã§ããã³ã¼ããæã
è¦ããã¾ãããå³å¯ã«ã¯requiresConstraintBasedLayout()
ã使ããã¨ãæ£ããæ¹æ³ã§ãã
ãrequiresConstraintBasedLayout()
ã«ã¤ãã¦è§¦ãã¦ããè¨äºã¯ãã¾ãè¦ããã¨ããªãã®ã§ãç¡è¦ãããã¡ãªã¡ã½ãããªã®ããããã¾ãããããã®æåãæ£ããçè§£ãã¦ããå¿
è¦ãããã¾ããThe Mystery of the +requiresConstraintBasedLayoutã¯ããã®ã¡ã½ããã®æåã«ã¤ãã¦æ¤è¨¼ãã¦ãã¾ãã
viewDidLayoutSubviews/layoutSubviewsââãã¬ã¼ã ã«ä¾åããå¦çã®è¨è¿°
ãAutoLayoutãã¼ã¹ã®ã¬ã¤ã¢ã¦ãã§ãã£ã¦ããæçµçãªãã¬ã¼ã ã«ä¾åããã³ã¼ããæ¸ãã±ã¼ã¹ãããå¾ã¾ãããã®ãããªã³ã¼ãã¯ãViewControllerã§ã¯viewDidLayoutSubviews()
ãé常ã®Viewã§ã¯layoutSubviews()
å
ã«è¨è¿°ãã¾ãã
override func layoutSubviews() { super.layoutSubviews() // ãã®æç¹ã§ãã¬ã¼ã ã確å®ãã¦ãã // imageViewã丸ããã imageView.layer.cornerRadius = bounds.size.height/2 imageView.layer.masksToBounds = true // æçµçãªã©ãã«ã®å¹ ã«ãããã¦ãpreferredMaxLayoutWidthãè¨å®ãã label.preferredMaxLayoutWidth = label.bounds.width }
ããã®ã±ã¼ã¹ã®ããã«ãã¬ã¤ã¢ã¦ãã®ã©ã®ãã§ã¼ãºã§ä½ã決å®ãããã¾ã決å®ããã¦ããªãã®ããã¨ãããã¨ãææ¡ãã¦ããªãã¨æå¾ ããçµæãå¾ãããªããã¨ãããã¾ããã³ã¼ããã¼ã¹ã®ã¬ã¤ã¢ã¦ããè¡ãå ´åã¯å°æ´ã§ããã¬ã¤ã¢ã¦ãã®ãã¹ãæ£ããçè§£ããã«ããã£ã¦ãAdvanced Auto Layout Toolboxã大å¤åèã«ãªãã¾ãã
ãããã«
ãæ¬è¨äºã§ã¯ãã³ã¼ããã¼ã¹ã®ã¬ã¤ã¢ã¦ãã®å©ç¹ã¨ããã®å®è£ æ¹æ³ã«ã¤ãã¦èª¬æãã¾ããã
ãç§ãç´é¢ãã¦ããã±ã¼ã¹ã§ã¯ãã³ã¼ããã¼ã¹ã®ã¬ã¤ã¢ã¦ãã«è»é ãä¸ãã£ããããã¾ãã主張ãæç¢ºã«ããããã«ã³ã¼ããã¼ã¹ã®ã¬ã¤ã¢ã¦ããæ¨å¥¨ãããããªå 容ã¨ãªãã¾ãããããããå®éã¯ããã¸ã§ã¯ãããã¼ã æ¯ã«é©åãªå¤æãè¡ãã¹ãã§ãããã
ãã¾ããGUIãã¼ã¹ã®ã¬ã¤ã¢ã¦ãã¨ã³ã¼ããã¼ã¹ã®ã¬ã¤ã¢ã¦ãã¯ç¸åãããã®ã§ã¯ããã¾ãããå®ç¾ãããã¬ã¤ã¢ã¦ãã«ãããã¦ããã®é½åº¦ãé©åãªæ¹éã鏿ããã¹ãã§ãããã®ä¸ã§ãã³ã¼ããã¼ã¹ã®ã¬ã¤ã¢ã¦ãã鏿ãããã¨ã«ãªã£ãå ´åã«ãä»åã®è¨äºãå°ãã§ãçæ§ã®å½¹ã«ç«ã¦ã°å¹¸ãã§ãã
ãæå¾ã«ãªãã¾ããããæµ·å¤å±éã¯ã¾ã ã¾ã åæã®ãã§ã¼ãºã§ããããããªããã°ãªããªããã¨ãç¡æ°ã«åå¨ãã¾ããã¾ããæµ·å¤ã®æåãã¦ã¼ã¶ã¼ã®ã¢ãã¤ã«å©ç¨ç°å¢ãªã©æ§ã ãªäºæãèæ ®ããªããã°ãªããªããããå¿ ç¶çã«éçºã®é£æåº¦ã¯é«ããªãã¾ããç§ãã¡ã¯ãããããå°é£ã«ç©æ¥µçã«ç«ã¡åãããæµ·å¤ã§ã¯ãã¯ãããã®ãµã¼ãã¹ãå±éãããã¨ã«ååãã¦ãããã¢ãã¤ã«ã¨ã³ã¸ãã¢ãç©æ¥µåéä¸ã§ãï¼
å¼ç¤¾æ¡ç¨ãã¼ã¸(æµ·å¤ã°ã«ã¼ã iOS/Android ã¢ããªã¨ã³ã¸ãã¢)