我有一个显示药丸的主tableView控制器,它有一个添加按钮,可以连接到静态tableView。所有药丸数据都保存在核心数据中。我希望向左滑动单元格以返回到所选单元格的静态表进行编辑。
我的主故事板的图像 https://ibb.co/6PhfvfB
我的主TableView
class HomeViewController: UITableViewController {
//MARK:- Properties
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
// All Pills array
var pillsArray: [Pill] = []
override func viewWillAppear(_ animated: Bool) {
//reload table rows
tableView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
// Set the interface color of User
overrideUserInterfaceStyle = .light
// Find user directory path for Core Data
let dataFilePath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
print(dataFilePath)
// Load pillsArray
loadPills()
// Add title to Nav Controller
let titleLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 30))
// titleLabel.textColor = UIColor.lightGray
titleLabel.text = "Add Pills"
titleLabel.textAlignment = .center
titleLabel.font = UIFont(name: "Baskerville-Bold", size: 30)
navigationItem.titleView = titleLabel
// Register Cell
self.registerCell()
}
//MARK:- TableView Datasource Methods
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Add Label if the table View is Empty
if pillsArray.count == 0 {
let homeLabel = UILabel(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height))
homeLabel.text = "Tap '+' to add Pill"
homeLabel.textAlignment = NSTextAlignment.center
tableView.backgroundView = homeLabel
tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
return 0
} else {
tableView.backgroundView = nil
return pillsArray.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Create Cell
guard let cell = tableView.dequeueReusableCell(withIdentifier: "ReminderCell", for: indexPath) as? PillTableViewCell else {
fatalError("Could not register cell with identifier ReminderCell")
}
let singlePill = pillsArray[indexPath.row]
cell.pillNameCell.text = singlePill.pillName
cell.instructionsCell.text = singlePill.pillInstruction
cell.pillTimerCell.text = singlePill.pillStartTimer
if let pillCountLabelText = singlePill.pillsCount {
cell.pillsLeft.text = pillCountLabelText
}
// cell.pillImageView.backgroundColor = singlePill.pillColor
// Add color to pill taken img (ternary operation)
cell.doneImageView.backgroundColor = singlePill.pillTaken ? .green : .red
return cell
}
//MARK:- TableView Delegate Methods
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Delete pill from context and tableView
// context.delete(pillsArray[indexPath.row])
// pillsArray.remove(at: indexPath.row)
// Toggle pill taken when selected
// pillsArray[indexPath.row].pillTaken = !pillsArray[indexPath.row].pillTaken
savePillsTaken()
tableView.deselectRow(at: indexPath, animated: true)
}
// Left Swipe Actions (Take and Edit)
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
// Write action code for Take a Pill
let pillTakenAction = UIContextualAction(style: .normal, title: "Done") { (UIContextualAction, UIView, boolValue) in
// Toggle pill taken when selected
self.pillsArray[indexPath.row].pillTaken = !self.pillsArray[indexPath.row].pillTaken
// Update pill count on the cell
guard let pillCountText = self.pillsArray[indexPath.row].pillsCount else {
return
}
guard let selectedDosageText = self.pillsArray[indexPath.row].selectedDosage else {
return
}
let pillCountInt = Int(pillCountText) ?? 0
let selectedDosageInt = Int(selectedDosageText) ?? 0
if pillCountInt > 0 {
self.pillsArray[indexPath.row].pillsCount = String(pillCountInt - selectedDosageInt)
}
self.savePillsTaken()
boolValue(true)
}
pillTakenAction.backgroundColor = .green
let editPillAction = UIContextualAction(style: .normal, title: "Edit") { (UIContextualAction, UIView, boolValue) in
print("Edit pill")
boolValue(true)
}
editPillAction.backgroundColor = .gray
let actionSwipes = UISwipeActionsConfiguration(actions: [pillTakenAction, editPillAction])
return actionSwipes
}
// Right Swipe Action
override func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
// Write action code for deleting a Pill
let trashAction = UIContextualAction(style: .normal, title: "Delete") { (UIContextualAction, UIView, boolValue) in
// Delete Pill from context and tableView
self.context.delete(self.pillsArray[indexPath.row])
self.pillsArray.remove(at: indexPath.row)
self.savePillsTaken()
boolValue(true)
}
trashAction.backgroundColor = .red
let actionSwipes = UISwipeActionsConfiguration(actions: [trashAction])
return actionSwipes
}
//MARK:- PillCell own methods
func registerCell() {
let pillCell = UINib(nibName: "PillTableViewCell", bundle: nil)
self.tableView.register(pillCell, forCellReuseIdentifier: "ReminderCell")
}
//MARK:- Actions and Segue Methods
@IBAction func saveButtonPressed(segue: UIStoryboardSegue) {
}
func savePillsTaken() {
do {
try context.save()
} catch {
print("Error saving pillsTaken in context, \(error)")
}
tableView.reloadData()
}
func loadPills() {
let request : NSFetchRequest<Pill> = Pill.fetchRequest()
do {
pillsArray = try context.fetch(request)
} catch {
print("Error fetching data from context \(error)")
}
}
}
我的用于添加药丸到核心数据的静态tableView
class PillViewController: UITableViewController, UITextFieldDelegate, UIPickerViewDelegate, UIPickerViewDataSource {
//MARK:- Outlets
@IBOutlet var saveButtonOutlet: UIBarButtonItem!
@IBOutlet var nameTextField: UITextField!
@IBOutlet var doseTextField: UITextField!
@IBOutlet var typeTextField: UITextField!
@IBOutlet var instructionsTextField: UITextField!
@IBOutlet var startDateTextField: UITextField!
@IBOutlet var intakeTextField: UITextField!
@IBOutlet var colorOrImageTextField: UITextField!
@IBOutlet var pillsCountTextField: UITextField!
//MARK:- Properties
// Selected options
var selectedPillType: String?
var selectedIntake: String?
var userSelectedTimeStart: String?
var userSelectedDateStart: String?
var pillsCount: String?
var selectedNotificationDate: Date?
// Static options
var pillTypes = ["Taps", "Pills", "g", "mg", "mcg"]
var intake = ["1 Times a Day", "2 Times a Day", "3 Times a Day", "4 Times a Day"]
var pillColors : [(colorName: String, color: UIColor)] = [("Red", .red), ("Orange", .orange), ("Magenta", .magenta)]
// Create a new pill NSManagedObject
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
private var datePicker: UIDatePicker?
override func viewDidLoad() {
super.viewDidLoad()
// Set the interface color of User
overrideUserInterfaceStyle = .light
// Check if Required TextFields are not Empty
checkIfTextFieldIsNotEmpty()
// Create PickerViews for a textField
createPickerView(for: [typeTextField, intakeTextField, colorOrImageTextField])
// Create datePickerView for a textField
createDatePicker(for: startDateTextField)
// Add toolbar to textFields
dissmissPickerView(for: [typeTextField, intakeTextField, colorOrImageTextField, startDateTextField, nameTextField, instructionsTextField, pillsCountTextField])
}
//MARK: - TableView Delegate Methods
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
//MARK:- UIPickerView data source and delegate methods
// Number of sections
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
// Number of dropdown items
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if typeTextField.isFirstResponder {
return pillTypes.count
} else if intakeTextField.isFirstResponder {
return intake.count
} else if colorOrImageTextField.isFirstResponder {
return pillColors.count
}
return 1
}
// Dropdown items
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if typeTextField.isFirstResponder {
return pillTypes[row]
} else if intakeTextField.isFirstResponder {
return intake[row]
} else if colorOrImageTextField.isFirstResponder {
return pillColors[row].colorName
}
return ""
}
// Selected item
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if typeTextField.isFirstResponder {
selectedPillType = pillTypes[row]
typeTextField.text = selectedPillType
} else if intakeTextField.isFirstResponder {
selectedIntake = intake[row]
intakeTextField.text = selectedIntake
} else if colorOrImageTextField.isFirstResponder {
// pill.selectedColorString = Pill.pillColors[row].colorName
// pill.selectedColor = Pill.pillColors[row].color
//
// colorOrImageTextField.text = pill.selectedColorString
// colorOrImageTextField.textColor = pill.selectedColor
}
}
//MARK:- PickerView own methods
func createPickerView(for textFields: [UITextField]) {
for textField in textFields {
let pickerView = UIPickerView()
pickerView.delegate = self
textField.inputView = pickerView
}
}
func dissmissPickerView(for textFields: [UITextField]) {
let toolBar: UIToolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: 320, height: 50))
toolBar.sizeToFit()
let button = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(self.action))
toolBar.setItems([button], animated: true)
toolBar.isUserInteractionEnabled = true
for textField in textFields {
textField.inputAccessoryView = toolBar
}
}
@objc func action() {
view.endEditing(true)
}
//MARK:- Own DatePickerView methods
func createDatePicker(for textField: UITextField) {
datePicker = UIDatePicker()
datePicker?.datePickerMode = .dateAndTime
let minDatePicker = Date()
datePicker?.minimumDate = minDatePicker
textField.inputView = datePicker
datePicker?.addTarget(self, action: #selector(dateChanged(datePicker:)), for: .valueChanged)
}
@objc func dateChanged(datePicker: UIDatePicker) {
// Format date
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM d, yyyy, h:mm a"
if startDateTextField.isFirstResponder {
self.startDateTextField.text = dateFormatter.string(from: datePicker.date)
guard let startTimeText = self.startDateTextField.text else { return }
// Create notification Date
selectedNotificationDate = dateFormatter.date(from: startTimeText)
// Create time and date substring
userSelectedTimeStart = self.createSubstring(for: startTimeText).time
userSelectedDateStart = self.createSubstring(for: startTimeText).date
}
}
//MARK:- My own methods
func checkIfTextFieldIsNotEmpty() {
saveButtonOutlet.isEnabled = false
nameTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
doseTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
startDateTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingDidEnd)
tableView.reloadData()
}
@objc func textFieldDidChange(_ textField: UITextField) {
guard let nameText = nameTextField.text, let dosageText = doseTextField.text, let startDateText = startDateTextField.text else { return }
if !nameText.isEmpty && !dosageText.isEmpty && !startDateText.isEmpty {
saveButtonOutlet.isEnabled = true
} else {
saveButtonOutlet.isEnabled = false
}
}
func createSubstring(for dateFullString: String) -> (time: String, date: String) {
let timeString = String(dateFullString.suffix(8))
let dateString = String(dateFullString.prefix(12))
return (timeString, dateString)
}
//MARK:- Segue Actions
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let pill = Pill(context: context)
// Set pill taken
pill.pillTaken = false
let uuidString = UUID()
pill.uuiString = uuidString
pill.selectedNotificationDate = selectedNotificationDate
pill.selectedPillType = selectedPillType
pill.selectedIntake = selectedIntake
pill.userSelectedTimeStart = userSelectedTimeStart
pill.userSelectedDateStart = userSelectedDateStart
if let destVC = segue.destination as? HomeViewController {
// Send pill names to HomeVC
guard let nameText = nameTextField.text else { return }
pill.pillName = nameText
// Send pill info to HomeVC
guard let infoText = instructionsTextField.text else { return }
pill.pillInstruction = infoText
// Send pill timer to HomeVC
guard let userTimerStart = startDateTextField.text else { return }
pill.pillStartTimer = userTimerStart
// Send pill dosage to HomeVc
guard let doseTextFieldText = doseTextField.text else { return }
pill.selectedDosage = doseTextFieldText
// Send pill count to HomeVC
guard let pillCountText = pillsCountTextField.text else { return }
pill.pillsCount = pillCountText
// Send pill color to HomeVC
// guard let pillColor = colorOrImageTextField.textColor else { return }
// pill.pillColor = pillColor
// Create Notification
createNotification(pill: pill)
// Append new pill to pill array
destVC.pillsArray.append(pill)
// Save pills in custom plist
savePills()
}
}
//MARK:- Model Manupulation Methods
func savePills() {
//Save data to Core Data
do {
try context.save()
} catch {
print("Error Saving context, \(error)")
}
}
func createNotification (pill: Pill) {
// Ask for permistion for local notification
let center = UNUserNotificationCenter.current()
center.removeAllPendingNotificationRequests()
center.requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in
if granted {
print("notification granted!")
} else {
print("notification was denied!")
}
}
// Create the notification content
let content = UNMutableNotificationContent()
// Create notification title, body and info
guard let pillNameString = pill.pillName else { return }
content.title = pillNameString
guard let pillInstructionString = pill.pillInstruction else { return }
content.body = pillInstructionString
content.sound = .default
// Create notification trigger
guard let selectedDate = pill.selectedNotificationDate else { return }
let dateComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: selectedDate)
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
// Create the request
guard let uuidstr = pill.uuiString?.uuidString else { return }
let request = UNNotificationRequest(identifier: uuidstr, content: content, trigger: trigger)
// Register the request
center.add(request) { (error) in
// Handle error
if error != nil {
print("Failed to add notification request, \(error!)")
}
}
}
}
我可以滑动删除并完成操作,但不知道如何编辑数据。