想知道怎么樣自定義你的寵物界面嗎汰瘫?譯者注:這篇文章是使用UIAppearance定義UI界面的入門教程或听,介紹了一些具體的控件的自定義方法顷啼。
雖然iOS的擬物設(shè)計(jì)已經(jīng)成為了過(guò)去式晤郑,但是這并不代表你的iOS App的控件的外觀被限制在系統(tǒng)自有的那幾個(gè)。 當(dāng)然神妹,你可以重新定義自己的控件和App的外觀,在這個(gè)時(shí)候盖桥,Apple推薦開發(fā)者使用標(biāo)準(zhǔn)的UIKit控件并利用iOS提供的各種自定義的方法來(lái)達(dá)到你的效果灾螃。這樣做的原因是因?yàn)閁IKit控件運(yùn)行效率非常高, 另外你的這些自定義的控件也會(huì)在未來(lái)的版本中表現(xiàn)更好的兼容性揩徊。 在這個(gè)UIAppearance的教程中腰鬼,你會(huì)用一些基本的UI自定義技術(shù)美化一款尋找寵物的App使它由平常變得與眾不同。
那么開始
點(diǎn)擊這里 下載本教程的所用到的源碼塑荒。這個(gè)App使用了很多標(biāo)準(zhǔn)UIKit控件熄赡,配色是默認(rèn)的vanilla。 打開這個(gè)項(xiàng)目齿税,然后看看它的結(jié)構(gòu)彼硫,編譯運(yùn)行后,寵物查找器的主界面是這樣子的:
支持主題
很多Apps并不能讓用戶選擇主題芜壁,在大多數(shù)時(shí)候也并不推薦開發(fā)者去發(fā)布一個(gè)具有主題選擇功能的App礁凡。如果你的app顯示得內(nèi)容控制不好的話高氮,你會(huì)很快發(fā)現(xiàn)你的App中的某些主題已經(jīng)生成了并分析了某些東西,然而另外一個(gè)主題卻與之沖突顷牌。然而剪芍,你也許在開發(fā)階段會(huì)想對(duì)不同 的主題進(jìn)行測(cè)試來(lái)看看哪個(gè)更適合你的App,或者做一個(gè)A/B 測(cè)試來(lái)看Beta版本的用戶更喜歡哪種主題。 在這個(gè)UIAppearance 教程中窟蓝,你會(huì)創(chuàng)建幾個(gè)不同的主題罪裹,然后可以看看哪個(gè)更加符合你的審美。 選擇 File\New\File…然后選擇 _iOS\Source\Swift File疗锐。 _點(diǎn)擊Next然后將文件命名為Theme坊谁。最后點(diǎn)擊Next并點(diǎn)擊Create,Xcode會(huì)自動(dòng)打開你創(chuàng)建的新文件滑臊,這個(gè)文件里只有一行代碼贿条。 刪除這行代碼并且用如下代碼替換:
<pre class="">import UIKit
enum Theme {
case Default, Dark, Graphical
var mainColor: UIColor {
switch self {
case .Default:
return UIColor(red: 87.0/255.0, green: 188.0/255.0, blue: 95.0/255.0, alpha: 1.0)
case .Dark:
return UIColor(red: 242.0/255.0, green: 101.0/255.0, blue: 34.0/255.0, alpha: 1.0)
case .Graphical:
return UIColor(red: 10.0/255.0, green: 10.0/255.0, blue: 10.0/255.0, alpha: 1.0)
}
}
}</pre>
這段代碼為你的App添加了一個(gè)包含不同的主題的枚舉值斜脂。從現(xiàn)在起拨齐,所有的主題只有特定一個(gè)mainColor
然后鲸睛,添加下面的struct:
<pre class="">struct ThemeManager {
}</pre>
這段代碼讓你可以在App中使用主題。它暫時(shí)是空的关划,但是馬上會(huì)對(duì)他進(jìn)行修改小染。 然后,將下面這行代碼添加到enum
的聲明前贮折。
<pre>let SelectedThemeKey = "SelectedTheme"</pre>
現(xiàn)在裤翩,給下面ThemeManager
添加如下方法:
<pre >static func currentTheme() -> Theme {
if let storedTheme = NSUserDefaults.standardUserDefaults().valueForKey(SelectedThemeKey)?.integerValue {
return Theme(rawValue: storedTheme)!
} else {
return .Default
}
}</pre>
這兒也沒有太過(guò)復(fù)雜的代碼:這是你將用到的控制app的樣式的主方法。它使用NSUserDefaults
來(lái)持久化存儲(chǔ)你的當(dāng)前主題调榄,每次啟動(dòng)App時(shí)它都會(huì)被讀取踊赠。 要測(cè)試這個(gè)是否可用,可以打開AppDelegate.swift然后將下面代碼添加到 application(_:didFinishLaunchingWithOptions)
:
<pre>println(ThemeManager.currentTheme().mainColor)</pre>
Build and run每庆。你應(yīng)該會(huì)在控制臺(tái)看到下面的輸出結(jié)果:
<pre>UIDeviceRGBColorSpace 0.94902 0.396078 0.133333 1</pre>
那么從現(xiàn)在起筐带,你已經(jīng)有三個(gè)主題,并且你可以通過(guò)ThemeManager
對(duì)他們進(jìn)行管理$土椋現(xiàn)在是時(shí)候在App中使用他們了伦籍。
將主題添加入控件
回到Theme.swift,添加下面的方法到ThemeManager
:
<pre>static func applyTheme(theme: Theme) {
// 1
NSUserDefaults.standardUserDefaults().setValue(theme.rawValue, forKey: SelectedThemeKey)
NSUserDefaults.standardUserDefaults().synchronize()
// 2
let sharedApplication = UIApplication.sharedApplication()
sharedApplication.delegate?.window??.tintColor = theme.mainColor
}</pre>
這里我們過(guò)一遍上面的代碼:
- 先使用NSUserDefaults持久化存儲(chǔ)選中的主題
- 然后獲取你選擇的主題并且將主題的main color賦給 application's window的
tintColor
屬性腮出。關(guān)于tintColor稍后會(huì)詳細(xì)講解
然后你需要做的就是調(diào)用這個(gè)方法帖鸦,在AppDelegate.swift中調(diào)用那必須是極好的。 將之前加的 println()
語(yǔ)句替換成下面的代碼:
<pre>let theme = ThemeManager.currentTheme()
ThemeManager.applyTheme(theme)</pre>
Build and run胚嘲。你會(huì)發(fā)現(xiàn)你的App明顯看起來(lái)偏綠色調(diào)多了:
在App中到處點(diǎn)點(diǎn)富蓄;會(huì)發(fā)現(xiàn)各種地方都已經(jīng)是這種顏色了。但是你并沒有在controller或者view上面做任何修改慢逾,這個(gè)黑 — 額立倍,綠魔法到底是什么呢?使用 Tint Colors
從iOS7開始侣滩,UIView
就已經(jīng)暴露了tintColor
屬性口注,一般這個(gè)屬性被用在app的主色調(diào)選擇器和某些可交互的界面元素的交互狀態(tài)。 如果你為某個(gè)view指定一個(gè)tint君珠,那么這個(gè)tint將會(huì)自動(dòng)應(yīng)用到這個(gè)view的所有的子view中寝志,因?yàn)閁IWindow繼承于UIView,你可以通過(guò)設(shè)定window的tintColor來(lái)定義整個(gè)app的色彩策添。 點(diǎn)擊左上角的齒輪圖標(biāo)材部;一個(gè)有分段控制的 table view將會(huì)顯示出來(lái),但是當(dāng)你選擇不同的主題并提交時(shí)唯竹,沒有東西會(huì)發(fā)生改變乐导,是時(shí)候修改它了。 打開SettingsTableViewController.swift 然后添加下面的代碼到 applyTheme()
浸颓,就在dismiss()
方法上面物臂;
<pre>if let selectedTheme = Theme(rawValue: themeSelector.selectedSegmentIndex) {
ThemeManager.applyTheme(selectedTheme)
}</pre>
然后你就可以調(diào)用你在 ThemeManager
中加入的方法了,這個(gè)方法會(huì)通過(guò)設(shè)置UIWindow的tintColor屬性來(lái)設(shè)定主題的主色調(diào)产上。 下一步棵磷,添加下面這些代碼到viewDidLoad()方法的底部,這樣做了之后晋涣,選中的主題會(huì)在view controller第一次加載時(shí)就被存儲(chǔ)到 NSUserDefaults
中
<pre>themeSelector.selectedSegmentIndex = ThemeManager.currentTheme().rawValue</pre>
Build and run.點(diǎn)擊設(shè)置按鍵仪媒,選擇Dark主題然后提交修改。App的主色調(diào)將瞬間會(huì)從綠色變?yōu)槌壬?
眼尖的讀者可能會(huì)注意到這些顏色是在ThemeType
中就定義了這些顏色谢鹊。 但是算吩,當(dāng)你選擇了Dark主題,但是App的顏色看起來(lái)并不是特別的深撇贺。想要主題生效赌莺,你需要自定義一些更多的東西。
Customizing the Navigation Bar 自定義導(dǎo)航欄
打開 Theme.swift 然后添加下面的兩個(gè)方法到Theme中:
<pre>var barStyle: UIBarStyle {
switch self {
case .Default, .Graphical:
return .Default
case .Dark:
return .Black
}
}
var navigationBackgroundImage: UIImage? {
return self == .Graphical ? UIImage(named: "navBackground") : nil
}</pre>
這些方法簡(jiǎn)單的為導(dǎo)航欄獲取了獲取了主題對(duì)應(yīng)的bar style和背景圖 然后松嘶,將下面語(yǔ)句添加到applyTheme()
:
<pre>UINavigationBar.appearance().barStyle = theme.barStyle
UINavigationBar.appearance().setBackgroundImage(theme.navigationBackgroundImage, forBarMetrics: .Default)</pre>
好了——為什么這些現(xiàn)在生效了艘狭,但是之前設(shè)置UINavigationBar的barStyle卻沒有呢? UIKit有一個(gè)通知機(jī)制叫UIAppearance翠订,大部分的控件都使用了它巢音。當(dāng)你調(diào)用通過(guò)UIKit的類(非實(shí)例)調(diào)用appearance()
,它就會(huì)返回一個(gè)UIAppearance代理尽超。當(dāng)你修改了這個(gè)代理的屬性官撼,所有的這個(gè)類的實(shí)例都會(huì)被賦予相同的值。這個(gè)機(jī)制就使得你無(wú)須在修改主題時(shí)手動(dòng)修改所有控件的樣式似谁。 Build and run傲绣,選擇Dark主題掠哥,導(dǎo)航欄現(xiàn)在的顏色就深多了。
自定義后退按鈕
這個(gè)修改會(huì)對(duì)所有主題生效毅往,所有你只需要將下面的幾行加入到Themes.swift 的applyTheme()方法中:
<pre>UINavigationBar.appearance().backIndicatorImage = UIImage(named: "backArrow")
UINavigationBar.appearance().backIndicatorTransitionMaskImage = UIImage(named: "backArrowMask")</pre>
在這里你設(shè)置了后退按鈕的圖片和遮罩圖牵咙。 Build and run.選擇一個(gè)寵物你會(huì)看見新的后退按鈕:
打開Images.xcassets 然后在Navigation組里面找到backArrow的圖片,這個(gè)圖片是純黑色的攀唯,但是在App里面他會(huì)采取你的window的色板顏色然后并使之生效(it just works)洁桌。- Original:總是使用圖片的原來(lái)的顏色。
- Template:忽略顏色残拐,只是把圖片看做一個(gè)模板途茫。在這個(gè)模式下,iOS只用到圖片的形狀溪食,然后自己渲染圖片的顏色囊卜。所以當(dāng)一個(gè)控件有tint color時(shí),iOS取了你提供的圖片的形狀错沃,然后用tint color繪制他了栅组。
- Automatic:看你在什么環(huán)境下使用圖片,系統(tǒng)會(huì)自己決定使用“original”或者“template”方式枢析。對(duì)后退按鈕玉掸,導(dǎo)航欄上的按鈕和標(biāo)簽欄上的按鈕,iOS會(huì)默認(rèn)的忽略他們的圖片顏色除非你修改了他們的渲染模式醒叁。
回到App司浪,點(diǎn)擊一個(gè)寵物并點(diǎn)擊Adopt進(jìn)行領(lǐng)養(yǎng)。仔細(xì)看這個(gè)后退按鈕的動(dòng)畫把沼。有看出問題嗎啊易?
當(dāng)Back文件往左移動(dòng)時(shí),文字和按鈕的重疊看起來(lái)非常怪: 為了改正這個(gè)饮睬,你需要修改遮罩圖: 在_Themes.swift 中的_applyTheme()方法中租谈,修改設(shè)置backIndicatorTransitionMaskImage的代碼為以下這一行:<pre>UINavigationBar.appearance().backIndicatorTransitionMaskImage = UIImage(named: "backArrow")</pre>
Build and run. 重新點(diǎn)擊寵物并點(diǎn)擊Adopt進(jìn)行領(lǐng)養(yǎng)。這次效果看起來(lái)好多了捆愁。
這些文字沒有后退標(biāo)切斷割去,看起來(lái)就像藏在了后退按鈕下一樣窟却。這中間到底發(fā)生了什么呢? 當(dāng)iOS使用非透明后退圖片繪制圖標(biāo)劫拗,如果添加了過(guò)渡遮罩層间校,它將給非透明的后退圖標(biāo)添加一個(gè)蒙版層。這個(gè)圖標(biāo)也只在那個(gè)區(qū)域可見页慷。 在最開始的實(shí)現(xiàn)方法中,你提供了一個(gè)覆蓋整個(gè)后退按鈕的圖片胁附,那樣的話文字將會(huì)一致可見【品保現(xiàn)在你將圖片設(shè)置成了蒙版,然后文件將在蒙版的右側(cè)就不見了控妻,而不是在重疊在圖標(biāo)下方顯示州袒。 看看這個(gè)箭頭圖和它在圖片assets目錄下得原始蒙版圖;你就會(huì)發(fā)現(xiàn)他們配合得非常棒弓候。<pre>UINavigationBar.appearance().backIndicatorTransitionMaskImage = UIImage(named: "backArrowMaskFixed")</pre>
Build and run. 最后一次點(diǎn)擊寵物并點(diǎn)擊Adopt進(jìn)行領(lǐng)養(yǎng),你會(huì)發(fā)現(xiàn)文字在蒙版層才顯示依鸥,達(dá)到了想要的效果亥至。
現(xiàn)在你的導(dǎo)航欄已經(jīng)是像素級(jí)別的效果了,現(xiàn)在是時(shí)候給標(biāo)簽欄一點(diǎn)點(diǎn)愛了(- -!)Customizing the Tab Bar自定義標(biāo)簽欄
還是在Theme.swift贱迟,添加下面的屬性到Theme中:
<pre>var tabBarBackgroundImage: UIImage? {
return self == .Graphical ? UIImage(named: "tabBarBackground") : nil
}
var backgroundColor: UIColor {
switch self {
case .Default, .Graphical:
return UIColor(white: 0.9, alpha: 1.0)
case .Dark:
return UIColor(white: 0.8, alpha: 1.0)
}
}
var secondaryColor: UIColor {
switch self {
case .Default:
return UIColor(red: 242.0/255.0, green: 101.0/255.0, blue: 34.0/255.0, alpha: 1.0)
case .Dark:
return UIColor(red: 34.0/255.0, green: 128.0/255.0, blue: 66.0/255.0, alpha: 1.0)
case .Graphical:
return UIColor(red: 140.0/255.0, green: 50.0/255.0, blue: 48.0/255.0, alpha: 1.0)
}
}</pre>
這些屬性提供了與主題相配的背景圖姐扮,背景色和次要的顏色。 要應(yīng)用這些樣式衣吠,添加項(xiàng)目的這幾行代碼到applyTheme()
.
<pre class="">UITabBar.appearance().barStyle = theme.barStyle
UITabBar.appearance().backgroundImage = theme.tabBarBackgroundImage
let tabIndicator = UIImage(named: "tabBarSelectionIndicator")?.imageWithRenderingMode(.AlwaysTemplate)
let tabResizableIndicator = tabIndicator?.resizableImageWithCapInsets(
UIEdgeInsets(top: 0, left: 2.0, bottom: 0, right: 2.0))
UITabBar.appearance().selectionIndicatorImage = tabResizableIndicator</pre>
設(shè)置barStyle和backgroundImage大家應(yīng)該很熟悉了茶敏;這和之前在UINavigationBar所做的是一樣的。 在最后三行代碼中缚俏,你使用了asset目錄下得一個(gè)圖片作為標(biāo)簽圖片然后設(shè)置他的渲染模式為.AlwaysTemplate
惊搏。這是一個(gè)iOS沒有自動(dòng)使用template rendering mode的例子。 最后袍榆,你創(chuàng)建了一個(gè)可以拉伸的圖片胀屿,并且設(shè)置它為標(biāo)簽欄的selectionIndicatorImage Build and run. 你會(huì)看見最新帶主題的標(biāo)簽欄:
自定義分段控件
還有一個(gè)組件沒有被修改就是選中主題的分段控件還沒有被修改。是時(shí)候?qū)⑺矌刖实闹黝}世界了讹堤。 添加下面的代碼到Theme.swift的applyTheme()方法的底部:
<pre>let controlBackground = UIImage(named: "controlBackground")?
.imageWithRenderingMode(.AlwaysTemplate)
.resizableImageWithCapInsets(UIEdgeInsets(top: 3, left: 3, bottom: 3, right: 3))
let controlSelectedBackground = UIImage(named: "controlSelectedBackground")?
.imageWithRenderingMode(.AlwaysTemplate)
.resizableImageWithCapInsets(UIEdgeInsets(top: 3, left: 3, bottom: 3, right: 3))
UISegmentedControl.appearance().setBackgroundImage(controlBackground, forState: .Normal,
barMetrics: .Default)
UISegmentedControl.appearance().setBackgroundImage(controlSelectedBackground, forState: .Selected,
barMetrics: .Default)</pre>
為了理解上面的代碼吆鹤,首先看一下asset目錄下的controlBackground圖片。這個(gè)圖片也許很小洲守,但是iOS知道如何使用它來(lái)繪制UISegmentedControl的邊框疑务,就像它預(yù)先切好展好的那樣。 切好是什么意思呢梗醇?看一看下面的放大的圖吧:
這有4個(gè)33的正方形知允,每個(gè)角一個(gè)。這些正方形將會(huì)在拉升圖片時(shí)被保留原樣叙谨。然而灰色的部分將會(huì)被拉升温鸽。 在圖片中,黑色部分將呈現(xiàn)為控件的配色手负。你將通過(guò)UIEdgeInsets()
告訴iOS如何拉升這個(gè)圖片然后會(huì)給top涤垫、left、bottom和right4個(gè)參數(shù)傳值為3竟终,因?yàn)槟愕?個(gè)角是33蝠猬。 Build and run.點(diǎn)擊設(shè)置圖片,你將會(huì)發(fā)現(xiàn)UISegmentedControl有了新的樣式: UIStepper
, UISlider
, and UISwitch需要加上主題迷守。
抓起刷子犬绒,穿上廢舊的衣服開始畫畫吧!
自定義累加器兑凿、滑塊和開關(guān)
將下面行加入到Theme.swift的applyTheme()
<pre>UIStepper.appearance().setBackgroundImage(controlBackground, forState: .Normal)
UIStepper.appearance().setBackgroundImage(controlBackground, forState: .Disabled)
UIStepper.appearance().setBackgroundImage(controlBackground, forState: .Highlighted)
UIStepper.appearance().setDecrementImage(UIImage(named: "fewerPaws"), forState: .Normal)
UIStepper.appearance().setIncrementImage(UIImage(named: "morePaws"), forState: .Normal)</pre>
你使用了和UISegmentedControl相同可以拉升的圖片凯力;唯一的不同是UIStepper會(huì)在值達(dá)到上限或下限時(shí)變成不可用,所以也需要為這種情況做準(zhǔn)備礼华。簡(jiǎn)單起見這里用之前的圖咐鹤。 這里不僅修改了累加器的顏色,還替換了單調(diào)的+和-的符號(hào)按鈕 Build and run.打開查找界面去看看了累加器變成什么樣了圣絮。
UISlider
和 UISwitch
同樣也缺愛 將下面代碼加入到applyTheme()
:
<pre>UISlider.appearance().setThumbImage(UIImage(named: "sliderThumb"), forState: .Normal)
UISlider.appearance().setMaximumTrackImage(UIImage(named: "maximumTrack")?
.resizableImageWithCapInsets(UIEdgeInsets(top: 0, left: 0.0, bottom: 0, right: 6.0)),
forState: .Normal)
UISlider.appearance().setMinimumTrackImage(UIImage(named: "minimumTrack")?
.imageWithRenderingMode(.AlwaysTemplate)
.resizableImageWithCapInsets(UIEdgeInsets(top: 0, left: 6.0, bottom: 0, right: 0)),
forState: .Normal)
UISwitch.appearance().onTintColor = theme.mainColor.colorWithAlphaComponent(0.3)
UISwitch.appearance().thumbTintColor = theme.mainColor</pre>
與你看到的UISegmentedControl一樣筑舅,外觀代理自定義了所有的代理類的實(shí)體座慰。但是有個(gè)時(shí)候你并不想要所有控件一個(gè)樣--這樣的話,你可以自定義某一個(gè)控件實(shí)體翠拣。
自定義控件實(shí)體
打開SearchTableViewController.swift然后添加下面的行到viewDidLoad()
:
<pre>speciesSelector.setImage(UIImage(named: "dog"), forSegmentAtIndex: 0)
speciesSelector.setImage(UIImage(named: "cat"), forSegmentAtIndex: 1)</pre>
在這里你只是設(shè)置了種類選擇器的segment的圖片。 Build and run. 打開搜索界面游盲,種族選擇器會(huì)變成這樣
你無(wú)須做任何事情误墓,iOS便會(huì)倒反選中項(xiàng)的圖片的顏色,這是因?yàn)檫@里的圖片會(huì)自動(dòng)以Template模式進(jìn)行渲染益缎。 如何選擇性的修改控件的字體谜慌?這個(gè)也很簡(jiǎn)單 打開 PetTableViewController.swift 并添加下面兩行到viewWillAppear()的底部
:
<pre>view.backgroundColor = ThemeManager.currentTheme().backgroundColor
tableView.separatorColor = ThemeManager.currentTheme().secondaryColor</pre>
然后, 將下面這行添加到 tableView(_:cellForRowAtIndexPath:)
的末尾,在return之前:
<pre>cell.textLabel!.font = UIFont(name: "Zapfino", size: 14.0)</pre>
這樣就會(huì)修改顯示動(dòng)物名字的label的字體了莺奔。 Build and run. 進(jìn)行一下比較欣范。下面還有些什么?
點(diǎn)擊這里可以下載這篇教程的完成版的項(xiàng)目恼琼。 在Objective-C里,你可以指定特定的自定義設(shè)置應(yīng)用到只有當(dāng)他們包含在特定類的其他控件里屏富。例如晴竞,您可以將自定義的UITextField放到UINavigationBar里。 但悲劇的是狠半,swift不能這么干噩死。不過(guò)有個(gè)好消息是,iOS9將添加此功能神年,請(qǐng)期待稍后更新本教程已维。 我希望你喜歡這篇UIAppearance的教程,并且學(xué)習(xí)到調(diào)整你的UI的方法已日。其實(shí)它真的很簡(jiǎn)單垛耳。 via Ray Wenderlich. 由創(chuàng)意應(yīng)用翻譯,轉(zhuǎn)載請(qǐng)注明出處。 http://www.appccc.com/uiappearance-tutorial-below/