attributed-string について
Swift開発者向けのFoundation AttributedStringガイドです。テキスト装飾、段落書式、選択範囲の編集、SwiftUI連携を扱い、APIの使い方と対応OSの条件を説明します。
主な機能
- 01フォント・色・下線の設定
- 02配置・方向・行の高さの制御
- 03テキスト選択範囲の置換と編集
- 04不連続なテキスト範囲の処理
- 05SwiftUIでのリッチテキスト表示と編集
活用シーン
- 01テキストの一部にスタイルを適用
- 02段落の配置や行間を調整
- 03エディターで選択テキストを置換
- 04SwiftUIのリッチテキスト編集画面を作成
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ rshankras/ claude-code-apple-skills --skill attributed-stringインストール後、Claude Code で/attributed-stringを入力して読み込まれたか確認します。
詳細
AttributedString のパターン
Foundation の AttributedString の正しい API の形とパターンです。スタイル付きテキストの作成、範囲への属性の適用、テキストの配置、書字方向、行の高さの制御、テキストの選択と編集、非連続部分文字列、SwiftUI との統合を扱います。
このスキルが有効になる場合
次のような質問には、このスキルを使用してください。
- AttributedString の作成や操作について質問されたとき
- フォント、色、下線などの属性でテキストにスタイルを適用したいとき
- テキストの配置、書字方向、行の高さに言及されたとき
- AttributedString を使ったテキストの選択やテキストの編集について質問されたとき
- DiscontiguousAttributedSubstring や RangeSet を使いたいとき
- SwiftUI で AttributedString を使った TextEditor に言及されたとき
- Swift でのリッチテキストの書式設定について質問されたとき
- AttributedString 内のテキストを置換または変更したいとき
- paragraphStyle、textSelectionAffinity、AttributedTextSelection に言及されたとき
判断フロー
What do you need with AttributedString?
|
+-- Create or style text
| |
| +-- Simple inline attributes (font, color)
| | --> Creating and Styling section
| |
| +-- Paragraph-level formatting (alignment, line height)
| --> Text Alignment and Formatting section
|
+-- Control text layout
| |
| +-- Writing direction (LTR / RTL)
| | --> Writing Direction and Line Height section
| |
| +-- Line spacing / height
| --> Writing Direction and Line Height section
|
+-- Edit or select text programmatically
| |
| +-- Replace selection with characters or AttributedString
| | --> Text Selection and Editing section
| |
| +-- Work with multiple non-contiguous ranges
| --> DiscontiguousAttributedSubstring section
|
+-- Display in SwiftUI
--> SwiftUI Integration section
API の利用可能状況
| API | 最低バージョン | 備考 |
|---|---|---|
AttributedString | iOS 15 / macOS 12 | NSAttributedString に代わる Swift ネイティブの型 |
AttributedString.paragraphStyle | iOS 15 / macOS 12 | NSMutableParagraphStyle を使用 |
AttributedString.writingDirection | iOS 26 / macOS 26 | 2025 年に追加 |
AttributedString.LineHeight | iOS 26 / macOS 26 | .exact(points:)、.multiple(factor:)、.loose |
AttributedString.alignment | iOS 26 / macOS 26 | .left、.center、.right |
AttributedTextSelection | iOS 26 / macOS 26 | プログラムによるテキストの選択 |
replaceSelection(_:withCharacters:) | iOS 26 / macOS 26 | 選択範囲を通常の文字で置換 |
replaceSelection(_:with:) | iOS 26 / macOS 26 | 選択範囲を AttributedString で置換 |
DiscontiguousAttributedSubstring | iOS 26 / macOS 26 | 非連続範囲の選択 |
AttributedString.utf8 | iOS 26 / macOS 26 | UTF-8 コード単位のビュー |
AttributedString を使った TextEditor(text:selection:) | iOS 26 / macOS 26 | SwiftUI のリッチテキスト編集 |
.textSelectionAffinity(_:) | iOS 26 / macOS 26 | 行境界でのカーソルのアフィニティを制御 |
よくある間違いトップ 5
| # | 間違い | 修正方法 |
|---|---|---|
| 1 | 新しい Swift コードで NSAttributedString を使用する | 型安全で Swift ネイティブの属性を使える iOS 15 以降では AttributedString を使用します |
| 2 | 範囲が存在するか確認せずに、範囲ベースの属性を適用する | 添字アクセスの前に、text.range(of:) の結果を必ず安全にアンラップします |
| 3 | AttributedString が値型であることを忘れる | 変更には let ではなく var が必要です。var として宣言してから属性を割り当てます |
| 4 | 新しい配置 API が使えるのに NSMutableParagraphStyle を作成する | iOS 26 以降では、手動で段落スタイルを設定する代わりに text.alignment = .center を使用します |
| 5 | replaceSelection の使用時に、選択範囲ではなく元の文字列を変更する | 選択範囲を inout として渡すと、API が選択範囲を更新します |
作成とスタイル設定
基本的な初期化
// Plain text
let plain = AttributedString("Hello, world!")
// With attributes applied inline
var bold = AttributedString("Bold text")
bold.font = .boldSystemFont(ofSize: 16)
範囲への属性の適用
var text = AttributedString("Styled text")
text.foregroundColor = .red
text.backgroundColor = .yellow
text.font = .systemFont(ofSize: 14)
// Attribute on a specific range
if let range = text.range(of: "Styled") {
text[range].underlineStyle = .single
text[range].underlineColor = .blue
}
部分文字列からの作成
let source = AttributedString("Hello, world!")
if let range = source.range(of: "world") {
let substring = source[range]
let extracted = AttributedString(substring) // standalone copy
}
| パターン | 判定 |
|---|---|
var text = AttributedString("...") を作成してから変更する | 正しい |
let text = AttributedString("...") を作成してから変更する | コンパイルできません。値型には var が必要です |
text.range(of:)! で強制アンラップする | 不安定です。if let または guard let を使用します |
テキストの配置と書式設定
従来の方法(iOS 15 以降)
var paragraph = AttributedString("Centered paragraph of text")
let style = NSMutableParagraphStyle()
style.alignment = .center
paragraph.paragraphStyle = style
最新の方法(iOS 26 以降)
var paragraph = AttributedString("Centered paragraph of text")
paragraph.alignment = .center
使用できる TextAlignment の値:
| 値 | 説明 |
|---|---|
.left | 左揃えのテキスト |
.right | 右揃えのテキスト |
.center | 中央揃えのテキスト |
書字方向と行の高さ
書字方向(iOS 26 以降)
var text = AttributedString("Hello عربي")
text.writingDirection = .rightToLeft
| 値 | 説明 |
|---|---|
.leftToRight | 標準的な左から右へのレイアウト |
.rightToLeft | アラビア語やヘブライ語などの右から左へのレイアウト |
行の高さ(iOS 26+)
var multiline = AttributedString(
"This is a paragraph\nwith multiple lines\nof text."
)
// Exact point value
multiline.lineHeight = .exact(points: 32)
// Multiplier of the default line height
multiline.lineHeight = .multiple(factor: 2.5)
// System-defined loose spacing
multiline.lineHeight = .loose
| モード | 用途 |
|---|---|
.exact(points:) | 固定の行の高さを使用するピクセル単位で正確なデザイン |
.multiple(factor:) | フォントサイズに対する比例的な拡大縮小 |
.loose | システムが選択する、読みやすい行間 |
テキストの選択と編集
選択したテキストの置換(iOS 26+)
var text = AttributedString("Here is my dog")
var selection = AttributedTextSelection(range: text.range(of: "dog")!)
// Replace with plain characters
text.replaceSelection(&selection, withCharacters: "cat")
// Replace with an AttributedString
let replacement = AttributedString("horse")
text.replaceSelection(&selection, with: replacement)
要点:プレーンテキストには withCharacters: を、スタイル付きの置換には with: を使用します。
DiscontiguousAttributedSubstring
複数の連続していない範囲を一度に選択して操作します(iOS 26+)。
let text = AttributedString("Select multiple parts of this text")
if let range1 = text.range(of: "Select"),
let range2 = text.range(of: "text") {
let rangeSet = RangeSet([range1, range2])
var substring = text[rangeSet] // DiscontiguousAttributedSubstring
substring.backgroundColor = .yellow
// Flatten into a single contiguous AttributedString
let combined = AttributedString(substring)
}
UTF-8ビュー
生のUTF-8コード単位にアクセスします(iOS 26+):
let text = AttributedString("Hello")
for codeUnit in text.utf8 {
print(codeUnit)
}
SwiftUIとの統合
AttributedStringと選択範囲を使ったTextEditor(iOS 26+)
struct SuggestionTextEditor: View {
@State var text: AttributedString = ""
@State var selection = AttributedTextSelection()
var body: some View {
VStack {
TextEditor(text: $text, selection: $selection)
SuggestionsView(
substrings: getSubstrings(
text: text,
indices: selection.indices(in: text)
)
)
}
}
}
テキスト選択のアフィニティ
行の境界にカーソルを置いたときに、カーソルを表示する行を制御します:
TextEditor(text: $text, selection: $selection)
.textSelectionAffinity(.upstream)
.upstream はカーソルを前の行の末尾に保持し、.downstream は次の行の先頭に移動します。
SwiftUIでのスタイル付きテキストの表示
// Simple display
Text(attributedString)
// With text selection enabled
Text(attributedString)
.textSelection(.enabled)
レビューチェックリスト
正確性
- 新しいSwiftコードでは
NSAttributedStringではなくAttributedStringを使用している - すべての範囲検索を
if letまたはguard letで安全にアンラップしている - 属性を適用する前に、文字列を
varとして宣言している -
replaceSelectionに選択範囲をinout(&selection)として渡している
プラットフォームとバージョン管理
- 新しいAPI(alignment、writingDirection、lineHeight、selection)をiOS 26+/macOS 26+向けに条件付きで使用している
- iOS 15~25を対象とする場合は、従来の段落スタイルの方法を使用している
- 古いデプロイメントターゲットにも対応する場合、新しいAPIを利用する箇所を可用性チェック(
if #available)で囲んでいる
SwiftUI
- リッチテキスト編集には
TextEditor(text:selection:)のオーバーロードを使用している(iOS 26+) - 行の折り返し時のカーソル動作が重要な箇所に
.textSelectionAffinityを適用している - ユーザーコンテンツを表示する
Textビューに.textSelection(.enabled)を追加している
アクセシビリティ
- 前景色と背景色の組み合わせがコントラスト要件を満たしている
- スタイル付きテキストが意味を伝える手段として色だけに依存していない(下線、太字、アイコンを追加している)
- RTL言語のコンテンツに適切な書字方向を設定している
参考資料
コメント
Markdown 対応