import UIKit
class TasksViewController: UIViewController, UITableViewDataSource {
private var tasks: [String] = []
private let tableView = UITableView()
private let emptyStateView = UIView()
private let emptyImageView = UIImageView()
private let emptyTitleLabel = UILabel()
private let emptySubtitleLabel = UILabel()
private let addButton = UIButton(type: .system)
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
title = "Tasks List"
setupTableView()
setupEmptyStateView()
updateUI()
}
private func setupTableView() {
tableView.dataSource = self
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
private func setupEmptyStateView() {
emptyStateView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(emptyStateView)
NSLayoutConstraint.activate([
emptyStateView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
emptyStateView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
emptyStateView.leadingAnchor.constraint(greaterThanOrEqualTo: view.leadingAnchor, constant: 20),
emptyStateView.trailingAnchor.constraint(lessThanOrEqualTo: view.trailingAnchor, constant: -20)
])
emptyImageView.translatesAutoresizingMaskIntoConstraints = false
emptyImageView.image = UIImage(systemName: "doc.text")
emptyImageView.tintColor = .systemGray
emptyImageView.contentMode = .scaleAspectFit
emptyStateView.addSubview(emptyImageView)
emptyTitleLabel.translatesAutoresizingMaskIntoConstraints = false
emptyTitleLabel.text = "No tasks yet!"
emptyTitleLabel.font = UIFont.preferredFont(forTextStyle: .title2)
emptyTitleLabel.textAlignment = .center
emptyTitleLabel.textColor = .label
emptyStateView.addSubview(emptyTitleLabel)
emptySubtitleLabel.translatesAutoresizingMaskIntoConstraints = false
emptySubtitleLabel.text = "Tap the button below to add your first task."
emptySubtitleLabel.font = UIFont.preferredFont(forTextStyle: .body)
emptySubtitleLabel.textAlignment = .center
emptySubtitleLabel.textColor = .secondaryLabel
emptySubtitleLabel.numberOfLines = 0
emptyStateView.addSubview(emptySubtitleLabel)
addButton.translatesAutoresizingMaskIntoConstraints = false
addButton.setTitle("Add Task", for: .normal)
addButton.titleLabel?.font = UIFont.preferredFont(forTextStyle: .headline)
addButton.addTarget(self, action: #selector(addTaskTapped), for: .touchUpInside)
emptyStateView.addSubview(addButton)
NSLayoutConstraint.activate([
emptyImageView.centerXAnchor.constraint(equalTo: emptyStateView.centerXAnchor),
emptyImageView.topAnchor.constraint(equalTo: emptyStateView.topAnchor),
emptyImageView.widthAnchor.constraint(equalToConstant: 80),
emptyImageView.heightAnchor.constraint(equalToConstant: 80),
emptyTitleLabel.topAnchor.constraint(equalTo: emptyImageView.bottomAnchor, constant: 16),
emptyTitleLabel.leadingAnchor.constraint(equalTo: emptyStateView.leadingAnchor),
emptyTitleLabel.trailingAnchor.constraint(equalTo: emptyStateView.trailingAnchor),
emptySubtitleLabel.topAnchor.constraint(equalTo: emptyTitleLabel.bottomAnchor, constant: 8),
emptySubtitleLabel.leadingAnchor.constraint(equalTo: emptyStateView.leadingAnchor),
emptySubtitleLabel.trailingAnchor.constraint(equalTo: emptyStateView.trailingAnchor),
addButton.topAnchor.constraint(equalTo: emptySubtitleLabel.bottomAnchor, constant: 20),
addButton.centerXAnchor.constraint(equalTo: emptyStateView.centerXAnchor),
addButton.bottomAnchor.constraint(equalTo: emptyStateView.bottomAnchor)
])
}
private func updateUI() {
if tasks.isEmpty {
tableView.isHidden = true
emptyStateView.isHidden = false
} else {
tableView.isHidden = false
emptyStateView.isHidden = true
tableView.reloadData()
}
}
@objc private func addTaskTapped() {
let newTask = "Task \(tasks.count + 1)"
tasks.append(newTask)
updateUI()
}
// MARK: - UITableViewDataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tasks.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") ?? UITableViewCell(style: .default, reuseIdentifier: "cell")
cell.textLabel?.text = tasks[indexPath.row]
return cell
}
This solution uses UIKit to build a simple tasks list screen.
We create a UITableView to show tasks when the list is not empty.
We also create a custom empty state view with an icon, title, subtitle, and a button.
The updateUI() method switches between showing the table or the empty state depending on whether the tasks array is empty.
Tapping the 'Add Task' button adds a new task to the array and refreshes the UI to show the list.
All views use Auto Layout to center and size properly on all iPhone screens.