Xcode8.2.1をSwift 3.UITextViewを含むカスタムUITableViewCellが1つあります。textView
に入力すると、カスタムセルが自動的に大きくなります。この部分は特定のセルに入力するときに、他のセルも同じデータで更新したい。例:
5番目のセルにテキストを入力すると、11番目、15番目、18番目のセルに同じデータが自動的に入力されます。これらの細胞も自動的に増殖させる必要があります。配列の特定のインデックスにデータを追加しました。ただし、tableView
には反映されません。この機能を実現するにはどうすればよいですか?
これまでに実装した次のコードを実行してください。このupdateCellHeight
メソッドは、カスタムデリゲートメソッドです。このメソッドは、ユーザーがtextView
を入力したときに呼び出されます。
func updateCellHeight(indexPath: IndexPath, comment: String) {
let currentCellLyricVal = self.traduzioneArray[indexPath.row]["rics"]
tempIndexArray.removeAll()
for (index,element) in traduzioneArray.enumerated() {
let lyricVal = element["rics"]
if currentCellLyricVal == lyricVal {
tempIndexArray.append(index)
}
}
for index in tempIndexArray {
self.traduzioneArray[index]["ione"] = comment
self.lyricsTableView.beginUpdates()
self.lyricsTableView.endUpdates()
}
}
func textViewDidChange(_ textView: UITextView) {
self.delegate.updateCellHeight(indexPath: self.cellIndexPath, comment: textView.text)
}
自動データ入力の問題は、セルをリロードするとresignFirstResponder()
呼び出しが発生するという事実だと思います。
これは非常に論理的なようです。データの再読み込みでは、実際にいくつかのセルを放棄し、_cellForRowAt:
_を介してテーブルビューに新しいセルを要求するからです。古いものは同じではない可能性があるため、resignFirstResponder()
。
セルのテキストを更新する1つの方法は、セルの内容を直接変更することです。これは、テキストビューのコンテンツに対して実行できます。残念ながら、セルの高さについては、_heightForRowAt:
_をトリガーせずにセルを直接変更する方法はありません。
PDATE2:ISテーブルビューで直接セル操作とAutomaticDimensionを組み合わせたiOS8 +のソリューションがあります。
UITextViewで問題なく動作します。以下の更新を確認してください。最終結果は次のようになります。
PDATE1:セルを直接操作するためのコード例を追加
単純なモデルを使用して、テーブルビューデータを保持します。
_// Simple model, for the example only
class Model {
// The value of the text field
var value: String?
// The type of the cell
var type: CustomCell.CellType = .typeA
init(value: String) {
self.value = value
}
init(value: String, type: CustomCell.CellType) {
self.value = value
self.type = type
}
}
// Init the model.
var tableData = [
Model(value: "Cell Type A", type: .typeA),
Model(value: "Cell Type B", type: .typeB),
Model(value: "Cell Type B", type: .typeB),
Model(value: "Cell Type A", type: .typeA),
Model(value: "Cell Type B", type: .typeB)]
_
そして、このように委任します:
_// Delegate to update visible cells in the table view when text field value change.
protocol TextChangeDelegate {
func textChangedAtCell(_ cell: CustomCell, text: String?)
}
_
次に、カスタムセルを初期化します。
_func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Will crash if identifier is not registered in IB
let cell = tableView.dequeueReusableCell(withIdentifier: "customCell") as! CustomCell
// For this to work you need to update the model on each text field text change
cell.textValue.text = tableData[indexPath.row].value
cell.index = indexPath.row
cell.type = tableData[indexPath.row].type
cell.textChangeDelegate = self
return cell
}
_
カスタムセル内:
_class CustomCell: UITableViewCell {
// The type of the cell. Cells with same type will be updated simultaneously.
enum CellType {
case typeA
case typeB
}
// Very simple prototype cell with only one text field in it
@IBOutlet weak var textValue: UITextField!
// Default type
var type = CellType.typeA
// Index in the model. Not optional (or other special assumptions on initial value)
// for simplicity of the example.
var index = 0
var textChangeDelegate: TextChangeDelegate?
}
extension CustomCell: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// Assume we will return true. Any logic could appear here.
// If we need to return false, don't call the delegate method.
let result = true
if result {
let nsString = textField.text as NSString?
let newString = nsString?.replacingCharacters(in: range, with: string)
print("New: \(newString ?? "(nil)")")
textChangeDelegate?.textChangedAtCell(self, text: newString)
}
return result
}
}
_
これは、直接セルアクセスを使用して、つまりデータをリロードせずに、ViewControllerにTextChangeDelegateを実装する方法です。
_extension ViewController: TextChangeDelegate {
func textChangedAtCell(_ cell: CustomCell, text: String?) {
// Only visual update. Skip the cell we are currently editing.
for visibleCell in tableView.visibleCells where visibleCell != cell {
if let currentCell = visibleCell as? CustomCell,
tableData[currentCell.index].type == cell.type {
currentCell.textValue.text = text
}
}
// Update the model (including invisible cells too)
for (index, data) in tableData.enumerated() where data.type == cell.type {
tableData[index].value = text
}
// Avoid reloading here, as this will trigger resignFirstResponder and you will
// have issues when jumping from text field to text field across cells.
}
}
_
これで、同じCellTypeを持つすべてのセルでテキストが同時に更新されます。この例では、UITextFieldを使用します(UITextViewのUPDATE2を確認してください)。
PDATE2はここにあります。テキストと高さを同時に調整できるUITextViewのセル。
前の例のモデルとコントローラーを使用します(新しいセルを使用するため、小さな変更があります)。 UITableViewCellを利用して、UITextViewを内部に配置します。 AutoLayoutで、制約をテキストビューに設定します。
スクロールとバウンスを無効にするテキストビューに移動することを忘れないでください(そうしないと、自動高さがありません)。 textViewのデリゲートをUITextViewCellサブクラスにリンクすることを忘れないでください。
次に、セルで、
_func textViewDidChange(_ textView: UITextView) {
self.textChangeDelegate?.textChangedAtCell(self, text: textView.text)
}
_
次に、super important、ViewControllerのviewDidLoadで、この2つの設定を追加します
_tableView.estimatedRowHeight = 50
tableView.rowHeight = UITableViewAutomaticDimension
_
セルを登録します。
_tableView.register(UINib(nibName: "CustomTextViewCell", bundle: nil),
forCellReuseIdentifier: "customTextViewCell")
_
最後に、このコードをUPDATE1からTextChangeDelegate実装に追加して、実際の高さ更新のトリックを実行します。
_func textChangedAtCell(_ cell: UITableViewCell, text: String?) {
<code from UPDATE 1 goes here>
tableView.beginUpdates()
tableView.endUpdates()
}
_
楽しい!
データセットを新しいデータで更新したら。更新されたデータセットを使用して特定のセルをリロードします。
func updateCellHeight(indexPath: IndexPath, comment: String) {
DispatchQueue.main.async {
let currentCellLyricVal = self.traduzioneArray[indexPath.row]["rics"]
tempIndexArray.removeAll()
for (index,element) in traduzioneArray.enumerated() {
let lyricVal = element["rics"]
//You have to skip the current cell. by checking index != indexPath.row
if currentCellLyricVal == lyricVal, index != indexPath.row {
tempIndexArray.append(index)
}
}
for index in tempIndexArray {
self.traduzioneArray[index]["ione"] = comment
let updatedIndexPath = IndexPath(row: index, section: indexPath.section)
if let visibleCellIndexPaths = tableView.indexPathsForVisibleRows {
if visibleCellIndexPaths.contains(updatedIndexPath) {
tableView.reloadRows(at: [updatedIndexPath], with: .automatic)
}
}
}
}
}
注:変更されたデータセットセルが表示されている場合は、特定のセルをリロードするだけで済みます。
まず、ストーリーボードまたはtableView Cellクラスで、textviews NumberOfLines =を設定します。
行デリゲートの高さで
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
ViewdidLoadに次の行を追加します。
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 140
TableViewController内
func updateCellHeight(indexPath: IndexPath, comment: String) {
let currentCellLyricVal = self.traduzioneArray[indexPath.row]["rics"]
tempIndexArray.removeAll()
for (index,element) in traduzioneArray.enumerated() {
let lyricVal = element["rics"]
if currentCellLyricVal == lyricVal {
tempIndexArray.append(index)
}
}
for index in tempIndexArray {
self.traduzioneArray[index]["ione"] = comment
}
tableView.reloadRows(at: [IndexPath(row: 11, section: 1),IndexPath(row: 13, section: 1)], with: UITableViewRowAnimation.none)
}
線を0に設定し、高さを自動寸法設定することにより、セルのサイズが自動的に変更されます。また、カスタムセルを設定していることを確認してください自分で自分に委任cellForRow
メソッド。
セルを更新する必要があるたびに、次のコードを使用します。
func updateCellHeight(indexPath: IndexPath, comment: String) {
//update dataModel according to new text
...
//then reload visible tableview rows
//pay atttention to beginUpdates endUpdates methods.
//This do the trick)
tableView.beginUpdates()
tableView.reloadRows(at: indexPathsForVisibleRows ?? [], with: .none)
tableView.endUpdates()
}