Skip to content

Commit 47eb675

Browse files
BBTableView adds refresh control
1 parent 3cf34e7 commit 47eb675

File tree

3 files changed

+80
-14
lines changed

3 files changed

+80
-14
lines changed

BBSwiftUIKit/BBSwiftUIKit/BBTableView.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,19 @@ public extension BBTableView {
3838
view._contentOffsetToScrollAnimated = contentOffsetToScrollAnimated
3939
return view
4040
}
41+
42+
func bb_setupRefreshControl(_ setupRefreshControl: @escaping (UIRefreshControl) -> Void) -> Self {
43+
var view = self
44+
view.setupRefreshControl = setupRefreshControl
45+
return view
46+
}
47+
48+
func bb_pullDownToRefresh(_ isRefreshing: Binding<Bool>, refresh: @escaping () -> Void) -> Self {
49+
var view = self
50+
view._isRefreshing = isRefreshing
51+
view.pullDownToRefresh = refresh
52+
return view
53+
}
4154
}
4255

4356
public struct BBTableViewScrollToRowParameter {
@@ -67,6 +80,10 @@ public struct BBTableView<Data, Content>: UIViewControllerRepresentable, BBUIScr
6780
public var alwaysBounceHorizontal: Bool
6881
public var showsVerticalScrollIndicator: Bool
6982
public var showsHorizontalScrollIndicator: Bool
83+
84+
@Binding public var isRefreshing: Bool
85+
public var setupRefreshControl: ((UIRefreshControl) -> Void)?
86+
public var pullDownToRefresh: (() -> Void)?
7087

7188
public init(_ data: Data,
7289
reloadData: Binding<Bool> = .constant(false),
@@ -80,6 +97,9 @@ public struct BBTableView<Data, Content>: UIViewControllerRepresentable, BBUIScr
8097
alwaysBounceHorizontal: Bool = false,
8198
showsVerticalScrollIndicator: Bool = true,
8299
showsHorizontalScrollIndicator: Bool = true,
100+
isRefreshing: Binding<Bool> = .constant(false),
101+
setupRefreshControl: ((UIRefreshControl) -> Void)? = nil,
102+
pullDownToRefresh: (() -> Void)? = nil,
83103
@ViewBuilder content: @escaping (Data.Element) -> Content)
84104
{
85105
self.data = data
@@ -95,6 +115,9 @@ public struct BBTableView<Data, Content>: UIViewControllerRepresentable, BBUIScr
95115
self.alwaysBounceHorizontal = alwaysBounceHorizontal
96116
self.showsVerticalScrollIndicator = showsVerticalScrollIndicator
97117
self.showsHorizontalScrollIndicator = showsHorizontalScrollIndicator
118+
self._isRefreshing = isRefreshing
119+
self.setupRefreshControl = setupRefreshControl
120+
self.pullDownToRefresh = pullDownToRefresh
98121
}
99122

100123
public func makeUIViewController(context: Context) -> UIViewController {
@@ -134,6 +157,15 @@ private class _BBTableViewController<Data, Content>: UIViewController, UITableVi
134157
tableView.dataSource = self
135158
tableView.delegate = self
136159
view.addSubview(tableView)
160+
161+
if representable.setupRefreshControl != nil || representable.pullDownToRefresh != nil {
162+
let refreshControl = UIRefreshControl()
163+
representable.setupRefreshControl?(refreshControl)
164+
refreshControl.addTarget(self, action: #selector(pullDownToRefresh), for: .valueChanged)
165+
tableView.refreshControl = refreshControl
166+
}
167+
168+
// TODO: Detect content offset to bottom space and load more data
137169

138170
NSLayoutConstraint.activate([
139171
view.leftAnchor.constraint(equalTo: tableView.leftAnchor),
@@ -183,6 +215,15 @@ private class _BBTableViewController<Data, Content>: UIViewController, UITableVi
183215
}
184216
}
185217

218+
if let refreshControl = tableView.refreshControl,
219+
representable.isRefreshing != refreshControl.isRefreshing {
220+
if representable.isRefreshing {
221+
refreshControl.beginRefreshing()
222+
} else {
223+
refreshControl.endRefreshing()
224+
}
225+
}
226+
186227
if let scrollToRow = representable.scrollToRow {
187228
tableView.scrollToRow(at: IndexPath(row: scrollToRow.row, section: 0), at: scrollToRow.position, animated: scrollToRow.animated)
188229
DispatchQueue.main.async { [weak self] in
@@ -200,6 +241,11 @@ private class _BBTableViewController<Data, Content>: UIViewController, UITableVi
200241
}
201242
}
202243

244+
@objc private func pullDownToRefresh() {
245+
representable.isRefreshing = true
246+
representable.pullDownToRefresh?()
247+
}
248+
203249
// MARK: UITableViewDataSource
204250

205251
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { data.count }

BBSwiftUIKitDemo/BBSwiftUIKitDemo/ContentView.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ struct ContentView: View {
3737
Text("Table view")
3838
}
3939
}
40+
.navigationBarTitle("", displayMode: .inline)
4041
}
4142
}
4243
}

BBSwiftUIKitDemo/BBSwiftUIKitDemo/TableViewExample.swift

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ struct TableViewExample: View {
1717
@State var scrollToRow: BBTableViewScrollToRowParameter? = nil
1818
@State var contentOffset: CGPoint = .zero
1919
@State var contentOffsetToScrollAnimated: CGPoint? = nil
20+
@State var isRefreshing: Bool = false
2021

2122
var body: some View {
2223
VStack {
@@ -40,6 +41,16 @@ struct TableViewExample: View {
4041
.bb_scrollToRow($scrollToRow)
4142
.bb_contentOffset($contentOffset)
4243
.bb_contentOffsetToScrollAnimated($contentOffsetToScrollAnimated)
44+
.bb_setupRefreshControl { refreshControl in
45+
refreshControl.tintColor = .blue
46+
refreshControl.attributedTitle = NSAttributedString(string: "Loading...", attributes: [.font: UIFont.systemFont(ofSize: 15), .foregroundColor: UIColor.blue])
47+
}
48+
.bb_pullDownToRefresh($isRefreshing) {
49+
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
50+
self.reloadListData()
51+
self.isRefreshing = false
52+
}
53+
}
4354

4455
Slider(value: $contentOffset.y, in: 0...1000)
4556

@@ -49,30 +60,38 @@ struct TableViewExample: View {
4960
.padding()
5061

5162
Button("Reload data") {
52-
if self.list.count > 50 {
53-
self.list = 0..<50
54-
} else {
55-
self.list = 0..<100
56-
}
57-
self.updateHeight.toggle()
58-
self.reloadData = true
63+
self.reloadListData()
5964
self.scrollToRow = BBTableViewScrollToRowParameter(row: 0, position: .top, animated: true)
6065
}
6166
.padding()
6267

6368
Button("Reload rows") {
64-
if self.list.count > 50 {
65-
self.list = 0..<50
66-
} else {
67-
self.list = 0..<100
68-
}
69-
self.updateHeight.toggle()
70-
self.reloadRows = (0..<10).map { $0 }
69+
self.reloadListRows()
7170
self.scrollToRow = BBTableViewScrollToRowParameter(row: 0, position: .top, animated: true)
7271
}
7372
.padding()
7473
}
7574
}
75+
76+
private func reloadListData() {
77+
if self.list.count > 50 {
78+
self.list = 0..<50
79+
} else {
80+
self.list = 0..<100
81+
}
82+
self.updateHeight.toggle()
83+
self.reloadData = true
84+
}
85+
86+
private func reloadListRows() {
87+
if self.list.count > 50 {
88+
self.list = 0..<50
89+
} else {
90+
self.list = 0..<100
91+
}
92+
self.updateHeight.toggle()
93+
self.reloadRows = (0..<10).map { $0 }
94+
}
7695
}
7796

7897
struct TableViewExample_Previews: PreviewProvider {

0 commit comments

Comments
 (0)