Swift 4:按钮在另一个 UITableViewCell 中触发相同的操作
Posted
技术标签:
【中文标题】Swift 4:按钮在另一个 UITableViewCell 中触发相同的操作【英文标题】:Swift 4: Button triggers the same action in another UITableViewCell 【发布时间】:2018-10-20 18:55:14 【问题描述】:我有一个带有 2 个按钮(用于听力和语音识别)、标签和文本字段的单元格。我正在尝试实现的是选择语音识别按钮时,用户会说出标签中显示的内容。 我的问题是听按钮根据 indexPath.row 可以正常工作,但说话按钮不能。当它处于活动状态时,另一个单元格中的按钮也将变为活动状态。它在这些单元格中记录相同。You can see the picture of what I am talking about here
收听(即音频合成器)和语音识别的方法在 UITableViewCell 中。我已经尝试了所有可以在网上找到的解决方案,但都没有成功。试过了
protocol RepeatCellDelegate: class
func buttonTapped(cell: RepeatCell)
但问题仍然存在。另外,创建了另一个项目,而不是使用按钮进行语音识别,我只是使用直接 textField 输入,仍然出现同样的问题。
TableViewCell 类中的按钮:
@IBAction func speakButtonPressed(_ sender: Any)
self.delegate?.buttonTapped(cell: self)
我的cellForRowAt indexPath
:
let cell = tableView.dequeueReusableCell(withIdentifier: "RepeatCell") as! RepeatCell
cell.delegate = self
cell.conditionlabel.text = repeatTask[indexPath.row].conditionLabel
return cell
检测单元格索引并记录语音输入的 buttonTapped 函数。点击按钮后它会打印正确的单元格索引,但该操作也会在另一个单元格中触发。
func buttonTapped(cell: RepeatCell)
guard let indexPath = self.repeatTV.indexPath(for: cell) else
return
cell.speakButton.isSelected = !cell.speakButton.isSelected
if (cell.speakButton.isSelected)
self.recordAndRecognizeSpeech()
else
audioEngine.inputNode.removeTap(onBus: 0)
recognitionTask?.cancel()
print("Button tapped on row \(indexPath.row)")
//语音输入识别函数:
// variables for speech recognizer
让 audioEngine = AVAudioEngine() 让speechRecognizer:SFSpeechRecognizer? = SFSpeechRecognizer(语言环境:Locale.init(标识符:“en-US”)) 让请求 = SFSpeechAudioBufferRecognitionRequest() var recognitionTask: SFSpeechRecognitionTask?
// 语音函数 func recordAndRecognizeSpeech()
let node = audioEngine.inputNode
let recordingFormat = node.outputFormat(forBus: 0)
node.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) buffer, _ in
self.request.append(buffer)
audioEngine.prepare()
do
try audioEngine.start()
catch
return print(error)
guard let myRecognizer = SFSpeechRecognizer() else
return
if !myRecognizer.isAvailable
return
recognitionTask = speechRecognizer?.recognitionTask(with: request, resultHandler: (result, error) in
if result != nil //
if let result = result
let cell = self.repeatTV.dequeueReusableCell(withIdentifier: "RepeatCell") as! RepeatCell
let bestString = result.bestTranscription.formattedString
if cell.speakButton.isSelected == true
cell.userInput.text = bestString
else if let error = error
print(error)
)
我从本地 JSON 文件中获取数据,这是一个模型:
struct RepeatTask: Codable
let name: String
let label: String
let conditionWord: String
也许有人可以帮助我解决这个问题?
【问题讨论】:
【参考方案1】:这里没有足够的代码来重新创建您的问题,以后请提供Minimal, Complete, and Verifiable example。不幸的是,如果他们无法重现问题,没有人可以为您提供有效的解决方案来帮助您解决问题。
但我相信我理解您想要完成的工作:
-
模型对象,即
struct
。
一种协议,其默认实现对所有单元都相同。
符合调用协议方法的协议的TableViewCell
类。
一个 TableViewDelegate 和 Datasource 来管理来自 1 的对象。
考虑以下几点:
import UIKit
/// 1.
/// Data model for "Repeat Cell Objects"
struct RepeaterModel
var outputText:String?
var inputAudio:Data?
/// 2.
/// Allows a cell to delegate listening and repeating (speaking)
protocol RepeatableCell
func listen()
func speak()
// Extend your protocol to add a default implementation,
// that way you can just confrom to the protocol
// without implementing it every time, in every cell class.
extension RepeatableCell
func listen()
print("default implementation for listen")
func speak()
print("default implementation for speak")
/// 3.
final class RepeatCell: UITableViewCell, RepeatableCell
// MARK: - Properties
var model:RepeaterModel?
didSet
DispatchQueue.main.async
self.titleLabel.text = self.model?.outputText
// MARK: - Views
lazy var listenButton: UIButton =
let btn = UIButton(type: .system)
btn.setTitle("Listen", for: .normal)
btn.addTarget(self, action: #selector(activateListen), for: .touchUpInside)
btn.setTitleColor(.white, for: .normal)
btn.backgroundColor = .blue
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
()
lazy var speakButton: UIButton =
let btn = UIButton(type: .system)
btn.setTitle("Speak", for: .normal)
btn.addTarget(self, action: #selector(activateSpeak), for: .touchUpInside)
btn.setTitleColor(.white, for: .normal)
btn.backgroundColor = .green
btn.translatesAutoresizingMaskIntoConstraints = false
return btn
()
let titleLabel: UILabel =
let l = UILabel()
l.translatesAutoresizingMaskIntoConstraints = false
l.textColor = .black
l.textAlignment = .center
l.text = "No Text"
return l
()
//MARK: - Initializers
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?)
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.setup()
required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
//MARK: - Class Methods
func setup()
self.contentView.addSubview(listenButton)
self.contentView.addSubview(speakButton)
self.contentView.addSubview(titleLabel)
let spacing: CGFloat = 25.0
//Listen top left
listenButton.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: spacing).isActive = true
listenButton.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: spacing).isActive = true
listenButton.widthAnchor.constraint(equalToConstant: 100).isActive = true
listenButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
// title label, center top.
titleLabel.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: spacing).isActive = true
titleLabel.leadingAnchor.constraint(equalTo: self.listenButton.trailingAnchor, constant: spacing).isActive = true
titleLabel.trailingAnchor.constraint(equalTo: self.speakButton.leadingAnchor, constant: -spacing).isActive = true
titleLabel.heightAnchor.constraint(equalToConstant: 50).isActive = true
//Speak top right
speakButton.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: spacing).isActive = true
speakButton.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -spacing).isActive = true
speakButton.widthAnchor.constraint(equalToConstant: 100).isActive = true
speakButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
@objc func activateListen()
print("listen was pressed! on cell \(self.model?.outputText ?? "No Text")")
/// The user wants to listen
// call the delegate method..
listen()
// use self.model?.outputText
@objc func activateSpeak()
print("Speak was pressed! on cell \(self.model?.outputText ?? "No Text")")
/// The user is speaking, record audio
// call the delegate method..
speak()
//self.model?.inputAudio = somedata
/// 4.
class ViewController: UITableViewController
// Array of your model objects
var objects:[RepeaterModel] = []
override func viewDidLoad()
super.viewDidLoad()
self.tableView.register(RepeatCell.self, forCellReuseIdentifier: "Repeat")
// create or fetch model objects
let items = [
RepeaterModel(outputText: "1st Cell", inputAudio: nil),
RepeaterModel(outputText: "2nd Cell", inputAudio: nil),
RepeaterModel(outputText: "3rd Cell", inputAudio: nil),
RepeaterModel(outputText: "4th Cell", inputAudio: nil),
RepeaterModel(outputText: "5th Cell", inputAudio: nil),
RepeaterModel(outputText: "6th Cell", inputAudio: nil),
RepeaterModel(outputText: "8th Cell", inputAudio: nil),
RepeaterModel(outputText: "9th Cell", inputAudio: nil),
RepeaterModel(outputText: "10th Cell", inputAudio: nil),
RepeaterModel(outputText: "11th Cell", inputAudio: nil),
RepeaterModel(outputText: "12th Cell", inputAudio: nil)
]
self.objects += items
//MARK: - TableView Methods
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
// 25 top spacing + 50 view element width + 25 bottom spacing
return 100.0
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return objects.count
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
if let cell = self.tableView.dequeueReusableCell(withIdentifier: "Repeat") as? RepeatCell
cell.model = objects[indexPath.row]
// other cell stuff
return cell
return UITableViewCell()
在每个向下的单元格上按“听”然后“说”会产生以下输出:
【讨论】:
感谢您花时间编写以上所有代码,不幸的是,它不起作用。它不播放音频,也不录制。我更新了我的问题,提供了有关我使用的先前方法的更多信息。有时间请看一下,谢谢。 或者我在RepeatCell扩展中做错了speak()和listen()函数,通常将bestString(语音识别)分配给另一个变量或textview,我需要做if语句,例如:如果(speakButton.isActiove) inputTextView.text = bestString 。但问题是我不能在扩展中使用 speakButton。也许还有另一种方法可以实现这一点,我需要弄清楚。 您可以通过协议方法传递 self 并返回一个值以分配给您的 textview。即listen(_ cell: UITableViewCell) -> String?
,然后在按钮方法中使用textView.text = self.listen(self)
。 (激活监听)。您遇到的问题很可能是因为recognitionTask
中的let cell = self.repeatTV.dequeueReusableCell(withIdentifier: "RepeatCell") as! RepeatCell
行,您应该引用单元格本身,而不是使另一个单元格出列。
好的,我会尝试找到如何引用单元格本身的方法。我假设单元格在进入 .isSelected 状态时获得由按钮本身引起的相同操作的问题。当我添加了一些只需要执行简单操作(聆听、更改颜色)的其他按钮时,它们会根据索引路径工作。无论如何,我对swift还是很陌生。你上面给出的例子也很好,它给了我一些关于事情是如何完成的见解。我会在接下来的几天里使用它,会告诉你它是怎么回事。感谢您的努力伙伴,非常感谢。以上是关于Swift 4:按钮在另一个 UITableViewCell 中触发相同的操作的主要内容,如果未能解决你的问题,请参考以下文章