Two Tables, Sliding Views, And Harry Potter!

Have you ever been curious about draggable views with dynamic content? Have you ever wondered how you might work with two UITableViews on the same viewController? Do you really like Harry Potter?

If you answered yes to any of those questions, you have certainly found the right place!

Step 1: Set up your initial UITableView.
Step 2: Make a network call to retrieve your data.
Step 3: Create a UIView for your card view that you’ll slide up and down.
Step 4: Create a second table view and add it to the card view instance.
Step 5: Add the dragging functionality of the card.

I’m going to post a link to the project below, so I won’t be posting all of the code here, but I’ll note some important parts for each step.

https://github.com/BodhiMoosa/DisplayCardExample

Step 1: Set up your initial UITableView!

I don’t really have a lot to say here. Set it up!

Step 2: Make a network call to retrieve your data.

The network call here is also pretty straightforward.

Step 3: Create a UIView for your card view that you’ll slide up and down.

Ok, here we go. Something to comment on.

As you see in the setup, I have 3 subviews on this UIView.

  1. bodyView: this view is where the body of your content will sit. I give it 50 points on top to leave room for the top bar visual of the card we’re building.
  2. lineView: This is the grey line that you see on that top bar.
  3. grabView: This is a clear view that sits on top of the top 50 points of the view. I set this here so that you will have a defined region you can grab so that you can’t move the view from anywhere you want on the cardView.

The cornerRadius is set to give the expected look. The 50 point top bar section is important to note, as it’ll be necessary when we’re limiting just how high and low the view can be dragged before it stops.

Step 4: Create a second table view and add it to the card view instance.

When you create a second UITableView, you might be wondering how you manage it with UITableViewDelegate and UITableViewDatasource. It’s actually super easy, barely an inconvenience. Since you can verify identity, you just run a quick conditional, something like:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: CharacterCell.reuseID) as! CharacterCell
        if tableView == self.mainTableView {
            cell.set(title: data[indexPath.row].name, alignment: .center)
            if let character = character, character.name == data[indexPath.row].name {
                cell.label.textColor = .white
            } else {
                cell.label.textColor = .black
            }
        } else {
            cell.set(title: selectionOfData[indexPath.row], alignment: .left)
        }
        return cell
    }

In this example from the project, we’re checking to see which UITableView we’re working with and then acting accordingly.

So when you want to click on a cell within the main table, you set a didSelectCellAt method to check if it’s the main table and if so to change the data for the secondary table.

IMPORTANT: Don’t forget to set the delegate/datasource for both tables!

Step 5: Add the dragging functionality of the card.

I don’t want to take up too much space here essentially just rebuilding the code you see in the project, but here are some key points:

  1. you add the UIPanGestureRecognizer to the grabView on the cardView so that you can only grab that one section.
  2. You set the top/bottom points within viewDidLayoutSubviews so that you can account for the layout before doing the calculations (switch it up to viewDidLoad and you’ll see what I’m talking about).
  3. Make sure you set the sender parameter in the function handling the gesture (if you haven’t done something like this you might not have seen it included).
  4. When the action begins, we’re going to set a variable for the original frame of the moving UIView, this way we can compare it to the translation distance.
  5. We set the top point and bottom point here, barring the view from moving too high or too low. For me, I know how many cells are on this UITableView and I don’t want it to scroll taller than needed; however, this project shows you how to set these if needed so feel free to modify the functionality to meet your specific needs.
  6. When the view is released, it checks whether it had quickly dragged past the point it should have and if it did it will bounce back to the limit.