使用 Swift 在 tableview 中使用 headers 部分进行复制
Posted
技术标签:
【中文标题】使用 Swift 在 tableview 中使用 headers 部分进行复制【英文标题】:duplication using headers section in tableview using Swift 【发布时间】:2020-08-03 15:27:45 【问题描述】:好吧,每次用户完成任务时,我都会尝试将日期添加到我的标题部分。问题是标题部分有点新问题,由于某种原因,每次我在“完成”部分中添加两个以上的任务时,它似乎都会自我复制。
查看了 *** 并找不到我需要的东西,我希望你们能帮助我:) 这是有问题的应用程序的图片:https://imgur.com/wjVy9Uy
这是我的代码:
import Foundation
import CoreData
import UIKit
import SwipeCellKit
protocol TaskDelegate
func updateTaskName(name:String)
class TasksManViewController: UITableViewController, SwipeTableViewCellDelegate
@IBOutlet weak var Sege: UISegmentedControl!
var tasksArray = [Task]()
didSet
// because we perform this operation on the main thread, it is safe
DispatchQueue.main.async
self.tableView.reloadData()
let isSwipeRightEnabled = true
var delegate: TaskDelegate?
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
override func viewDidLoad()
override func viewWillAppear(_ animated: Bool)
loadTasks()
// MARK: - DataSource + Delegate Methods:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return tasksArray.count
override func numberOfSections(in tableView: UITableView) -> Int
return tasksArray.count
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "taskCellRow") as! SwipeTableViewCell
cell.delegate = self
cell.textLabel?.text = tasksArray[indexPath.row].title
return cell
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]?
if orientation == .left
guard isSwipeRightEnabled else return nil
let doneAction = SwipeAction(style: .destructive, title: "Done") (action, indexPath) in
//STEP1: Append the task to the doneTasksArr:
self.tasksArray[indexPath.row].isDone = true
//STEP3: Remove the Row:
self.tasksArray.remove(at: indexPath.row)
//STEP4: Update the Model:
self.saveTasks()
self.delegate?.updateTaskName(name: "")
self.tableView.reloadData()
let unDoneAction = SwipeAction(style: .destructive, title: "Undone") (unDoneAction, indexPath) in
self.tasksArray[indexPath.row].isDone = false
self.tasksArray.remove(at: indexPath.row)
self.saveTasks()
//configure btn:
doneAction.backgroundColor = .cyan
unDoneAction.backgroundColor = .blue
if Sege.selectedSegmentIndex == 0 //Doing this to allow the user to unDone tasks.
return [doneAction]
else return [unDoneAction]
else
let deleteAction = SwipeAction(style: .destructive, title: "Delete") action, indexPath in
self.context.delete(self.tasksArray[indexPath.row])
self.tasksArray.remove(at: indexPath.row)
self.saveTasks()
self.delegate?.updateTaskName(name: "")
self.tableView.reloadData()
return [deleteAction]
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
tableView.deselectRow(at: indexPath, animated: true)
// MARK: - Class Methods:
@IBAction func addBtnTapped(_ sender: UIBarButtonItem)
Sege.selectedSegmentIndex = 0 // Doing this to avoid the user to insert a task into the DoneTasks by mistake! and avoiad a bug :)
insertNewTask()
func insertNewTask()
var textField = UITextField()
let alert = UIAlertController(title: "New Task", message: "Please Add Your Task", preferredStyle: .alert)
alert.addTextField (alertTextField) in
alertTextField.placeholder = "Create New Task"
textField = alertTextField
let action = UIAlertAction(title: "Add", style: .default) (action) in
let newItem = Task(context: self.context)
newItem.title = textField.text!
newItem.isDone = false
newItem.date = Date()
self.tasksArray.append(newItem)
self.delegate?.updateTaskName(name: newItem.title!)
self.saveTasks()
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
// MARK: - Sege Section:
@IBAction func segeControlTapped(_ sender: UISegmentedControl)
switch Sege.selectedSegmentIndex
case 0:
//Loading normal tasks whose are not done
loadTasks()
case 1:
//Loading the doneTasks:
loadDoneTasksFrom()
default:
print("There's something wrong with Sege!")
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
let completedTasksToDisply = 0
if Sege.selectedSegmentIndex == 1
if let firstTask = tasksArray[section].date
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/MM/yyyy"
let dateString = dateFormatter.string(from: firstTask)
return " " + dateString + " " + " " + "Completed Tasks: \(completedTasksToDisply)"
return ""
override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int)
let header: UITableViewHeaderFooterView = view as! UITableViewHeaderFooterView
header.textLabel?.font = UIFont(name: "Verdana", size: 13.0)
header.textLabel?.textAlignment = NSTextAlignment.center
//MARK: - Model Manipulation Methods:
func saveTasks()
do
try! context.save()
catch let err
print("Error Saving context \(err)")
func loadTasks()
let request: NSFetchRequest<Task> = Task.fetchRequest()
request.predicate = NSPredicate(format: "isDone == %@", NSNumber(value: false))
request.sortDescriptors = [NSSortDescriptor(key: "isDone", ascending: false)]
do
tasksArray = try! context.fetch(request)
catch
print("There was an error with loading items \(error)")
tableView.reloadData()
func loadDoneTasksFrom()
let request:NSFetchRequest<Task> = Task.fetchRequest()
request.predicate = NSPredicate(format: "isDone == %@", NSNumber(value: true))
request.sortDescriptors = [NSSortDescriptor(key: "isDone", ascending: false)]
do
tasksArray = try context.fetch(request)
catch
print("Error fetching data from context\(error)")
tableView.reloadData()
【问题讨论】:
在tableView(_ tableView:titleForHeaderInSection:)
中你不应该测试你在哪个部分而不是Sege
?
您有一个一维数据源数组,您将返回 numberOfRowsInSection
和 numberOfSections
中的项目数。这行不通。对于部分,您需要一个二维数组或 - 最好 - 一个 Section
结构。并且数据源数组的didSet
属性观察器不是一个好习惯。
@vadian 哦 :\ 我的错,会解决这个问题。你我会尝试更多地了解这一点。
【参考方案1】:
编辑:好的,我知道您要做什么。试一试——我们需要一个双精度数组——里面的每个数组都必须按日期分割——我们的查询看起来像这样:
var tasksArray = [[Task]]()
var sectionDates = [String]()
func loadTasks()
tasksArray.removeAll(keepingCapacity: false)
sectionDates.removeAll(keepingCapacity: false)
let request: NSFetchRequest<Task> = Task.fetchRequest()
request.predicate = NSPredicate(format: "isDone == %@", NSNumber(value: false))
request.sortDescriptors = [NSSortDescriptor(key: "isDone", ascending: false)]
do
let tasks = try! context.fetch(request)
for task in tasks
if let taskDate = task.date
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/MM/yyyy"
let dateString = dateFormatter.string(from: taskDate)
if self.sectionDates.contains(dateString)
if let section = self.sectionDates.firstIndex(of: dateString)
self.tasksArray[section].append(task)
else
self.sectionDates.append(dateString)
// EDIT - ADD THIS LINE (and self. where necessary)
self.tasksArray.append([])
if let section = self.sectionDates.firstIndex(of: dateString)
self.tasksArray[section].append(task)
catch
print("There was an error with loading items \(error)")
tableView.reloadData()
按顺序加载对象也可能会有所帮助,但通过此设置,无论顺序如何,它仍应正确分组所有内容 - 除非您希望您的部分按特定顺序排列,否则您可以在查询中指定
现在更改您的 tableView 委托方法
override func numberOfSections(in tableView: UITableView) -> Int
return sectionDates.count
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return tasksArray[section].count
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "taskCellRow") as! SwipeTableViewCell
cell.delegate = self
cell.textLabel?.text = tasksArray[indexPath.section][indexPath.row].title
return cell
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
let completedTasksToDisply = 0
if Sege.selectedSegmentIndex == 1
let dateString = sectionDates[section]
return " " + dateString + " " + " " + "Completed Tasks: \(completedTasksToDisply)"
return ""
我想我会将其余的 tableView 委托方法留给您,但在大多数情况下,我们只需要在使用双精度数组时识别 indexPath 行之前的部分 - 就像我们在 cellForRow 中所做的那样
我运行了这段代码,结果如下:
【讨论】:
@robots 首先非常感谢您的回答,其次您有任何提示可以引导我做我愿意做的事情吗? :) 我有点卡住了,因为当我不需要它时,我很难做一个二维数组:\ 我不确定我是否理解这个问题。你想完成什么? @robots 基本上我想要完成的是能够根据已完成的任务将日期插入标题中,例如,如果我今天已经完成了 3 个任务,那么它将在日期标题下组合在一起。 好的,我现在明白了。检查更新的答案。它应该可以帮助您朝着正确的方向前进 对不起,我正在度假——我运行了代码,但遗漏了一行:taskArray.append([])——我会更新我的答案以上是关于使用 Swift 在 tableview 中使用 headers 部分进行复制的主要内容,如果未能解决你的问题,请参考以下文章
在 tableView Swift 中使用 javascript 数据
Swift - 在 TableView 单元中使用步进器增加标签
在 Swift 中使用远程 JSON 数据填充 tableView