版本記錄
版本號(hào) | 時(shí)間 |
---|---|
V1.0 | 2018.08.30 |
前言
TextKit
框架是對(duì)Core Text
的封裝,用簡(jiǎn)潔的調(diào)用方式實(shí)現(xiàn)了大部分Core Text
的功能夹姥。 TextKit是一個(gè)偏上層的開發(fā)框架杉武,在iOS7
以上可用,使用它可以方便靈活處理復(fù)雜的文本布局佃声,滿足開發(fā)中對(duì)文本布局的各種復(fù)雜需求艺智。TextKit實(shí)際上是基于CoreText的一個(gè)上層框架,其是面向?qū)ο蟮幕鳌=酉聛韼灼覀兙鸵黄鹂匆幌逻@個(gè)框架十拣。感興趣的看下面幾篇文章。
1. TextKit框架詳細(xì)解析 (一) —— 基本概覽和應(yīng)用場(chǎng)景(一)
2. TextKit框架詳細(xì)解析 (二) —— 基本概覽和應(yīng)用場(chǎng)景(二)
開始
注意志鹃!注意夭问!注意!:本文的寫作背景比較老曹铃,是
iOS7
缰趋,現(xiàn)在已經(jīng)沒人使用了,但是之所以這樣還是放出來陕见,就想說一下TextKit
框架的體系和應(yīng)用范圍秘血,個(gè)別人可以忽略本文。
隨著Apple增加更多功能和特性评甜,iOS呈現(xiàn)文本的方式在過去幾年中變得越來越強(qiáng)大灰粮。 iOS 7的發(fā)布帶來了一些最重要的文本呈現(xiàn)更改。 現(xiàn)在忍坷,iOS 8以后以這種能力為基礎(chǔ)粘舟,使其更易于使用。
在iOS 6之前的過去佩研,Web視圖通常是使用混合樣式呈現(xiàn)文本的最簡(jiǎn)單方法柑肴,例如粗體,斜體或甚至帶有顏色旬薯。
2012年晰骑,iOS 6為許多UIKit控件添加了屬性字符串支持。 這使得在不使用渲染HTML的情況下實(shí)現(xiàn)這種類型的布局變得更加容易绊序。
在iOS 6中些侍,UIKit基于WebKit
和Core Graphics
的字符串繪制函數(shù)控制其文本功能,如下面的分層圖所示:
注意:在這個(gè)圖中政模,有什么事情讓你覺得奇怪嗎? 沒錯(cuò) -
UITextView
使用WebKit
蚂会。 iOS 6將文本視圖上的屬性字符串呈現(xiàn)為HTML淋样,這一事實(shí)對(duì)于尚未深入深入框架的開發(fā)人員來說并不明顯。
iOS 6中的屬性字符串確實(shí)對(duì)許多用例有用胁住。 但是趁猴,對(duì)于高級(jí)布局和多行渲染文本刊咳,Core Text仍然是唯一真正的選擇 - 相對(duì)靠近底層且繁瑣的框架。
但是儡司,從iOS 7開始娱挨,有一種更簡(jiǎn)單的方法。 憑借當(dāng)前簡(jiǎn)約的設(shè)計(jì)重點(diǎn)捕犬,避開多余裝飾并更多地關(guān)注排版 - 例如剝離所有邊框和陰影的UIButton跷坝,只留下文本 - iOS 7添加了一個(gè)用于處理文本和文本屬性的全新框架并不奇怪: Text Kit。
現(xiàn)在架構(gòu)更加整潔碉碉,所有基于文本的UIKit控件(除了UIWebView
)現(xiàn)在都使用Text Kit
柴钻,如下圖所示:
Text Kit
構(gòu)建于Core Text
之上,繼承了Core Text框架的全部功能垢粮,并且令所有開發(fā)人員高興贴届,將其包含在改進(jìn)的面向?qū)ο蟮腁PI中。
在這個(gè)Text Kit
教程中蜡吧,您將探索Text Kit的各種功能毫蚓,因?yàn)槟鸀閕Phone創(chuàng)建了一個(gè)簡(jiǎn)單但功能豐富的筆記記錄應(yīng)用程序,該應(yīng)用程序具動(dòng)態(tài)文本大小調(diào)整和動(dòng)態(tài)文本樣式昔善。
下面我們打開建立的工程并運(yùn)行元潘,界面應(yīng)該如下所示:
該應(yīng)用程序創(chuàng)建一個(gè)初始的Note實(shí)例數(shù)組,并將它們呈現(xiàn)在table view
控制器中耀鸦。sb和segue在table view
中檢測(cè)單元格選擇柬批,并處理到視圖控制器的轉(zhuǎn)換,用戶可以在其中編輯選定的note袖订。
瀏覽源代碼并稍微使用應(yīng)用程序氮帐,以了解應(yīng)用程序的結(jié)構(gòu)及其運(yùn)行方式。 完成后洛姑,請(qǐng)轉(zhuǎn)到下一部分上沐,其中討論了應(yīng)用中動(dòng)態(tài)類型的使用。
Dynamic Type - 動(dòng)態(tài)類型
Dynamic Type是iOS 7中改變游戲規(guī)則最多的功能之一楞艾,它將選擇權(quán)放在您的應(yīng)用程序上参咙,以符合用戶選擇的字體大小和權(quán)重。
在iOS 7中硫眯,打開Settings
應(yīng)用并導(dǎo)航到General/Accessibility
和General/Text Size
以查看影響應(yīng)用顯示文本方式的設(shè)置:
在iOS 8中蕴侧,打開Settings
應(yīng)用并導(dǎo)航到General/Accessibility/Larger Text
以訪問Dynamic Type
文本大小。
iOS 7提供了通過增加字體權(quán)重來增強(qiáng)文本易讀性的功能两入,以及為支持動(dòng)態(tài)文本的應(yīng)用程序設(shè)置首選字體大小的選項(xiàng)净宵。
注意:當(dāng)Apple在
WWDC 2013
上發(fā)布Text Kit
時(shí),他們強(qiáng)烈建議開發(fā)人員采用動(dòng)態(tài)類型。在WWDC 2014
上择葡,蘋果公司走得更遠(yuǎn)了紧武。他們強(qiáng)調(diào)所有內(nèi)置應(yīng)用都支持動(dòng)態(tài)類型。此外敏储,他們使得動(dòng)態(tài)類型在iOS 8中更容易使用阻星。WWDC 2014會(huì)議226表 What’s New in Tables and Collection Views,涵蓋了對(duì)table views和collections的iOS 8動(dòng)態(tài)類型支持已添。建議你觀看它妥箕!用戶希望為iOS 7及更高版本編寫的應(yīng)用程序能夠遵守這些設(shè)置。
為了使用動(dòng)態(tài)類型酝碳,您需要使用styles
指定字體矾踱,而不是明確說明字體名稱和大小。 iOS 7為UIFont
添加了一個(gè)新方法preferredFontForTextStyle
疏哗,它使用用戶的字體首選項(xiàng)為給定樣式創(chuàng)建字體呛讲。
下圖給出了六種不同字體樣式的示例:
左側(cè)的文本使用最小的用戶可選文本大小,中心的文本使用最大的文本返奉,右側(cè)的文本顯示啟用可訪問性粗體文本功能的效果贝搁。
Basic Support - 基本支持
實(shí)現(xiàn)對(duì)動(dòng)態(tài)文本的基本支持相對(duì)簡(jiǎn)單。 而不是在應(yīng)用程序中使用顯式字體芽偏,而是請(qǐng)求特定樣式的字體雷逆。 在運(yùn)行時(shí),應(yīng)用程序根據(jù)給定的樣式和用戶的文本首選項(xiàng)選擇合適的字體污尉。
使用iOS 8膀哲,Apple實(shí)現(xiàn)動(dòng)態(tài)類型比在iOS 7中更容易。特別是被碗,table views
中的默認(rèn)標(biāo)簽自動(dòng)支持動(dòng)態(tài)類型某宪! 盡管如此,您可能希望支持iOS 7锐朴,和/或您可能希望在table views
中使用自定義標(biāo)簽兴喂。 首先,您將學(xué)習(xí)如何處理iOS 7的動(dòng)態(tài)類型焚志。然后衣迷,您將了解Apple如何在iOS 8中讓您的生活更輕松。
Why iOS 7 is Great, but iOS 8 is Even Greater
初始化項(xiàng)目的deployment
設(shè)置為iOS 8酱酬,在繼續(xù)之前壶谒,構(gòu)建并運(yùn)行應(yīng)用程序并嘗試將默認(rèn)文本大小更改為各種值。您將發(fā)現(xiàn)table view
列表中的文本大小和單元格高度都會(huì)相應(yīng)更改膳沽。而且你不需要做任何事情佃迄!但是請(qǐng)注意泼差,notes本身并不反映文本大小設(shè)置的更改。
盡管不是很精彩呵俏,但iOS 7中的內(nèi)容仍然相當(dāng)不錯(cuò)。對(duì)于本文的大部分內(nèi)容滔灶,如果您使用的是iOS 7或iOS 8(只是確保您使用的是Xcode 6F账椤),現(xiàn)在录平,將應(yīng)用程序的deployment level
設(shè)置為iOS 7麻车,然后在iOS模擬器中進(jìn)行操作。以下大部分內(nèi)容在iOS 8中也有用斗这,所以即使你不打算支持早于iOS 8的iOS版本动猬,它也是值得的。
注意:要在Xcode 6中將部署級(jí)別設(shè)置為iOS 7表箭,請(qǐng)選擇
View/Navigators/Show Project Navigator
赁咙。在右側(cè)面板中,選擇項(xiàng)目免钻,單擊info
并在iOS Deployment Target
彈出菜單中選擇iOS 7彼水。此外,在右側(cè)面板中選擇目標(biāo)极舔,并將部署目標(biāo)設(shè)置為iOS 7凤覆。確保模擬器充當(dāng)iOS 7設(shè)備也很重要。所以在iOS模擬器中選擇Hardware/Device/iOS 7/iPhone 5s
拆魏。
現(xiàn)在您已經(jīng)準(zhǔn)備好作為iOS 7應(yīng)用程序運(yùn)行盯桦,繼續(xù)構(gòu)建并運(yùn)行。像以前一樣玩文字大小設(shè)置渤刃,你會(huì)發(fā)現(xiàn)遺憾的是拥峦,應(yīng)用程序忽略了你的設(shè)置。現(xiàn)在溪掀,您將做一些事情來使其在iOS 7中運(yùn)行事镣。
打開NoteEditorViewController.swift
并將以下內(nèi)容添加到viewDidLoad
的末尾:
textView.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody)
請(qǐng)注意,您沒有指定Helvetica Neue
等確切字體揪胃。 相反璃哟,您要求使用UIFontTextStyleBody
文本樣式常量為正文添加適當(dāng)?shù)淖煮w。
接下來喊递,打開NotesListViewController.swift
并在返回調(diào)用之前將以下內(nèi)容添加到tableView(_:cellForRowAtIndexPath :)
方法:
cell.textLabel?.font = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)
同樣随闪,您指定了文本樣式,iOS將返回適當(dāng)?shù)淖煮w骚勘。
使用字體名稱的語(yǔ)義方法(例如UIFontTextStyleSubHeadline
)有助于避免代碼中的硬編碼字體名稱和樣式 - 并確保您的應(yīng)用程序能夠按預(yù)期正確響應(yīng)用戶定義的排版設(shè)置铐伴。
再次構(gòu)建并運(yùn)行應(yīng)用程序撮奏,您會(huì)注意到table view
和note屏幕現(xiàn)在支持當(dāng)前文本大小当宴;兩者之間的差異顯示在下面的屏幕截圖中:
這看起來很不錯(cuò) - 但是敏銳的讀者會(huì)注意到這只是解決方案的一半畜吊。 返回General/Text Size
下的Settings
應(yīng)用,然后再次修改文本大小户矢。 這一次玲献,切換回SwiftTextKitNotepad
- 無需重新啟動(dòng)應(yīng)用程序 - 您會(huì)注意到您的應(yīng)用程序沒有響應(yīng)新的文本大小。
Responding to Updates - 響應(yīng)更新
打開NoteEditorViewController.swift
并將以下代碼添加到viewDidLoad
的末尾
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "preferredContentSizeChanged:",
name: UIContentSizeCategoryDidChangeNotification,
object: nil)
上面的代碼注冊(cè)該類以在首選內(nèi)容大小更改時(shí)接收通知梯浪,并在發(fā)生此事件時(shí)傳入要調(diào)用的方法(preferredContentSizeChanged)
捌年。
接下來,將以下方法添加到類中:
func preferredContentSizeChanged(notification: NSNotification) {
textView.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody)
}
這只是根據(jù)新的首選大小設(shè)置文本視圖字體挂洛。
注意:您可能想知道為什么看起來您將字體設(shè)置為之前的相同值礼预。 當(dāng)用戶更改其首選字體大小時(shí),您必須再次請(qǐng)求首選字體虏劲;它不會(huì)自動(dòng)更新托酸。 更改字體首選項(xiàng)時(shí),通過
preferredFontForTextStyle
返回的字體將有所不同伙单。
打開NotesListViewController.swift
并通過向類中添加以下代碼來覆蓋viewDidLoad
函數(shù):
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "preferredContentSizeChanged:",
name: UIContentSizeCategoryDidChangeNotification,
object: nil)
}
嘿获高,是不是你剛剛添加到NoteEditorViewController.swift
的代碼? 是的吻育,它是 - 但你會(huì)以稍微不同的方式處理首選的字體更改念秧。
將以下方法添加到類中:
func preferredContentSizeChanged(notification: NSNotification) {
tableView.reloadData()
}
上面的代碼只是指示table view
重新加載其可見單元格,這會(huì)更新每個(gè)單元格的外觀布疼。 這將觸發(fā)對(duì)preferredFontForTextStyle()
的調(diào)用并刷新字體選擇摊趾。
構(gòu)建并運(yùn)行您的應(yīng)用程序;更改文本大小設(shè)置游两,并驗(yàn)證您的應(yīng)用是否正確響應(yīng)新用戶首選項(xiàng)砾层。
Changing Layout - 改變布局
這部分看起來效果很好,但是當(dāng)你選擇一個(gè)非常小的字體大小時(shí)贱案,你的table view
看起來有點(diǎn)稀疏肛炮,如右下圖所示:
這是動(dòng)態(tài)類型的棘手方面之一(在iOS 7中)。 為了確保您的應(yīng)用程序在各種字體大小中看起來很好宝踪,您的布局需要響應(yīng)用戶的文本設(shè)置侨糟。 自動(dòng)布局為您解決了很多問題,但這是您必須自己解決的一個(gè)問題瘩燥。
您的表行高度需要隨著字體大小的變化而變化秕重。 實(shí)現(xiàn)tableView(_:heightForRowAtIndexPath :)
委托方法很好地解決了這個(gè)問題。
將以下代碼添加到NotesListViewController.swift
厉膀,在標(biāo)記為Table view data source
的部分中:
let label: UILabel = {
let temporaryLabel = UILabel(frame: CGRect(x: 0, y: 0, width: Int.max, height: Int.max))
temporaryLabel.text = "test"
return temporaryLabel
}()
override func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat {
label.font = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)
label.sizeToFit()
return label.frame.height * 1.7
}
上面的代碼創(chuàng)建了一個(gè)UILabel
的共享實(shí)例溶耘,table view
用它來計(jì)算單元格的高度二拐。 然后,在tableView(_:heightForRowAtIndexPath :)
中凳兵,將標(biāo)簽的字體設(shè)置為表視圖單元格使用的相同字體百新。 然后它在標(biāo)簽上調(diào)用sizeToFit
,強(qiáng)制標(biāo)簽的frame緊緊圍繞文本留荔,并導(dǎo)致frame高度與表格行高度成比例吟孙。
構(gòu)建并運(yùn)行您的應(yīng)用程序;再次修改文本大小設(shè)置聚蝶,表格行現(xiàn)在動(dòng)態(tài)調(diào)整大小以適合文本大小,如下面的屏幕截圖所示:
如果您愿意藻治,現(xiàn)在可以在本教程的其余部分將deployment
重置為iOS 8碘勉。
Letterpress Effect - 凸版印刷效果
凸版印刷效果為文本添加了細(xì)微的陰影和高光,使其具有深度感 - 就像文字略微壓入屏幕一樣桩卵。
注意:術(shù)語(yǔ)“凸版印刷 -
letterpress
”是對(duì)早期印刷機(jī)的一種認(rèn)可验靡,它印有一組刻在塊上的字母并將它們壓入頁(yè)面。 這些字母經(jīng)常在頁(yè)面上留下一個(gè)小縮進(jìn) - 這是一種意想不到但視覺上令人愉悅的效果雏节,這種效果在今天的數(shù)字排版中經(jīng)常被復(fù)制胜嗓。
打開NotesListViewController.swift
并使用以下實(shí)現(xiàn)替換tableView(_:cellForRowAtIndexPath :):
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell? {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
let note = notes[indexPath.row]
let font = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)
let textColor = UIColor(red: 0.175, green: 0.458, blue: 0.831, alpha: 1)
let attributes = [
NSForegroundColorAttributeName : textColor,
NSFontAttributeName : font,
NSTextEffectAttributeName : NSTextEffectLetterpressStyle
]
let attributedString = NSAttributedString(string: note.title, attributes: attributes)
cell.textLabel?.attributedText = attributedString
return cell
}
上面的代碼使用凸版印刷樣式為表格單元格的標(biāo)題創(chuàng)建一個(gè)屬性字符串。
構(gòu)建并運(yùn)行您的應(yīng)用程序钩乍;您的table view
現(xiàn)在將顯示具有良好凸版效果的文本辞州,如下所示:
Letterpress
是一種微妙的效果 - 但這并不意味著你應(yīng)該過度使用它! 視覺效果可能會(huì)使您的文字更有趣寥粹,但它們并不一定能讓您的文字更清晰变过。
Exclusion Paths - 路徑排除
圍繞圖像或其他對(duì)象的流動(dòng)文本是大多數(shù)文字處理器的標(biāo)準(zhǔn)特征。 Text Kit允許您使用排除路徑- exclusion paths
在復(fù)雜路徑和形狀周圍渲染文本涝涤。
告訴用戶note
的創(chuàng)建日期是很方便的媚狰;您將在顯示此信息的note
的右上角添加一個(gè)小的曲線視圖。
您將首先添加視圖本身 - 然后您將創(chuàng)建一個(gè)排除路徑以使文本環(huán)繞它阔拳。
1. Adding the View - 添加視圖
打開NoteEditorViewController.swift
并將以下屬性聲明添加到類中:
var timeView: TimeIndicatorView!
顧名思義崭孤,這里有時(shí)間指示器子視圖。
接下來糊肠,將此代碼添加到viewDidLoad
的最后:
timeView = TimeIndicatorView(date: note.timestamp)
textView.addSubview(timeView)
這只是創(chuàng)建新視圖的實(shí)例并將其添加為子視圖辨宠。
TimeIndicatorView
計(jì)算自己的大小,但不會(huì)自動(dòng)執(zhí)行此操作罪针。 當(dāng)視圖控制器布局子視圖時(shí)彭羹,您需要一種機(jī)制來調(diào)用updateSize
。
最后泪酱,將以下兩個(gè)方法添加到類中:
override func viewDidLayoutSubviews() {
updateTimeIndicatorFrame()
}
func updateTimeIndicatorFrame() {
timeView.updateSize()
timeView.frame = CGRectOffset(timeView.frame, textView.frame.width - timeView.frame.width, 0)
}
viewDidLayoutSubviews
調(diào)用updateTimeIndicatorFrame
派殷,它執(zhí)行兩項(xiàng)操作:調(diào)用updateSize
設(shè)置子視圖的大小还最,并將子視圖放在文本視圖的右上角。
剩下的就是當(dāng)視圖控制器收到內(nèi)容大小已更改的通知時(shí)調(diào)用updateTimeIndicatorFrame
毡惜。 將preferredContentSizeChanged
的實(shí)現(xiàn)替換為以下內(nèi)容:
func preferredContentSizeChanged(notification: NSNotification) {
textView.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody)
updateTimeIndicatorFrame()
}
構(gòu)建并運(yùn)行您的項(xiàng)目拓轻,點(diǎn)擊列表項(xiàng),時(shí)間指示器視圖將顯示在項(xiàng)目視圖的右上角经伙,如下所示:
修改設(shè)備文本大小首選項(xiàng)扶叉,視圖將自動(dòng)調(diào)整為適合。
但是帕膜,有些事情看起來不太對(duì)勁枣氧。 note
的文本在時(shí)間指示器視圖后面呈現(xiàn),而不是整齊地圍繞它流動(dòng)垮刹。 幸運(yùn)的是达吞,這是排除路徑旨在解決的確切問題。
打開TimeIndicatorView.swift
并查看curvePathWithOrigin()
荒典。 時(shí)間指示器視圖在填充背景時(shí)使用此代碼酪劫,但您也可以使用它來確定文本流動(dòng)的路徑。 啊哈 - 這就是為什么貝塞爾曲線的計(jì)算被分解成自己的方法寺董!
剩下的就是定義排除路徑本身覆糟。 打開NoteEditorViewController.swift
并將以下代碼塊添加到updateTimeIndicatorFrame
的最后:
let exclusionPath = timeView.curvePathWithOrigin(timeView.center)
textView.textContainer.exclusionPaths = [exclusionPath]
上面的代碼基于在時(shí)間指示器視圖中創(chuàng)建的Bezier路徑創(chuàng)建排除路徑,但是具有相對(duì)于文本視圖的原點(diǎn)和坐標(biāo)遮咖。
構(gòu)建并運(yùn)行項(xiàng)目并從列表中選擇一個(gè)項(xiàng)目滩字;現(xiàn)在,文本在時(shí)間指示器視圖周圍很好地流動(dòng)盯滚。
這個(gè)簡(jiǎn)單的例子只是劃分了排除路徑的能力踢械。 您可能會(huì)注意到exclusionPaths
屬性需要一個(gè)路徑數(shù)組,這意味著每個(gè)容器都可以支持多個(gè)排除路徑魄藕。
此外内列,排除路徑可以根據(jù)需要簡(jiǎn)單或復(fù)雜。 需要渲染星形或蝴蝶形的文字嗎背率? 只要您可以定義路徑话瞧,exclusionPaths
就會(huì)毫無問題地處理它!
當(dāng)文本容器在排除路徑更改時(shí)通知布局管理器時(shí)寝姿,您可以實(shí)現(xiàn)動(dòng)態(tài)或甚至動(dòng)畫排除路徑 - 只是不要指望您的用戶欣賞在他們嘗試閱讀時(shí)在屏幕上移動(dòng)的文本交排!
Dynamic Text Formatting and Storage - 動(dòng)態(tài)文本格式和存儲(chǔ)
您已經(jīng)看到Text Kit可以根據(jù)用戶的文本大小首選項(xiàng)動(dòng)態(tài)調(diào)整字體。 但是饵筑,如果字體可以根據(jù)實(shí)際文本本身動(dòng)態(tài)更新埃篓,那會(huì)不會(huì)很酷?
例如根资,如果您想自動(dòng)創(chuàng)建此應(yīng)用程序架专,該怎么辦:
- 使用波形符(?)包圍的任何文本都是一個(gè)花哨的字體
- 使用下劃線字符(_)斜體包圍任何文本
- 將短劃線字符( - )包圍的任何文本劃掉
- 將所有大寫字母的文字設(shè)為紅色
通過利用Text Kit
框架的強(qiáng)大功能同窘,這正是您在本節(jié)中所要做的!
為此部脚,您需要了解Text Kit中的文本存儲(chǔ)系統(tǒng)的工作原理想邦。 這是一個(gè)圖表,顯示用于存儲(chǔ)委刘,呈現(xiàn)和顯示文本的“Text Kit stack”
:
在幕后丧没,Apple會(huì)在您創(chuàng)建UITextView
,UILabel
或UITextField
時(shí)自動(dòng)為您創(chuàng)建這些類锡移。在您的應(yīng)用中呕童,您可以使用這些默認(rèn)實(shí)現(xiàn),也可以自定義任何部分以獲得自己的行為淆珊。讓我們來看看每個(gè)類:
-
NSTextStorage
將要呈現(xiàn)的文本存儲(chǔ)為屬性字符串拉庵,并通知布局管理器文本內(nèi)容的任何更改。您可能希望子類化NSTextStorage套蒂,以便在文本更新時(shí)動(dòng)態(tài)更改文本屬性。 -
NSLayoutManager
獲取存儲(chǔ)的文本并在屏幕上呈現(xiàn)它茫蛹,它在您的應(yīng)用中充當(dāng)布局“引擎”操刀。 -
NSTextContainer
描述應(yīng)用呈現(xiàn)文本的屏幕區(qū)域的幾何形狀。每個(gè)文本容器通常與UITextView
相關(guān)聯(lián)婴洼。您可能希望子類化NSTextContainer
以定義要在其中呈現(xiàn)文本的復(fù)雜形狀骨坑。
要在此應(yīng)用程序中實(shí)現(xiàn)動(dòng)態(tài)文本格式設(shè)置功能,您需要子類化NSTextStorage
柬采,以便在用戶在文本中鍵入時(shí)動(dòng)態(tài)添加文本屬性欢唾。
一旦您創(chuàng)建了自定義NSTextStorage
,您將用您自己的實(shí)現(xiàn)替換UITextView
的默認(rèn)文本存儲(chǔ)實(shí)例粉捻。讓我們?cè)囈辉嚕?/p>
Subclassing NSTextStorage - 子類化NSTextStorage
右鍵單擊項(xiàng)目導(dǎo)航器中的SwiftTextKitNotepad
組礁遣,選擇New File ...
,然后選擇iOS / Source / Cocoa Touch Class
并單擊Next
肩刃。
將類命名為SyntaxHighlightTextStorage
祟霍,使其成為NSTextStorage
的子類,并確認(rèn)語(yǔ)言設(shè)置為Swift
盈包。 單擊Next
沸呐,然后單擊Create
。
打開SyntaxHighlightTextStorage.swift
并在類聲明中添加一個(gè)新屬性:
let backingStore = NSMutableAttributedString()
文本存儲(chǔ)子類必須提供自己的持久性呢燥,因此使用NSMutableAttributedString
后備存儲(chǔ) - 稍后將對(duì)此進(jìn)行更多介紹崭添。
接下來將以下內(nèi)容添加到類中:
override var string: String {
return backingStore.string
}
override func attributesAtIndex(index: Int, effectiveRange range: NSRangePointer) -> [NSObject : AnyObject] {
return backingStore.attributesAtIndex(index, effectiveRange: range)
}
這兩個(gè)聲明中的第一個(gè)覆蓋string
計(jì)算屬性,推遲到后備存儲(chǔ)叛氨。 同樣呼渣,attributesAtIndex
方法也委托給后備存儲(chǔ)棘伴。
最后將剩余的強(qiáng)制覆蓋添加到同一個(gè)文件中:
override func replaceCharactersInRange(range: NSRange, withString str: String) {
println("replaceCharactersInRange:\(range) withString:\(str)")
beginEditing()
backingStore.replaceCharactersInRange(range, withString:str)
edited(.EditedCharacters | .EditedAttributes, range: range, changeInLength: (str as NSString).length - range.length)
endEditing()
}
override func setAttributes(attrs: [NSObject : AnyObject]!, range: NSRange) {
println("setAttributes:\(attrs) range:\(range)")
beginEditing()
backingStore.setAttributes(attrs, range: range)
edited(.EditedAttributes, range: range, changeInLength: 0)
endEditing()
}
同樣,這些方法委托給后備存儲(chǔ)徙邻。 但是排嫌,它們還包含對(duì)beginEditing
,edited
和endEditing
的調(diào)用缰犁。 文本存儲(chǔ)類需要這三種方法淳地,以便在進(jìn)行編輯時(shí)通知其關(guān)聯(lián)的布局管理器。
您可能已經(jīng)注意到帅容,為了子類化文本存儲(chǔ)颇象,您需要編寫相當(dāng)多的代碼。 由于NSTextStorage
是類集群的公共接口并徘,因此您不能僅將其子類化并覆蓋一些方法來擴(kuò)展其功能遣钳。 相反,您必須自己實(shí)現(xiàn)某些要求麦乞,例如屬性字符串?dāng)?shù)據(jù)的后備存儲(chǔ)蕴茴。
注意:類集群是Apple整個(gè)框架中常用的設(shè)計(jì)模式。類集群只是
Abstract Factory
模式的Objective-C實(shí)現(xiàn)姐直,它提供了一個(gè)通用接口倦淀,用于創(chuàng)建相關(guān)或依賴對(duì)象的族,而無需指定具體類声畏。NSArray
和NSNumber
等熟悉的類實(shí)際上是類集群的公共接口撞叽。
Apple使用類集群將私有具體子類封裝在公共抽象超類下,并且它是這個(gè)抽象超類插龄,它聲明客戶端必須使用的方法才能創(chuàng)建其私有子類的實(shí)例愿棋。客戶端也完全不知道工廠正在分配哪個(gè)私有類均牢,因?yàn)樗慌c公共接口進(jìn)行交互糠雨。
使用類集群肯定簡(jiǎn)化了界面,使學(xué)習(xí)和使用類變得更加容易膨处,但重要的是要注意在可擴(kuò)展性和簡(jiǎn)單性之間進(jìn)行權(quán)衡见秤。創(chuàng)建集群的抽象超類的自定義子類通常要困難得多。
現(xiàn)在你有了一個(gè)自定義的NSTextStorage
真椿,你需要?jiǎng)?chuàng)建一個(gè)使用它的UITextView
鹃答。
后記
本篇主要講述了一個(gè)簡(jiǎn)單布局示例,感興趣的給個(gè)贊或者關(guān)注~~~