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

Posted

技术标签:

【中文标题】点击单元格按钮时如何更新单元格滑块的值?【英文标题】:How to update a cell slider's value when the cell's button tapped? 【发布时间】:2020-10-28 08:03:53 【问题描述】:

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

当点击播放按钮时,我需要访问 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,所以一个解释会很棒!谢谢

【问题讨论】:

【参考方案1】:

由于单元格复用机制,当你使用时

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])

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

我们记录cell的属性值,然后配置通过reloading更新的cell。

我将模式命名为 ma​​rk & 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不存在。

对于用户界面,如果单元格不可见,则该单元格对用户没有用处。

【讨论】:

return collectionView.cellForItem(at: indexPath) as? BackStageCollectionViewCell 成功了。谢谢!

以上是关于点击单元格按钮时如何更新单元格滑块的值?的主要内容,如果未能解决你的问题,请参考以下文章

Swift:如何在动态 UITableView 的自定义单元格中获取滑块的值?

滑块值更改时快速更新表格中的单元格数

如何连续更新一堆表格单元格上的滑块?

iOS 应用程序在带有滑块的大量表格单元格上崩溃

删除按钮仅显示在单元格下方的一半

UITableView以编程方式调用滑动操作