点击单元格按钮时如何更新单元格滑块的值?

How to update a cell slider's value when the cell's button tapped?

我有一个集合视图单元格,它有两个视图。一个是按钮,另一个是水平滑块。我想做的是,我想在点击单元格的按钮时播放曲目,一旦曲目开始播放,滑块的值就应该增加。

点击播放按钮后,我需要访问 UI 滑块并更新它的值。这是我尝试过的;

点击按钮:

   @IBAction func playPreviewButtonTapped(sender: UIButton) {
       playPreviewSound(fileName: fileName)
       setPausePreviewSoundButtonImage(button: sender)
   }

播放声音功能:

  private func playPreviewSound(fileName: String) {
            let url = Bundle.main.url(forResource: fileName, withExtension: "mp3")
            do {
                try AVAudioSession.sharedInstance().setActive(true)
                player = try AVAudioPlayer(contentsOf: url!, fileTypeHint: AVFileType.mp3.rawValue)
                guard let player = player else { return }
                player.play()
                setIsPreviewPlaying(state: true)
                
                let selectedIndexPath = cellIndexPathDict[fileName]!.indexPath
                
                let asset = AVAsset(url: url!)
                let audioDuration = asset.duration
                let audioDurationSeconds = Float(CMTimeGetSeconds(audioDuration))
                
                getCellByIndexPath(indexPath: selectedIndexPath).previewSoundSlider.maximumValue = audioDurationSeconds
                timer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(updateSliderWithTimer), userInfo: ["slider": getCellByIndexPath(indexPath: selectedIndexPath).previewSoundSlider], repeats: true)
                
            } catch let error {
                print(error.localizedDescription)
        }
    }
    private func getCellByIndexPath (indexPath: IndexPath) -> BackStageCollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: BackStageCollectionViewCell.REUSE, for: indexPath) as! BackStageCollectionViewCell
        setCellInstances(cell: cell, indexPath: indexPath)
        print("cell title; ", cell.processorNameLabel.text!) // here, the title always the default title. 
        return cell
    }

定时器功能:

   @objc private func updateSliderWithTimer(slider: UISlider) {
       let userInfo = timer.userInfo as! Dictionary<String, AnyObject>
       let slider: UISlider = (userInfo["slider"] as! UISlider)
       print(slider.maximumValue) // here, the max value is always 1
       slider.value += 0.5
   }

如何访问单元格?我创建了一本字典;

   private var cellIndexPathDict: [String: CellIndexModel] = [:]

   struct CellIndexModel {
       var indexPath : IndexPath
   }

在创建单元格时推送到 dic:

UICollectionViewDelegate 扩展:

  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: BackStageCollectionViewCell.REUSE, for: indexPath) as! BackStageCollectionViewCell
            
        setCellInstances(cell: cell, indexPath: indexPath)
            
        let gearsGroup = listGearsGroups.object(at: indexPath.section) as! GearsGroup
        let gear = gearsGroup.listGears.object(at: indexPath.row) as! BaseGear
            
        let mod : CellIndexModel = CellIndexModel(indexPath: indexPath)
        cellIndexPathDict[gear.previewSoundFile as String] = mod
            
        cell.playPreviewButton.addTarget(self, action:#selector(playPreviewButtonTapped(sender:)), for: .touchUpInside)
        cell.playPreviewButton.accessibilityLabel = gear.previewSoundFile as String?
            
        return cell
   }

基本上我正在创建一个字典来存储单元格索引路径并尝试在 tap 函数中访问它,但我只获得默认值。不是选中的。

点击按钮时如何访问和更新单元格? 我刚开始学习Swift,所以解释一下会很棒!谢谢

因为cell复用机制,当你使用

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: BackStageCollectionViewCell.REUSE, for: indexPath) as! BackStageCollectionViewCell

在大多数情况下,你不会得到你看到的那个indexPath的单元格。

它的状态属于对象池中的一个单元格。

也许你得到了新创建的单元格,它的状态是默认的。


典型解法:

当您的播放声音按钮被点击时,您可以相应地获取它的 indexPath。

然后你可以访问audioPlayer.currentTime,

的值

重新加载相关单元格。

 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
      // configure the slide value here
}

调用它重新加载

collectionView.reloadItems(at: [indexPath])

通常我们要更新单元格的值,我们不会直接处理单元格,

我们记录单元格的值属性,然后配置通过重新加载更新的单元格。

我给模式命名mark & config


其他提示一:

很多时候,我们不使用

 @objc private func updateSliderWithTimer(slider: UISlider) {
       let userInfo = timer.userInfo as! Dictionary<String, AnyObject>
       let slider: UISlider = (userInfo["slider"] as! UISlider)
       print(slider.maximumValue) // here, the max value is always 1
       slider.value += 0.5
   }

我们使用

@objc private func updateSliderWithTimer(slider: UISlider) {
           
           let slider: UISlider = (userInfo["slider"] as! UISlider)
           slider.value = Float(audioPlayer.currentTime)
       }

我们可以访问当前播放器的音频播放时间,

最好使用准确的时间,而不是大概的时间。


其他提示2:

通常我们不使用

private func getCellByIndexPath (indexPath: IndexPath) -> BackStageCollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: BackStageCollectionViewCell.REUSE, for: indexPath) as! BackStageCollectionViewCell
        //...
        return cell
    }

我们使用

 private func getCellByIndexPath (indexPath: IndexPath) -> BackStageCollectionViewCell? {
        if collectionView.indexPathsForVisibleItems.contains(indexPath){
             // ...
             return collectionView.cellForItem(at: indexPath) as? BackStageCollectionViewCell
        }else{
             return nil
        }
    }

因为collectionView的cell复用,如果看不到cell,则cell不存在。

对于用户界面,如果看不到该单元格,则该单元格对用户没有用。