【SwiftUI】DisclosureGroup、OutlineGroup
今回はiOS14からのUI部品で利用できるようになったDisclosureGroup、OutlineGroupとについて取り上げます。
1.DisclosureGroupについて
・特徴
コンテンツを折りたためるビューです。
・コード
画面での表示が見やすいようにSpacer()を入れてます。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct ContentView: View { | |
struct ToggleStates { | |
var oneIsOn: Bool = false | |
var twoIsOn: Bool = true | |
} | |
@State private var toggleStates = ToggleStates() | |
@State private var topExpanded: Bool = true | |
var body: some View { | |
VStack(alignment: .leading, spacing: 10.0){ | |
DisclosureGroup("Items", isExpanded: $topExpanded) { | |
HStack{ | |
Spacer().frame(width: 20.0) | |
Toggle("Toggle 1", isOn: $toggleStates.oneIsOn) | |
Spacer() | |
} | |
HStack{ | |
Spacer().frame(width: 20.0) | |
Toggle("Toggle 2", isOn: $toggleStates.twoIsOn) | |
Spacer() | |
} | |
DisclosureGroup("Sub-items") { | |
HStack{ | |
Spacer().frame(width: 20.0) | |
Text("Sub-item 1") | |
Spacer() | |
} | |
} | |
} | |
}.padding(.all, 10.0) | |
} | |
} |
・画面表示
・全部閉じる
・全部開く
・Sub-itemsだけ開く
2.OutlineGroup
・特徴
階層化データ構造を表示するのに便利です。ForEach、ネストされたビューを表示するために使用されます。
・コード
区切り線を消したい場合は、「 .listStyle(SidebarListStyle()) 」を指定すると区切り線が消えます。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
struct ContentView: View { | |
var body: some View { | |
List{ | |
OutlineGroup(data, children: \.children) { item in | |
Text("\(item.description)") | |
} | |
} | |
// }.listStyle(SidebarListStyle()) //区切り線消す場合 | |
} | |
} | |
struct FileItem: Hashable, Identifiable, CustomStringConvertible { | |
var id: Self { self } | |
var name: String | |
var children: [FileItem]? = nil | |
var description: String { | |
switch children { | |
case nil: | |
return "📄 \(name)" | |
case .some(let children): | |
return children.isEmpty ? "📂 \(name)" : "📁 \(name)" | |
} | |
} | |
} | |
let data = | |
FileItem(name: "users", children: | |
[FileItem(name: "user1234", children: | |
[FileItem(name: "Photos", children: | |
[FileItem(name: "photo001.jpg"), | |
FileItem(name: "photo002.jpg")]), | |
FileItem(name: "Movies", children: | |
[FileItem(name: "movie001.mp4")]), | |
FileItem(name: "Documents", children: []) | |
]), | |
FileItem(name: "newuser", children: | |
[FileItem(name: "Documents", children: []) | |
]) | |
]) | |
・表示
別手法:階層データについての表示方法
OutlineGroupを利用せずにListの階層表現を使う方法がありました。SmallDeskSoftwareさんが紹介されております。以下のコードはSmallDeskSoftwareさんのコードを引用させて頂いております。
・SmallDeskSoftwareさんのサイト
・コード
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
// | |
struct ContentView: View { | |
var body: some View { | |
List(data, children: \.children) { item in | |
OutlineItemView(item: item) | |
} | |
.padding() | |
} | |
} | |
struct OutlineItemView : View { | |
let item: OutlineItem | |
var body: some View { | |
switch item.type { | |
case .Folder: | |
HStack { | |
Image(systemName: "folder") | |
.resizable() | |
.scaledToFit() | |
.frame(width: 30, height: 30) | |
Text("\(item.description)") | |
} | |
case .Symbol: | |
Image(systemName: item.name) | |
.resizable() | |
.scaledToFit() | |
.frame(width: 30, height: 30) | |
default: | |
Text("\(item.description)") | |
} | |
} | |
} | |
struct OutlineItem: Identifiable, Hashable, CustomStringConvertible { | |
var id: Self { self } | |
var name: String | |
enum ItemType { | |
case Folder | |
case Symbol | |
case Default | |
} | |
var type: ItemType = .Default | |
var children:[OutlineItem]? = nil | |
var description: String { | |
switch type { | |
case .Folder: | |
return "\(name) ( \(children?.count ?? 0) )" | |
case .Symbol: | |
return "\(name)" | |
case .Default: | |
return "\(name)" | |
} | |
} | |
} | |
let data = [OutlineItem(name: "Symbols", type: .Folder, children: [ | |
OutlineItem(name: "Transportation", type: .Folder, children: [ | |
OutlineItem(name: "bicycle", type: .Symbol, children: nil), | |
OutlineItem(name: "car", type: .Symbol, children: nil) | |
]), | |
OutlineItem(name: "Empty", type: .Folder, children: []), | |
OutlineItem(name: "Weather", type: .Folder, children: [ | |
OutlineItem(name: "sun.min", type: .Symbol, children: nil), | |
OutlineItem(name: "cloud", type: .Symbol, children: nil), | |
OutlineItem(name: "moon", type: .Symbol, children: nil) | |
])]), | |
OutlineItem(name: "Symbols.Fill", type: .Folder, children: [ | |
OutlineItem(name: "clock.fill", type: .Symbol, children: nil)]), | |
OutlineItem(name: "sum", type: .Symbol, children: nil)] | |