<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>TextKit on Joe's Blog</title><link>https://shinrenpan.github.io/tags/textkit/</link><description>Recent content in TextKit on Joe's Blog</description><generator>Hugo</generator><language>zh-tw</language><copyright>© Shinren Pan. All rights reserved.</copyright><lastBuildDate>Sat, 13 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://shinrenpan.github.io/tags/textkit/index.xml" rel="self" type="application/rss+xml"/><item><title>UILabel 計算行數、每行字串、每行大小</title><link>https://shinrenpan.github.io/2020-07-01/</link><pubDate>Wed, 01 Jul 2020 00:00:00 +0000</pubDate><guid>https://shinrenpan.github.io/2020-07-01/</guid><description>&lt;p&gt;&lt;code&gt;UILabel&lt;/code&gt; 很方便，但有幾件事它不告訴你：這段文字實際跑了幾行？每行的內容是什麼？每行佔的大小是多少？&lt;/p&gt;
&lt;p&gt;這些需求在做客製化 UI 的時候常常會遇到，例如「超過三行就顯示漸層遮罩」、「第一行要特別標色」、「根據每行高度計算捲動位置」。&lt;code&gt;UILabel&lt;/code&gt; 的公開 API 沒有提供，只好自己往下挖。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="為什麼-uilabel-沒有這些-api"&gt;為什麼 UILabel 沒有這些 API&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;UILabel&lt;/code&gt; 的設計目標是顯示文字，不是提供排版資訊。實際的排版工作由底層的 &lt;strong&gt;CoreText&lt;/strong&gt; 或 &lt;strong&gt;TextKit（NSLayoutManager）&lt;/strong&gt; 完成，&lt;code&gt;UILabel&lt;/code&gt; 把這些細節都封裝起來了。&lt;/p&gt;
&lt;p&gt;要拿到行數和行內容，就必須繞過 &lt;code&gt;UILabel&lt;/code&gt;，自己用同樣的文字和寬度重新跑一遍排版計算。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="三個計算屬性"&gt;三個計算屬性&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 5
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 6
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 7
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 8
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 9
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;10
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;11
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;12
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;13
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;14
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;15
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;16
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;17
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;18
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;19
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;20
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;21
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;22
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;23
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;24
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;25
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;26
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;27
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;28
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;29
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;30
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;31
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;32
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;33
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;34
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;35
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;36
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;37
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;38
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;39
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;40
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;41
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;42
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;43
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;44
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;45
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;46
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;47
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;48
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;49
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;50
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;51
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;52
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;53
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;54
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;55
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;56
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;57
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;58
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;59
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;60
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;61
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;62
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;63
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;64
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;65
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#cf222e"&gt;extension&lt;/span&gt; &lt;span style="color:#1f2328"&gt;UILabel&lt;/span&gt; &lt;span style="color:#1f2328"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#57606a"&gt;// &lt;/span&gt;&lt;span style="color:#57606a"&gt;MARK:&lt;/span&gt;&lt;span style="color:#57606a"&gt; - 行數&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;var&lt;/span&gt; &lt;span style="color:#953800"&gt;lineCount&lt;/span&gt;&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; &lt;span style="color:#6639ba"&gt;Int&lt;/span&gt; &lt;span style="color:#1f2328"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;guard&lt;/span&gt; &lt;span style="color:#cf222e"&gt;let&lt;/span&gt; &lt;span style="color:#953800"&gt;text&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; attributedText &lt;span style="color:#cf222e"&gt;else&lt;/span&gt; &lt;span style="color:#1f2328"&gt;{&lt;/span&gt; &lt;span style="color:#cf222e"&gt;return&lt;/span&gt; &lt;span style="color:#1f2328"&gt;.&lt;/span&gt;zero &lt;span style="color:#1f2328"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;let&lt;/span&gt; &lt;span style="color:#953800"&gt;framesetter&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; CTFramesetterCreateWithAttributedString&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;text&lt;span style="color:#1f2328"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;let&lt;/span&gt; &lt;span style="color:#953800"&gt;fittingRect&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; CGRect&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;x&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; &lt;span style="color:#0550ae"&gt;0&lt;/span&gt;&lt;span style="color:#1f2328"&gt;,&lt;/span&gt; y&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; &lt;span style="color:#0550ae"&gt;0&lt;/span&gt;&lt;span style="color:#1f2328"&gt;,&lt;/span&gt; width&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; frame&lt;span style="color:#1f2328"&gt;.&lt;/span&gt;width&lt;span style="color:#1f2328"&gt;,&lt;/span&gt; height&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; &lt;span style="color:#1f2328"&gt;.&lt;/span&gt;greatestFiniteMagnitude&lt;span style="color:#1f2328"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;let&lt;/span&gt; &lt;span style="color:#953800"&gt;path&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; UIBezierPath&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;rect&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; fittingRect&lt;span style="color:#1f2328"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;let&lt;/span&gt; &lt;span style="color:#953800"&gt;ctFrame&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; CTFramesetterCreateFrame&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;framesetter&lt;span style="color:#1f2328"&gt;,&lt;/span&gt; CFRangeMake&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;&lt;span style="color:#0550ae"&gt;0&lt;/span&gt;&lt;span style="color:#1f2328"&gt;,&lt;/span&gt; &lt;span style="color:#0550ae"&gt;0&lt;/span&gt;&lt;span style="color:#1f2328"&gt;),&lt;/span&gt; path&lt;span style="color:#1f2328"&gt;.&lt;/span&gt;cgPath&lt;span style="color:#1f2328"&gt;,&lt;/span&gt; &lt;span style="color:#cf222e"&gt;nil&lt;/span&gt;&lt;span style="color:#1f2328"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;let&lt;/span&gt; &lt;span style="color:#953800"&gt;lines&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; CTFrameGetLines&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;ctFrame&lt;span style="color:#1f2328"&gt;)&lt;/span&gt; &lt;span style="color:#cf222e"&gt;as&lt;/span&gt; &lt;span style="color:#6639ba"&gt;Array&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;return&lt;/span&gt; lines&lt;span style="color:#1f2328"&gt;.&lt;/span&gt;&lt;span style="color:#6a737d"&gt;count&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#1f2328"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#57606a"&gt;// &lt;/span&gt;&lt;span style="color:#57606a"&gt;MARK:&lt;/span&gt;&lt;span style="color:#57606a"&gt; - 每行字串&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;var&lt;/span&gt; &lt;span style="color:#953800"&gt;lineStrings&lt;/span&gt;&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; &lt;span style="color:#1f2328"&gt;[&lt;/span&gt;&lt;span style="color:#6639ba"&gt;String&lt;/span&gt;&lt;span style="color:#1f2328"&gt;]?&lt;/span&gt; &lt;span style="color:#1f2328"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;guard&lt;/span&gt; &lt;span style="color:#cf222e"&gt;let&lt;/span&gt; &lt;span style="color:#953800"&gt;text&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; text&lt;span style="color:#1f2328"&gt;,&lt;/span&gt; &lt;span style="color:#cf222e"&gt;let&lt;/span&gt; &lt;span style="color:#953800"&gt;font&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; font &lt;span style="color:#cf222e"&gt;else&lt;/span&gt; &lt;span style="color:#1f2328"&gt;{&lt;/span&gt; &lt;span style="color:#cf222e"&gt;return&lt;/span&gt; &lt;span style="color:#cf222e"&gt;nil&lt;/span&gt; &lt;span style="color:#1f2328"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;let&lt;/span&gt; &lt;span style="color:#953800"&gt;attStr&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; NSMutableAttributedString&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;string&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; text&lt;span style="color:#1f2328"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; attStr&lt;span style="color:#1f2328"&gt;.&lt;/span&gt;addAttribute&lt;span style="color:#1f2328"&gt;(.&lt;/span&gt;font&lt;span style="color:#1f2328"&gt;,&lt;/span&gt; value&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; font&lt;span style="color:#1f2328"&gt;,&lt;/span&gt; range&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; NSRange&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;location&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; &lt;span style="color:#0550ae"&gt;0&lt;/span&gt;&lt;span style="color:#1f2328"&gt;,&lt;/span&gt; length&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; attStr&lt;span style="color:#1f2328"&gt;.&lt;/span&gt;length&lt;span style="color:#1f2328"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;let&lt;/span&gt; &lt;span style="color:#953800"&gt;framesetter&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; CTFramesetterCreateWithAttributedString&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;attStr&lt;span style="color:#1f2328"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;let&lt;/span&gt; &lt;span style="color:#953800"&gt;fittingRect&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; CGRect&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;x&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; &lt;span style="color:#0550ae"&gt;0&lt;/span&gt;&lt;span style="color:#1f2328"&gt;,&lt;/span&gt; y&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; &lt;span style="color:#0550ae"&gt;0&lt;/span&gt;&lt;span style="color:#1f2328"&gt;,&lt;/span&gt; width&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; frame&lt;span style="color:#1f2328"&gt;.&lt;/span&gt;width&lt;span style="color:#1f2328"&gt;,&lt;/span&gt; height&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; &lt;span style="color:#1f2328"&gt;.&lt;/span&gt;greatestFiniteMagnitude&lt;span style="color:#1f2328"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;let&lt;/span&gt; &lt;span style="color:#953800"&gt;path&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; UIBezierPath&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;rect&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; fittingRect&lt;span style="color:#1f2328"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;let&lt;/span&gt; &lt;span style="color:#953800"&gt;ctFrame&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; CTFramesetterCreateFrame&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;framesetter&lt;span style="color:#1f2328"&gt;,&lt;/span&gt; CFRangeMake&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;&lt;span style="color:#0550ae"&gt;0&lt;/span&gt;&lt;span style="color:#1f2328"&gt;,&lt;/span&gt; attStr&lt;span style="color:#1f2328"&gt;.&lt;/span&gt;length&lt;span style="color:#1f2328"&gt;),&lt;/span&gt; path&lt;span style="color:#1f2328"&gt;.&lt;/span&gt;cgPath&lt;span style="color:#1f2328"&gt;,&lt;/span&gt; &lt;span style="color:#cf222e"&gt;nil&lt;/span&gt;&lt;span style="color:#1f2328"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;guard&lt;/span&gt; &lt;span style="color:#cf222e"&gt;let&lt;/span&gt; &lt;span style="color:#953800"&gt;lines&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; CTFrameGetLines&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;ctFrame&lt;span style="color:#1f2328"&gt;)&lt;/span&gt; &lt;span style="color:#cf222e"&gt;as&lt;/span&gt;&lt;span style="color:#1f2328"&gt;?&lt;/span&gt; &lt;span style="color:#1f2328"&gt;[&lt;/span&gt;CTLine&lt;span style="color:#1f2328"&gt;]&lt;/span&gt; &lt;span style="color:#cf222e"&gt;else&lt;/span&gt; &lt;span style="color:#1f2328"&gt;{&lt;/span&gt; &lt;span style="color:#cf222e"&gt;return&lt;/span&gt; &lt;span style="color:#cf222e"&gt;nil&lt;/span&gt; &lt;span style="color:#1f2328"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;return&lt;/span&gt; lines&lt;span style="color:#1f2328"&gt;.&lt;/span&gt;&lt;span style="color:#6a737d"&gt;map&lt;/span&gt; &lt;span style="color:#1f2328"&gt;{&lt;/span&gt; line &lt;span style="color:#cf222e"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;let&lt;/span&gt; &lt;span style="color:#953800"&gt;range&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; CTLineGetStringRange&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;line&lt;span style="color:#1f2328"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;return&lt;/span&gt; &lt;span style="color:#1f2328"&gt;(&lt;/span&gt;text &lt;span style="color:#cf222e"&gt;as&lt;/span&gt; NSString&lt;span style="color:#1f2328"&gt;).&lt;/span&gt;substring&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;with&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; NSRange&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;location&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; range&lt;span style="color:#1f2328"&gt;.&lt;/span&gt;location&lt;span style="color:#1f2328"&gt;,&lt;/span&gt; length&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; range&lt;span style="color:#1f2328"&gt;.&lt;/span&gt;length&lt;span style="color:#1f2328"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#1f2328"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#1f2328"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#57606a"&gt;// &lt;/span&gt;&lt;span style="color:#57606a"&gt;MARK:&lt;/span&gt;&lt;span style="color:#57606a"&gt; - 每行 Frame&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;var&lt;/span&gt; &lt;span style="color:#953800"&gt;lineFrames&lt;/span&gt;&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; &lt;span style="color:#1f2328"&gt;[&lt;/span&gt;CGRect&lt;span style="color:#1f2328"&gt;]&lt;/span&gt; &lt;span style="color:#1f2328"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;guard&lt;/span&gt; &lt;span style="color:#cf222e"&gt;let&lt;/span&gt; &lt;span style="color:#953800"&gt;text&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; attributedText &lt;span style="color:#cf222e"&gt;else&lt;/span&gt; &lt;span style="color:#1f2328"&gt;{&lt;/span&gt; &lt;span style="color:#cf222e"&gt;return&lt;/span&gt; &lt;span style="color:#1f2328"&gt;[]&lt;/span&gt; &lt;span style="color:#1f2328"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;let&lt;/span&gt; &lt;span style="color:#953800"&gt;layoutManager&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; NSLayoutManager&lt;span style="color:#1f2328"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;let&lt;/span&gt; &lt;span style="color:#953800"&gt;textStorage&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; NSTextStorage&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;attributedString&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; text&lt;span style="color:#1f2328"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; textStorage&lt;span style="color:#1f2328"&gt;.&lt;/span&gt;addLayoutManager&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;layoutManager&lt;span style="color:#1f2328"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;let&lt;/span&gt; &lt;span style="color:#953800"&gt;textContainer&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; NSTextContainer&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;size&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; CGSize&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;width&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; frame&lt;span style="color:#1f2328"&gt;.&lt;/span&gt;width&lt;span style="color:#1f2328"&gt;,&lt;/span&gt; height&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; &lt;span style="color:#1f2328"&gt;.&lt;/span&gt;greatestFiniteMagnitude&lt;span style="color:#1f2328"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; textContainer&lt;span style="color:#1f2328"&gt;.&lt;/span&gt;lineFragmentPadding &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; &lt;span style="color:#0550ae"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; textContainer&lt;span style="color:#1f2328"&gt;.&lt;/span&gt;lineBreakMode &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; &lt;span style="color:#1f2328"&gt;.&lt;/span&gt;byWordWrapping
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; textContainer&lt;span style="color:#1f2328"&gt;.&lt;/span&gt;maximumNumberOfLines &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; &lt;span style="color:#0550ae"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; layoutManager&lt;span style="color:#1f2328"&gt;.&lt;/span&gt;addTextContainer&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;textContainer&lt;span style="color:#1f2328"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;var&lt;/span&gt; &lt;span style="color:#953800"&gt;result&lt;/span&gt;&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; &lt;span style="color:#1f2328"&gt;[&lt;/span&gt;CGRect&lt;span style="color:#1f2328"&gt;]&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; &lt;span style="color:#1f2328"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;var&lt;/span&gt; &lt;span style="color:#953800"&gt;index&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; &lt;span style="color:#0550ae"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;var&lt;/span&gt; &lt;span style="color:#953800"&gt;lineRange&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; NSRange&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;location&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; NSNotFound&lt;span style="color:#1f2328"&gt;,&lt;/span&gt; length&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; &lt;span style="color:#0550ae"&gt;0&lt;/span&gt;&lt;span style="color:#1f2328"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;while&lt;/span&gt; index &lt;span style="color:#0550ae"&gt;&amp;lt;&lt;/span&gt; layoutManager&lt;span style="color:#1f2328"&gt;.&lt;/span&gt;numberOfGlyphs &lt;span style="color:#1f2328"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;let&lt;/span&gt; &lt;span style="color:#953800"&gt;rect&lt;/span&gt; &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; layoutManager&lt;span style="color:#1f2328"&gt;.&lt;/span&gt;lineFragmentUsedRect&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;forGlyphAt&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; index&lt;span style="color:#1f2328"&gt;,&lt;/span&gt; effectiveRange&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; &lt;span style="color:#1f2328"&gt;&amp;amp;&lt;/span&gt;lineRange&lt;span style="color:#1f2328"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result&lt;span style="color:#1f2328"&gt;.&lt;/span&gt;append&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;rect&lt;span style="color:#1f2328"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; index &lt;span style="color:#1f2328"&gt;=&lt;/span&gt; NSMaxRange&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;lineRange&lt;span style="color:#1f2328"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#1f2328"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cf222e"&gt;return&lt;/span&gt; result
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#1f2328"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#1f2328"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="為什麼-linecount-和-linestrings-用-coretextlineframes-用-textkit"&gt;為什麼 lineCount 和 lineStrings 用 CoreText，lineFrames 用 TextKit&lt;/h2&gt;
&lt;p&gt;CoreText 和 TextKit 是兩套不同層級的文字排版系統：&lt;/p&gt;</description></item></channel></rss>