tidi

178 阅读7分钟

当然,我们可以纯粹使用Swift和UIKit来创建一个简单的To-do List应用程序。这里是一个简单的包含UI和逻辑的示例。

首先,你需要在Xcode中创建一个新的项目,选择App并命名为TodoList_SwiftUIKit。

以下是一些关键代码片段:

1.定义ToDo的数据模型

struct ToDo {
    var title: String
    var isComplete: Bool
}

2.创建ToDo列表视图控制器(TableViewController)

import UIKit

class ToDoListViewController: UITableViewController {

    // 初始化一个空的待办事项数组
    var toDoItems: [ToDo] = []

  override func viewDidLoad() {
        super.viewDidLoad()
        
        // 设置标题
        self.title = "To-Do List"
        
        // 添加导航按钮
        navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addTodo))
    }
    
    // 添加待办事项的操作
    @objc private func addTodo() {
      // 这是一个弹窗视图,用于获取用户输入的待办事项名称,然后将其添加到待办事项数组中
      let alertController = UIAlertController(title: "Add Todo", message: nil, preferredStyle: .alert)
      alertController.addTextField()

      let addAction = UIAlertAction(title: "Add", style: .default) { _ in
          guard 
            let text = alertController.textFields?.first?.text,
            !text.isEmpty 
            else { return }

          self.toDoItems.append(ToDo(title: text, isComplete: false))
          self.tableView.reloadData()
      }
        alertController.addAction(addAction)

        present(alertController, animated: true)
    }
}

这段代码是在使用iOS开发中的UIAlertControllerUIAlertAction来创建一个弹出对话框,并添加一个名为"Add"的操作按钮。

首先,创建了一个带有标题“Add”和默认样式(.default)的UI警告操作。该操作会在用户点击“Add”按钮时触发。

当用户点击“Add”按钮时,代码块 { _ in ... } 会执行。此处的 _ in 表示这个闭包忽略了传入的参数(在这种情况下,该参数将是触发该操作的UIAlertAction实例)。

接下来是一个 guard 语句,它用于提前退出函数或闭包,避免进一步的嵌套。let text = alertController.textFields?.first?.text 尝试从弹出框的第一个文本字段获取文本。如果无法获取文本或文本为空( !text.isEmpty 为假),则 guard 语句就会触发,立即退出闭包,剩下的代码不会执行。

如果能够成功获取非空的文本,那么 self.toDoItems.append(ToDo(title: text, isComplete: false)) 就会被执行,它创建一个新的 ToDo 对象并将其添加到 toDoItems 数组中。每个 ToDo 对象都有一个标题(用户输入的文本)和一个标记是否完成的布尔值(在这种情况下始终为 false)。

最后,self.tableView.reloadData() 被调用以刷新表视图,显示新添加的待办事项。

总的来说,这段代码主要用于创建一个弹出对话框,允许用户输入新的待办事项,然后将新的待办事项添加到列表中,并刷新表格以显示新的待办事项。

3.实现UITableViewDataSource方法:

extension ToDoListViewController {
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return toDoItems.count
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell") ?? UITableViewCell(style: .default, reuseIdentifier: "cell")
        
        let item = toDoItems[indexPath.row]
        cell.textLabel?.text = item.title
        cell.accessoryType = item.isComplete ? .checkmark : .none
        
        return cell
    }
}

4.实现UITableViewDelegate方法:

extension ToDoListViewController {
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        
        // 更新待办事项的完成状态
        toDoItems[indexPath.row].isComplete.toggle()
        tableView.reloadRows(at: [indexPath], with: .automatic)
    }
}

以上代码就已经实现了一个基本的ToDo列表。但是这个应用还很简单,你可能希望添加如下功能:

  • 删除待办事项
  • 编辑待办事项
  • 持久化存储待办事项
  • 分类待办事项

以上提供的代码仅供参考,具体实现会根据你对应用的需求不同而有所差异。

以下是你可以添加到在上面的基本ToDo列表中来实现删除,编辑,持久化存储和分类待办事项功能。我们会使用UserDefaults进行简单的持久化存储,实际项目开发中可能会需要更复杂的数据库系统。

1.删除待办事项

在UITableViewDelegate扩展中添加以下方法:

override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
    if editingStyle == .delete {
        toDoItems.remove(at: indexPath.row)
        // 持久化存储删除操作
        saveData()
        tableView.deleteRows(at: [indexPath], with: .fade)
    }
}

2.编辑待办事项

可以在didSelectRowAt方法中添加代码以处理编辑动作:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath, animated: true)

    let alertController = UIAlertController(title: "Edit Todo", message: nil, preferredStyle: .alert)
    alertController.addTextField { textField in
        textField.text = self.toDoItems[indexPath.row].title
    }

    let editAction = UIAlertAction(title: "Edit", style: .default) { _ in
        guard 
            let text = alertController.textFields?.first?.text,
            !text.isEmpty 
        else { return }

        self.toDoItems[indexPath.row].title = text
        // 持久化存储编辑操作
        self.saveData()
        tableView.reloadRows(at: [indexPath], with: .automatic)
    }
    alertController.addAction(editAction)

    present(alertController, animated: true)
}

3.持久化存储

可以使用UserDefaults存储待办事项。由于UserDefaults无法直接存储自定义类型,我们需要将待办事项转换为可以被UserDefaults存储的类型。同时,我们也需要在应用启动时从UserDefaults载入数据。

在ToDoListViewController类中添加以下方法:

private func saveData() {
    let data = try? JSONEncoder().encode(toDoItems)
    UserDefaults.standard.set(data, forKey: "toDoItems")
}

private func loadData() {
    guard 
        let data = UserDefaults.standard.data(forKey: "toDoItems"),
        let items = try? JSONDecoder().decode([ToDo].self, from: data) 
    else { return }
    
    toDoItems = items
}

然后在viewDidLoad方法中调用loadData()以载入数据,并在addTodo和tableView(_:commit:forRowAt:)方法中调用saveData()以保存数据。

4.分类待办事项

这个需求较为复杂,可能需要重新设计数据模型和UI。例如,可以将ToDo结构体修改为:

struct ToDo {
    var title: String
    var isComplete: Bool
    var category: String
}

并在addTodo方法中添加代码以获取用户输入的分类。

同时,你可能需要一个新的TableView或者CollectionView来显示不同分类的待办事项,具体实现会根据你对UI和交互设计的要求有所不同。

以上代码仅供参考,完整的实现需要你自己根据实际需求进行适当的修改和扩展。

要实现分类待办事项,我们需要增加一个新的表格视图控制器(CategoryTableViewController)来展示所有的类别。然后在每个类别内部,都可以跳转到相应的待办列表。

首先,我们将ToDo结构体修改为:

struct ToDo {
    var title: String
    var isComplete: Bool
    var category: String
}

然后在ToDoListViewController中添加以下代码,用于初始化显示特定类别的待办事项:

var categoryName: String?

override func viewDidLoad() {
    super.viewDidLoad()

    // 设置标题为当前类别名称
    self.title = categoryName

    // 其他代码...
}

// 修改数据源方法,只显示当前类别的待办事项
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return toDoItems.filter { $0.category == categoryName }.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell") ?? UITableViewCell(style: .default, reuseIdentifier: "cell")

    let item = toDoItems.filter { $0.category == categoryName }[indexPath.row]
    cell.textLabel?.text = item.title
    cell.accessoryType = item.isComplete ? .checkmark : .none

    return cell
}

接着创建一个新的CategoryTableViewController,用于显示所有的待办事项类别:

import UIKit

class CategoryTableViewController: UITableViewController {

    // 存储所有的类别名称
    var categories: [String] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        self.title = "Categories"
        
        // 添加导航按钮
        navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addCategory))
    }
    
    @objc private func addCategory() {
        // 与添加待办事项类似,弹出对话框让用户输入新的类别名称,并存储起来
    }
}

extension CategoryTableViewController {
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return categories.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell") ?? UITableViewCell(style: .default, reuseIdentifier: "cell")
        
        cell.textLabel?.text = categories[indexPath.row]

        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)

        // 当用户选择一个类别时,进入该类别的待办事项列表
        let todoListViewController = ToDoListViewController()
        todoListViewController.categoryName = categories[indexPath.row]
        navigationController?.pushViewController(todoListViewController, animated: true)
    }
}

请注意这是一个基本的实现,你可能需要根据具体需求进行修改和扩展,例如添加删除类别功能,或者使用更复杂的数据持久化方案以处理大量数据。

CategoryTableViewController中实现添加和删除类别功能,具体步骤如下:

1.添加类别

@objc private func addCategory() {
    let alertController = UIAlertController(title: "Add Category", message: nil, preferredStyle: .alert)
    alertController.addTextField()
    
    let addAction = UIAlertAction(title: "Add", style: .default) { _ in
        guard 
            let text = alertController.textFields?.first?.text,
            !text.isEmpty 
            else { return }
        
        self.categories.append(text)
        // 持久化存储添加操作
        self.saveData()
        self.tableView.reloadData()
    }
    alertController.addAction(addAction)
    
    present(alertController, animated: true)
}

2.删除类别

可以使用.delete编辑风格在滑动单元格时显示删除按钮。在UITableViewDelegate扩展中添加以下代码:

override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
    if editingStyle == .delete {
        // 删除类别前需检查是否存在属于该类别的待办事项
        let category = categories[indexPath.row]
        if !toDoItems.contains(where: { $0.category == category }) {
            categories.remove(at: indexPath.row)
            // 持久化存储删除操作
            saveData()
            tableView.deleteRows(at: [indexPath], with: .fade)
        } else {
            let alert = UIAlertController(title: "Warning", message: "This category contains to-do items. Please delete them first.", preferredStyle: .alert)
            let okAction = UIAlertAction(title: "OK", style: .default)
            alert.addAction(okAction)
            present(alert, animated: true)
        }
    }
}

3.持久化存储

使用UserDefaults存储类别列表。同样由于UserDefaults无法直接存储自定义类型,我们需要将待办事项转换为可以被UserDefaults存储的类型。同时,我们也需要在应用启动时从UserDefaults载入数据。

CategoryTableViewController类中添加以下方法:

private func saveData() {
    UserDefaults.standard.set(categories, forKey: "categories")
}

private func loadData() {
    if let items = UserDefaults.standard.array(forKey: "categories") as? [String] {
        categories = items
    }
}

然后在viewDidLoad方法中调用loadData()以载入数据,并在addCategorytableView(_:commit:forRowAt:)方法中调用saveData()以保存数据。

以上就是添加和删除类别功能的基本实现,你可能还需要根据具体需求进行修改和扩展。