Skip to content

Commit

Permalink
列表优化,内容添加
Browse files Browse the repository at this point in the history
- 列表优化。
- 添加 List 内容。
- Lazy 容器、Grid、Table 表格等内容。
  • Loading branch information
ming1016 committed May 14, 2024
1 parent e285b0e commit 5a87761
Show file tree
Hide file tree
Showing 25 changed files with 956 additions and 44 deletions.
80 changes: 74 additions & 6 deletions SwiftPamphletApp.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

29 changes: 23 additions & 6 deletions SwiftPamphletApp/Guide/View/GuideListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ struct GuideListView: View {
.contentShape(Rectangle())
}
}
.searchable(text: $listModel.searchText)
.searchable(text: $listModel.searchText, prompt: "搜索 Apple 技术手册")
.listStyle(.sidebar)
.onChange(of: trigger, { oldValue, newValue in
updateApBookmarks()
Expand Down Expand Up @@ -213,13 +213,13 @@ final class GuideListModel {
]),
L(t: "Link"),
L(t: "Label"),
L(t: "TextEditor"),
L(t: "TextEditor", icon: "arrow.up.and.down.text.horizontal"),
L(t: "TextField"),
L(t: "Image"),
]),
L(t: "数据集合组件", sub: [
L(t: "ForEach"),
L(t: "Scroll视图", icon: "scroll", sub: [
L(t: "Scroll视图", icon: "scroll.fill", sub: [
L(t: "ScrollView"),
L(t: "固定到滚动视图的顶部",icon: "pin.circle"),
L(t: "滚动到特定的位置"),
Expand All @@ -229,10 +229,27 @@ final class GuideListModel {
]),
L(t: "List列表", icon: "list.bullet.rectangle.portrait.fill", sub: [
L(t: "List", icon: "list.bullet.rectangle.portrait"),
L(t: "List-设置样式"),
L(t: "List-移动元素"),
L(t: "List-搜索", icon: "text.magnifyingglass"),
L(t: "List-下拉刷新", icon: "arrow.circlepath"),
L(t: "List-轻扫操作", icon: "hand.point.up.left.and.text"),
L(t: "List-大纲视图"),
L(t: "List-完全可点击的行"),
L(t: "List-索引标题"),
L(t: "List-加载更多"),
]),
L(t: "Lazy容器", sub: [
L(t: "LazyVStack和LazyHStack"),
L(t: "LazyVGrid和LazyHGrid"),
]),
L(t: "Grid", icon: "square.grid.3x2"),
L(t: "Table表格", sub: [
L(t: "Table"),
L(t: "Table-样式"),
L(t: "Table-行的选择"),
L(t: "Table-多属性排序"),
]),
L(t: "LazyVStack和LazyHStack"),
L(t: "LazyVGrid和LazyHGrid"),
L(t: "table"),
]),
L(t: "布局组件", sub: [
L(t: "Navigation"),
Expand Down
2 changes: 1 addition & 1 deletion SwiftPamphletApp/Guide/WWDC/WWDCListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ struct WWDCListView: View {
}
})
.listStyle(.sidebar)
.searchable(text: $wwdcVM.searchText)
.searchable(text: $wwdcVM.searchText, prompt: "搜索 WWDC Session 内容")
.overlay {
if wwdcVM.filtered().isEmpty {
ContentUnavailableView {
Expand Down
2 changes: 1 addition & 1 deletion SwiftPamphletApp/InfoOrganizer/Info/InfoListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ struct InfoListView: View {
}

}
.searchable(text: $searchText)
.searchable(text: $searchText, prompt:"搜索资料")
.onAppear {
_ = parseSearchTerms()
}
Expand Down
4 changes: 3 additions & 1 deletion SwiftPamphletApp/InfoOrganizer/Info/InfoRowView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@ struct InfoRowView: View {
}
if info.url.isEmpty == false {
HStack {
Text(info.name) + Text(" - \(hostFromString(info.url))").font(.footnote).foregroundStyle(.secondary)
Text(info.name).bold() + Text(" - \(hostFromString(info.url))").font(.footnote).foregroundStyle(.secondary)
}
.fixedSize(horizontal: false, vertical: true)
} else {
Text(info.name)
.bold()
.fixedSize(horizontal: false, vertical: true)
}

Expand Down Expand Up @@ -94,6 +95,7 @@ struct InfoRowView: View {
.font(.footnote)
.padding(EdgeInsets(top: 0, leading: 0, bottom: 10, trailing: 0))
}
.listRowSeparator(.hidden, edges: .all)
.swipeActions {
Button(role: .destructive) {
IOInfo.delete(info)
Expand Down
13 changes: 7 additions & 6 deletions SwiftPamphletApp/InfoOrganizer/Info/InfosView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,15 @@ struct InfosView: View {
List(selection: $selectInfo) {
ForEach(infos) { info in
InfoRowView(info: info)
.tag(info)
.onAppear {
if info == infos.last {
if limit <= infos.count {
limit += 50

.tag(info)
.onAppear {
if info == infos.last {
if limit <= infos.count {
limit += 50
}
}
}
}
}
} // end List
.listStyle(.plain)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

Grid 会将最大的一个单元格大小应用于所有单元格

代码例子:

```swift
struct ContentView: View {
var body: some View {
Grid(alignment: .center,
horizontalSpacing: 30,
verticalSpacing: 8) {
GridRow {
Text("Tropical")
Text("Mango")
Text("Pineapple")
}
GridRow(alignment: .bottom) {
Text("Leafy")
Text("Spinach")
Text("Kale")
Text("Lettuce")
}
}
}
}
```

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ List 除了能够展示数据外,还有下拉刷新、过滤搜索和侧滑 Sw

通过 List 的可选子项参数提供数据模型的关键路径来制定子项路劲,还可以实现大纲视图,使用 DisclosureGroup 和 OutlineGroup 可以进一步定制大纲视图。

使用 `.listRowSeparator(.hidden, edges: .all)` 可以隐藏分割线。

下面是 List 使用,包括了 DisclosureGroup 和 OutlineGroup 的演示代码:

```swift
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

你可以使用 `.refreshable()` 修饰符来添加下拉刷新功能。以下是一个例子:

```swift
struct ContentView: View {
@State private var items = ["Item 1", "Item 2", "Item 3", "Item 4", "Item 5"]

var body: some View {
List {
ForEach(items, id: \.self) { item in
Text(item)
}
}
.refreshable {
await refresh()
}
}

func refresh() async {
// 这里是你的刷新逻辑
// 例如,你可以从网络获取新的数据,然后更新 items 数组
// 这里我们只是简单地将 items 数组反转
items.reverse()
}
}
```

在这个例子中,我们创建了一个包含五个元素的 List,并添加了下拉刷新功能。当用户下拉 List 时,`refresh()` 方法会被调用,然后我们将 items 数组反转,从而模拟刷新操作。注意,`refresh()` 方法需要是一个异步方法,因为刷新操作通常需要一些时间来完成。
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@


你可以通过检测列表滚动到底部来实现加载更多的功能。以下是一个简单的例子:

```swift
struct ContentView: View {
@State private var items = Array(0..<20)

var body: some View {
List {
ForEach(items, id: \.self) { item in
Text("Item \(item)")
.onAppear {
if item == items.last {
loadMore()
}
}
}
}
.onAppear(perform: loadMore)
}

func loadMore() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
let newItems = Array(self.items.count..<self.items.count + 20)
self.items.append(contentsOf: newItems)
}
}
}
```

在这个例子中,我们创建了一个包含多个元素的 List。当 List 出现最后一项时,我们调用 `loadMore` 方法来加载更多的元素。在 `loadMore` 方法中,模拟在一秒后添加新的元素到 `items` 数组中。

请注意,这只是一个基本的使用示例,实际的使用方式可能会根据你的需求而变化。例如,你可能需要从网络获取新的元素,而不是像这个例子中那样直接创建新的元素。
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@

## List 树状结构

通过 children 参数指定子树路径。

```swift
List(outlineModel, children: \.children) { i in
Label(i.title, systemImage: i.iconName)
}
```

## DisclosureGroup 实现展开和折叠

`DisclosureGroup` 视图可以用来创建一个可以展开和折叠的内容区域。以下是一个例子:

```swift
struct ContentView: View {
@State private var isExpanded = false

var body: some View {
DisclosureGroup("Options", isExpanded: $isExpanded) {
Text("Option 1")
Text("Option 2")
Text("Option 3")
}
}
}
```

在这个例子中,我们创建了一个 `DisclosureGroup` 视图,它的标题是 "Options",并且它包含三个选项。我们使用一个 `@State` 属性 `isExpanded` 来控制 `DisclosureGroup` 视图是否展开。当用户点击标题时,`DisclosureGroup` 视图会自动展开或折叠,同时 `isExpanded` 属性的值也会相应地改变。

## OutlineGroup 创建大纲视图

可以使用 `OutlineGroup` 视图来创建一个大纲视图。以下是一个例子:

```swift
struct ContentView: View {
var body: some View {
List {
OutlineGroup(sampleData, id: \.self) { item in
Text(item.name)
}
}
}
}

struct Item: Identifiable {
var id = UUID()
var name: String
var children: [Item]?
}

let sampleData: [Item] = [
Item(name: "Parent 1", children: [
Item(name: "Child 1"),
Item(name: "Child 2")
]),
Item(name: "Parent 2", children: [
Item(name: "Child 3"),
Item(name: "Child 4")
])
]
```

在这个例子中,我们创建了一个 `Item` 结构体,它有一个 `name` 属性和一个 `children` 属性。然后我们创建了一个 `sampleData` 数组,它包含两个父项,每个父项都有两个子项。最后我们在 `ContentView` 中使用 `OutlineGroup` 视图来显示这个数组,每个父项和子项都显示为一个文本视图。


## 结合 OutlineGroup 和 DisclosureGroup 实现自定义可折叠大纲视图

代码如下:
```swift
struct SPOutlineListView<D, Content>: View where D: RandomAccessCollection, D.Element: Identifiable, Content: View {
private let v: SPOutlineView<D, Content>

init(d: D, c: KeyPath<D.Element, D?>, content: @escaping (D.Element) -> Content) {
self.v = SPOutlineView(d: d, c: c, content: content)
}

var body: some View {
List {
v
}
}
}

struct SPOutlineView<D, Content>: View where D: RandomAccessCollection, D.Element: Identifiable, Content: View {
let d: D
let c: KeyPath<D.Element, D?>
let content: (D.Element) -> Content
@State var isExpanded = true // 控制初始是否展开的状态

var body: some View {
ForEach(d) { i in
if let sub = i[keyPath: c] {
SPDisclosureGroup(content: SPOutlineView(d: sub, c: c, content: content), label: content(i))
} else {
content(i)
} // end if
} // end ForEach
} // end body
}

struct SPDisclosureGroup<C, L>: View where C: View, L: View {
@State var isExpanded = false
var content: C
var label: L
var body: some View {
DisclosureGroup(isExpanded: $isExpanded) {
content
} label: {
Button {
withAnimation {
isExpanded.toggle()
}
} label: {
label
}
.buttonStyle(.plain)
}

}
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

使用 `.contentShape(Rectangle())` 可以使整个区域都可点击

```swift
struct ContentView: View {
var body: some View {
List {
ForEach(1..<50) { num in
HStack {
Text("\(num)")
Spacer()
}
.contentShape(Rectangle())
.onTapGesture {
print("Clicked \(num)")
}
}
} // end list
}
}
```
Loading

0 comments on commit 5a87761

Please sign in to comment.