You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

仿iOS待办提醒APP的UITableView文本输入实现技术求助

Solution for iOS Reminder-Style Text Input in UITableView

Hey there! Let's work through your three issues step by step to replicate that smooth native iOS task/reminder input experience.


1. Add a New Cell When the User Presses Enter

Since you're using UITextView (not UITextField as shown in your existing code), we'll use the UITextViewDelegate method to listen for the enter key. Replace your current textFieldShouldReturn with this implementation:

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    // Catch the enter key press
    guard text == "\n" else { return true }
    
    // Get the current cell and its index path
    guard let cell = textView.superview?.superview as? tvcAddMetaDetails,
          let indexPath = tvAddMetaDetails.indexPath(for: cell) else {
        return false
    }
    
    let dataCount = isIngredients ? listItems.count : Method.count
    // Only add a new row if we're in an editable data row (not the "+" row)
    if indexPath.row < dataCount {
        // Save the current text (strip the newline)
        let updatedText = (textView.text as NSString).replacingCharacters(in: range, with: text).trimmingCharacters(in: .newlines)
        if isIngredients {
            listItems[indexPath.row] = updatedText
        } else {
            Method[indexPath.row] = updatedText
        }
        
        // Add an empty entry to the data source for the new row
        isIngredients ? listItems.append("") : Method.append("")
        
        // Refresh the table
        tvAddMetaDetails.reloadData()
        
        // Scroll to the new row and focus its text view
        DispatchQueue.main.async {
            let newIndexPath = IndexPath(row: dataCount, section: 0)
            self.tvAddMetaDetails.scrollToRow(at: newIndexPath, at: .bottom, animated: true)
            if let newCell = self.tvAddMetaDetails.cellForRow(at: newIndexPath) as? tvcAddMetaDetails {
                newCell.textView.becomeFirstResponder()
            }
        }
    }
    
    // Prevent the newline from appearing in the text view
    return false
}

Make sure your tvcAddMetaDetails cell has a textView property, and you've set the view controller as its delegate in cellForRowAt.


2. Remove Hardcoded Number of Rows

Instead of hardcoding a row count, base it on your data source plus one extra row for the "+" add button. Update your numberOfRowsInSection method:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // Actual data entries + 1 row for the add button
    let dataCount = isIngredients ? listItems.count : Method.count
    return dataCount + 1
}

This way, the table will always show exactly your existing entries plus the add row—no hardcoding required.


3. Add a "+" Button for the New Row

First, make sure your tvcAddMetaDetails cell has a UIButton (we'll call it addButton) added to its layout. Then modify your cellForRowAt method to differentiate between data rows and the add row:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "AddMetaDetails", for: indexPath) as! tvcAddMetaDetails
    
    let dataCount = isIngredients ? listItems.count : Method.count
    
    if indexPath.row < dataCount {
        // Configure editable text view row
        cell.textView.isHidden = false
        cell.addButton.isHidden = true
        cell.textView.text = isIngredients ? listItems[indexPath.row] : Method[indexPath.row]
        cell.textView.delegate = self // Set delegate for text input handling
        // Keep your existing numbering if needed:
        // cell.textLabel?.text = "\(indexPath.row + 1). \(cell.textView.text ?? "")"
    } else {
        // Configure add button row
        cell.textView.isHidden = true
        cell.addButton.isHidden = false
        cell.addButton.setTitle("+", for: .normal)
        cell.addButton.titleLabel?.font = UIFont.systemFont(ofSize: 24, weight: .medium)
        // Add tap action for the button
        cell.addButton.addTarget(self, action: #selector(addNewRowTapped), for: .touchUpInside)
    }
    
    return cell
}

// Action for the "+" button tap
@objc private func addNewRowTapped() {
    // Add empty entry to data source
    isIngredients ? listItems.append("") : Method.append("")
    tvAddMetaDetails.reloadData()
    
    // Scroll to the new row and focus its text view
    let newRowIndex = (isIngredients ? listItems.count : Method.count) - 1
    let newIndexPath = IndexPath(row: newRowIndex, section: 0)
    tvAddMetaDetails.scrollToRow(at: newIndexPath, at: .bottom, animated: true)
    
    DispatchQueue.main.async {
        if let newCell = self.tvAddMetaDetails.cellForRow(at: newIndexPath) as? tvcAddMetaDetails {
            newCell.textView.becomeFirstResponder()
        }
    }
}

Note: Adjust your cell's layout to center the addButton and match the clean, native iOS style.


Quick Additional Notes

  • Keep your existing heightForRowAt setup (automatic dimension) to maintain dynamic cell heights as the user types.
  • Ensure your tvcAddMetaDetails cell's textView has isScrollEnabled = false (you mentioned you already have this covered).

内容的提问来源于stack exchange,提问作者captain_haddock

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:40:11