61

I'm trying to implement a table view with scrollable horizontal items (with unknown number of items) like the illustration below:

enter image description here

The UI should behave like so:

  1. At the init state the table cell shows a label and some text and the circle item pops out of the right side
  2. If the users swipes from right to left, the label and text fades out and the horizontal list (inside the cell) takes it's place

I thought about using TableView and dequeueReusableCellWithIdentifier and creating a prototype cell, but then I need to remember the list horizontal position and init the cell properly on cellForRowAtIndexPath and that will probably affect performance.

Q: What layout would you use in order to achieve this goal, any input / tutorial would be appreciated

jzeferino
  • 7,700
  • 1
  • 39
  • 59
Shlomi Schwartz
  • 8,693
  • 29
  • 109
  • 186
  • 1
    You should use `UITableView`, with reusable cells, and with a `UIScrollView` as the sideways scroller. You can store the values of horizontal position and retrieve them when the cell is init'd in `cellForRowAtIndexPath`. Retrieving a value for a dictionary storing the horizontal position should be trivial in `cellForRowAtIndexPath`. – Andrew Robinson Jan 08 '15 at 17:56
  • nicely illustrated for immediate clarity! – mobibob Sep 16 '15 at 15:17

4 Answers4

60

Use a UITableView and add a UICollectionView to your reusable tableView cell. UICollectionView works similar to UITableView in that the "items" (like cells) are reusable and instantiated only when they will appear on screen. I did a quick google search for tutorials and found UICollectionView in UITableViewCell. Check that out and a few other StackOverflow questions regarding design and you should be golden.

Andrew Robinson
  • 3,404
  • 3
  • 20
  • 26
6

Using UIScrollView may require heavy effort if there are large amount of UI elements inside each scrollview because you have to instantiate all those upfront. A better solution is to define your custom UITableViewCell which has its own UITableView but rotated in 90 degree for horizontal scrolling. UI elements inside will be created only when they need to be shown by using dequeueReusableCellWithIdentifier:forIndexPath:. Please see some sample code on how to create a 90 degree rotated table view:

iPhone Tableview Use Cells in Horizontal Scrolling not Vertical

Milad Faridnia
  • 9,113
  • 13
  • 65
  • 78
Xiaojun
  • 833
  • 6
  • 4
  • 14
    Why in the world would you rotate a tableView instead of using a `UICollectionView` that's designed to scroll sideways? – Andrew Robinson Jan 09 '15 at 16:17
  • Is there any hidden advantage in using rotated `UITableView` than using `UICollectionView`? – Joe Huang Jan 18 '16 at 01:48
  • @AndrewRobinson Because collection views are complicated to size, especially when inside a table view cell. A horizontal table view would simplify things a lot if you only needed one row. – Eric Mar 06 '23 at 23:20
3

You can use a ScrollView to put inside your tableview and set the values "Direction lock enabled" and "Paging Enabled" to true for the scrollview.

Calc91
  • 124
  • 2
  • Cool I will try that, but can you elaborate a bit about those properties? – Shlomi Schwartz Jan 08 '15 at 17:54
  • If using UIScrollView, what are the limitations regarding the number of items in each row? – Shlomi Schwartz Jan 08 '15 at 17:55
  • 1
    @ShlomiSchwartz, `UIScrollView` also uses a prototype / reusable cell pattern. There wouldn't be # of items in a row limitations, unless enforced by you. [UIScrollView Class Reference](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIScrollView_Class/index.html) – Andrew Robinson Jan 08 '15 at 18:01
  • @AndrewRobinson, thanks for the reply ... however I could not find the reusable cell property / function in the docs, could you please be more specific? – Shlomi Schwartz Jan 09 '15 at 09:52
  • I wish I wasn't on my phone when I replied to this, it's definitely not a `UIScrollView` that you want, it's a `UICollectionView`. – Andrew Robinson Jan 09 '15 at 16:16
2

- SwiftUI

In swiftUI, you can use the power of Stacks and ScrollView alongside with List (if you want):

struct ContentView: View {

    var verticalData = 0...3
    var horizontalData = 0...15

    var body: some View {
        List(self.verticalData, id: \.self) { vData in
            ScrollView(.horizontal) {
                HStack(spacing: 16) {
                    ForEach(self.horizontalData, id: \.self) { _ in
                        Circle()
                            .foregroundColor(.blue)
                            .frame(width: 40, height: 40, alignment: .center)
                    }
                }
            }
        }
    }
}

In this example I used a List for vertical data and a horizontal ScrollView containing a HStack (Horizonl stack) of circles.

- Example

The following code is the the only code to reproduce a view exactly like your illustration (4 years later on iPhone Xs):

struct CircleView: View {
    var body: some View {
        Circle()
        .foregroundColor(.blue)
        .frame(width: 80, height: 80, alignment: .center)
    }
}

struct RowView: View {
    var body: some View {
        ScrollView(.horizontal) {
            HStack(spacing: 16) {
                VStack(alignment: .leading, spacing: 4) {
                    Text("Label")
                    Text("Some text here")
                }
                ForEach(0...15, id: \.self) { _ in
                    CircleView()
                }
            }
            .padding(16)
        }
    }
}

struct ContentView: View {

    var body: some View {
        List {
            ForEach(0...3, id: \.self) { _ in
                RowView()
            }.listRowInsets(EdgeInsets())
        }
    }
}

- Result

enter image description here

Mojtaba Hosseini
  • 95,414
  • 31
  • 268
  • 278
  • Performance is not acceptable if you try this. It's fine if you have a handful of items. the entire point of collection views (including scroll views) is that performance is incredibly better than a static scroll of items. – Fattie Feb 09 '20 at 11:31