ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
| この記事の要点 |
|
Storyboard で作る(UIKit)
1. ラベルを配置する
1. Main.storyboard を開く
2. Library(Cmd + Shift + L)から Label をドラッグして配置する
3. ダブルクリックして初期表示の文字を入れる
4. Attributes inspector でフォント・色・行数・配置を設定する
5. Add New Constraints で位置と幅の制約を付ける
2. コードとつなぐ
1. Assistant エディタで Storyboard とコードを並べる
2. ラベルを Control キーを押しながらコード側へドラッグする
3. Connection: Outlet ← Action ではない
Name: messageLabel
Type: UILabel
4. Connect を押す
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var messageLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
messageLabel.text = "準備ができました"
}
@IBAction func tapButton(_ sender: UIButton) {
messageLabel.text = "ボタンが押されました"
messageLabel.textColor = .systemBlue
}
}
ラベルは「操作を受け取る」部品ではないので @IBAction は作りません。Action にすると Touch Up Inside 相当のイベントが無く、接続しても何も起きません。
コードだけで作る
private let messageLabel: UILabel = {
let label = UILabel()
label.text = "準備ができました"
label.font = .preferredFont(forTextStyle: .body)
label.adjustsFontForContentSizeCategory = true // 文字サイズ設定に追従する
label.textColor = .label // ダークモードに追従する
label.numberOfLines = 0 // 何行でも折り返す
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(messageLabel)
NSLayoutConstraint.activate([
messageLabel.leadingAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16),
messageLabel.trailingAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16),
messageLabel.topAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 24),
])
}
textColor に .black ではなく .label を使うと、ダークモードで自動的に白になります。.systemBackground や .secondaryLabel も同様です。
複数行にする
label.numberOfLines = 0 // 0 = 制限なし。既定は 1
label.numberOfLines = 2 // 2 行まで
label.lineBreakMode = .byTruncatingTail // 入りきらないとき末尾を … にする
label.lineBreakMode = .byWordWrapping // 単語単位で折り返す
// 行間を調整する
let style = NSMutableParagraphStyle()
style.lineSpacing = 6
label.attributedText = NSAttributedString(
string: "1 行目\n2 行目",
attributes: [.paragraphStyle: style])
numberOfLines = 0 にしても、幅の制約が無ければ折り返しません。ラベルは自分の幅が決まらないと改行位置を計算できないため、leading と trailing(または width)の制約が必要です。
// 幅を優先して縦に伸ばす
label.setContentCompressionResistancePriority(.required, for: .vertical)
label.setContentHuggingPriority(.defaultLow, for: .horizontal)
// 1 行に収めたいときは自動縮小
label.numberOfLines = 1
label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.7
値を流し込む
// 文字列補間
let name = "田中"
messageLabel.text = "\(name) さん、こんにちは"
// 数値の整形
let price = 1234567
messageLabel.text = price.formatted() + " 円" // 1,234,567 円
// 日付の整形
messageLabel.text = Date().formatted(date: .long, time: .omitted)
// 一部だけ色を変える
let text = NSMutableAttributedString(string: "残り 3 件")
text.addAttribute(.foregroundColor, value: UIColor.systemRed,
range: NSRange(location: 3, length: 1))
messageLabel.attributedText = text
// nil を入れると何も表示されない("" と同じ扱い)
messageLabel.text = nil
非同期処理から更新する
// 落ちる: バックグラウンドスレッドから UI を触っている
URLSession.shared.dataTask(with: url) { data, _, _ in
self.messageLabel.text = "取得しました" // Main Thread Checker で警告
}.resume()
// 正しい: メインスレッドに戻す
URLSession.shared.dataTask(with: url) { data, _, _ in
DispatchQueue.main.async {
self.messageLabel.text = "取得しました"
}
}.resume()
// async / await なら @MainActor を付ける
@MainActor
private func update(_ text: String) {
messageLabel.text = text
}
Task {
let (data, _) = try await URLSession.shared.data(from: url)
await update("取得しました")
}
UI の更新は必ずメインスレッドで行います。守らないと表示が更新されない、レイアウトが崩れる、突然クラッシュするといった再現しにくい不具合になります。Xcode の Main Thread Checker が実行時に紫色の警告を出してくれます。
SwiftUI の場合
struct ContentView: View {
@State private var message = "準備ができました"
var body: some View {
VStack(spacing: 16) {
Text(message)
.font(.body)
.foregroundStyle(.primary)
.multilineTextAlignment(.center)
.lineLimit(nil) // 折り返しの制限なし
.padding(.horizontal)
Button("更新") {
message = "ボタンが押されました" // 代入するだけで再描画される
}
}
}
}
SwiftUI では @State の値が変わると自動的に画面が描き直されます。@IBOutlet のような接続も、メインスレッドへ戻す記述も不要です。
表示されないときの確認順
| 症状 | 原因 |
|---|---|
Unexpectedly found nil while unwrapping an Optional | @IBOutlet が繋がっていない/viewDidLoad より前に触っている |
| 文字が途中で切れる | numberOfLines が 1 のまま/幅の制約が無い |
| 何も表示されない | text が nil/文字色と背景色が同じ/他のビューの下にある |
| 更新しても変わらない | バックグラウンドスレッドから触っている |
| ダークモードで読めない | 色を .black で固定している。.label を使う |
| Storyboard の文字が実行時に消える | viewDidLoad で text を上書きしている |
関連
ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
子ページ
子ページはありません
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- 【django】ログイン 認証機能 2026-09-08 03:22:09
- MySQL ERROR 1063 Incorrect column specifier for column|原因と直し方 2026-09-08 03:11:09
- 【PHPエラー】Object of class stdClass could not be converted to string 2026-09-07 07:46:04
- Julia Genie ローカル開発サーバ起動完全ガイド 2026-09-07 07:46:04
- Wi-Fi とは|規格と世代(Wi-Fi 4〜7)・周波数帯・CSMA/CA・WPA3 NEW 2026-09-07 07:45:13
- set コマンドでシェルオプションと位置パラメータを操作 | bash 2026-09-07 07:45:13
- JPEG(.jpg/.jpeg)画像形式の完全ガイド — 仕様・マジックナンバー・他形式との比較・EXIF 2026-09-07 07:45:13
- UE5 Get Overlapping Actorsで特定クラスだけ処理|Class Filter・Cast To 2026-09-07 07:45:13
- Linuxで特定拡張子のファイルを再帰削除|find -deleteの安全手順 2026-09-07 07:45:13
- Django CBVでテンプレートに値を渡す|get_context_data・extra_context 2026-09-07 07:45:13
- Linuxで複数ファイルの文字列を一括置換|find・sed・xargsの安全手順 2026-09-07 07:45:13
- Laravelルートグループ|prefix・middleware・nameで一括管理 2026-09-07 07:45:13
- Linux whichコマンドの使い方|絶対パス取得とtype・command -vの違い 2026-09-07 07:45:13
- Linux catコマンドの使い方|行番号表示・複数ファイル連結 2026-09-07 07:45:13
- unable to execute 'gcc': No such file or directory 2026-09-07 07:45:13
コメントを削除してもよろしいでしょうか?