Skip to content

Shows how to use SwiftUI to wrap UITableView when you need greater control over the table and its events.

Notifications You must be signed in to change notification settings

peterent/CustomTableView

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 

Repository files navigation

CustomTableView

Shows how to use SwiftUI to wrap UITableView when you need greater control over the table and its events.

I started developing a new app using SwiftUI. For the most part, it works well, but there are definitely some gaps. You can find all kinds of examples appearing, probably daily, as people try out SwiftUI, and post their own findings and examples.

One of the things I need to do is present a list of data that comes from a remote server. All I really know about the data is that I should fetch it in batches (or chunks or pages). Until I fetch the first batch of data, I have no idea how large the data set will be. Sometimes its just 3 items, sometimes its over 3,000 items. Rather than fetching all of the records at once, I fetch them in batches and use the scrolling of the list to determine when to fetch the next batch.

Another thing I need to do is present multiple lists with a row of scrollable buttons to select a specific list. When a list becomes active, it immediately fetches its first batch of data if its empty; otherwise it waits for the list to scroll to fetch more.

One more thing I wanted to do, but could not, was fade a button in and out as the list was scrolled. This is something our Android version does quite well and I wanted the behavior to be the same. Unfortunately, SwiftUI's List does not provide any scrolling events. There are some suggestions about looking for a bottom row but I need to trigger an animation as the list is scrolling.

I was able to do the first two things reasonably well using the SwiftUI List component, but I ran into a performance problem when the list got large. Or specifically, when I switched between lists and made one list active. For the life of me, I cannot figure out why this would take a long time. I determined that the SwiftUI List was NOT trying to build all of the items, but whether or not those items were present certainly impacted the performace.

Having the need to monitor scrolling along with this performance problem, I decided to create my own SwiftUI wrapper for UITableView. I'm pretty sure the SwiftUI List is such a wrapper, but I don't need to be so generic.

This GIT repro is what I came up with as a prototype. The TableView is the wrapped UITableView and it uses a TableViewDataSource to supply the data to present. You also pass it something that conforms to the TableViewDelegate protocol which will provide feedback during scrolling, when a row is tapped, and so forth.

Using the delegate pattern is not very SwiftUI-like, but as I am still somewhat of a novice with SwiftUI, this was the most straightforward approach I could think of to accomplish my goals. I welcome anyone who can suggest changes to make this component feel more at home in the SwiftUI realm.

The cells in the table are subclasses of UITableViewCell and use a XIB for layout. You can do that in code of course, but I wanted to show how you can blend the old with the new in case you need to do that.

You can use the TableView like this:

TableView(
    dataSource: self.mutableData as TableViewDataSource, 
    delegate: self
)

This TableView is contained (look at the ContentView.swift file) within a VStack that's ultimately contained within a NavigationView. What you want to do when a row is tapped is activate a NavigationLink. I found a handy way to do this on StackOverflow.com:

NavigationLink(destination: DetailView(rowIndex: self.detailViewRow), isActive: self.$detailViewActive) {
    EmptyView()
}
.frame(width: 0, height: 0)
.disabled(true)
.hidden()

This NavigationLink is hidden on the screen and tapping on a row of the TableView causes the @State vars, detailViewRow and detailViewActive, to be changed, and trigger the NavigationLink.

Check out the TableView source file. It isn't that big and you can certainly find ways to customize how it works.

About

Shows how to use SwiftUI to wrap UITableView when you need greater control over the table and its events.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages