Pointers 如何以编程方式选择UICollection视图单元格并更新指针数组?

Pointers 如何以编程方式选择UICollection视图单元格并更新指针数组?,pointers,uicollectionview,selection,avplayer,Pointers,Uicollectionview,Selection,Avplayer,我正在将indexPath与指针数组与我的数据模型进行匹配,以查看正在播放的曲目,从而可以使用didSelectItemAt委托方法控制音频播放。i、 e.当一个单元格被点击时,它会根据所选单元格的索引来检查播放的是哪首歌曲。(我根据这些参数在didSelectItemAt代理中播放和暂停音频)。为此,我在给定的索引XPath处切换轨迹指针数组中的布尔值 当您手动选择单元格(点击或单击)时,这非常适合播放和暂停音频 我想以编程方式选择其他单元格,但这样做时,布尔值似乎设置不正确 下面是一些代码来

我正在将indexPath与指针数组与我的数据模型进行匹配,以查看正在播放的曲目,从而可以使用didSelectItemAt委托方法控制音频播放。i、 e.当一个单元格被点击时,它会根据所选单元格的索引来检查播放的是哪首歌曲。(我根据这些参数在didSelectItemAt代理中播放和暂停音频)。为此,我在给定的索引XPath处切换轨迹指针数组中的布尔值

当您手动选择单元格(点击或单击)时,这非常适合播放和暂停音频

我想以编程方式选择其他单元格,但这样做时,布尔值似乎设置不正确

下面是一些代码来帮助解释:

  let workData = TypeData.createWorkMusicArray()
  var musicDataArray: [TypeData] = []
  var keys = [TypeData]()
  var pointerArray: [TypeData : Bool]! 
  var currentTrack: Int!

    override func viewDidLoad() {
      super.viewDidLoad()

    musicDataArray = workData

    keys = [workData[0], workData[1], workData[2]]
    pointerArray = [workData[0] : false, workData[1] : false, workData[2] : false]

    musicCollectionView.allowsMultipleSelection = false

}


 func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

    currentTrack = indexPath.item

    if pointerArray[keys[indexPath.item]] == false {
        pointerArray[keys[indexPath.item]] = true
        print("Playing", keys[indexPath.item])
        playAudio()
        return
    }

    pointerArray[keys[indexPath.item]] = false
    print("Stop", keys[indexPath.item])
    pause()
}
还要注意的是,我的应用程序中的任何播放逻辑都没有使用DidDecelectItemat delegate方法,因为我只有一个AVPlayer,当单元格被选中时,一个新项目会被传递到该单元格中(这里的Decelecte方法只是将布尔值设置为false,以便我可以更改UI)

这是我用来尝试和编程选择单元格的函数:

func previousTrack() {
    func getCurrentTrack() {
        if currentTrack - 1 < 0 {
            currentTrack = (musicDataArray.count - 1) < 0 ? 0 : (musicDataArray.count - 1)

        } else {
            currentTrack -= 1

        }
    }

    getCurrentTrack()

    //I've tried setting the boolean here to false but it still does not work 
    pointerArray[keys[currentTrack]] = false

    self.musicCollectionView.selectItem(at: IndexPath(item: currentTrack, section: 0), animated: true, scrollPosition: .top)
    self.musicCollectionView.delegate?.collectionView!(self.musicCollectionView, didSelectItemAt: IndexPath(item: currentTrack, section: 0))
}

  @IBAction func rewindBtnTapped(_ sender: Any) {
  previousTrack()
}
func-previousTrack(){
func getCurrentTrack(){
如果currentTrack-1小于0{
currentTrack=(musicDataArray.count-1)<0?0:(musicDataArray.count-1)
}否则{
currentTrack-=1
}
}
getCurrentTrack()
//我已尝试将布尔值设置为false,但仍然不起作用
pointerArray[keys[currentTrack]]=false
self.musicCollectionView.selectItem(位于:IndexPath(项:currentTrack,节:0),动画:true,滚动位置:.top)
self.musicCollectionView.delegate?.collectionView!(self.musicCollectionView,didSelectItemAt:IndexPath(项:currentTrack,节:0))
}
@iAction func倒带标记(uu发送方:任何){
以前的轨道()
}
当调用REWINDBNTATPED时,它将选择上一个单元格,但当我决定选择/点击/单击单元格时,行为不一致,即启用播放和暂停的布尔值混淆


我真的很感谢你抽出时间-谢谢你

我之前发布的代码只是向你展示了一点关于拥有一个变量的逻辑,该变量告诉你歌曲是否正在播放。但它不是一个好的生产代码,它主要是为了说明(维护字典和指针数组并不容易)。因此,我将尝试以不同的方式指导您,使您的应用程序更易于以后阅读,并且您将尽可能多地从控制器中分离播放功能->原因:想象一下,稍后您希望重用同一单元格来填充一个集合视图,该视图显示与唱片集对应的歌曲,例如。然后,您必须重构所有代码,使新的集合视图也能正常工作。然而,任何面向对象编程的要点是,您实际上可以构建可以根据需要重用的“对象”

所以,首先想想你的“歌曲”对象到底是什么。最有可能的是,它不仅仅是一个文件的路径,当用户从集合视图点击单元格时,该文件就会被播放。我猜一首歌也会有图像、长度、名称、专辑等。如果你继续为一首歌需要显示的每个变量创建数组,你可能会得到无数需要单独维护的数组。这并不容易,而且肯定更容易失败

第一件事是创建一个类或结构,该类或结构实际上包含歌曲的所有数据。例如(使用struct-如果需要,可以使用class):

我只为song对象使用了两个变量,但您可以添加任意数量的变量。只需注意在创建“Song”对象的实例时可以初始化哪个变量。在本例中,只能初始化歌曲名称,播放的Bool默认初始化为false,它是告诉您歌曲是否正在播放的变量

然后,您可以设置您的单元格,在这种情况下,单元格将负责根据您的“歌曲”设置所有视图。为此,您可以为cell创建一个自定义类,在本例中,我将其称为cell,您可以随意调用它

class Cell : UICollectionViewCell {

    var song : Song?

    weak var cellDelegate : CellDelegate?

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupViews()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func setupViews() {
        self.backgroundColor = .red
    }

    func play() { 
        if !(song?.isPlaying)! {
            song?.isPlaying = true
            print("Playing", (song?.songName)!)
            return
        }
        song?.isPlaying = false
        print("Stop", (song?.songName)!)
    }

}
请注意,该单元格有play()函数和一个名为song
var song:song?
的变量。原因是我将让每个细胞决定何时播放或暂停。这会将单元格与要在“收藏”视图中使用的播放功能分离

现在您有了一个“歌曲”对象,您可以轻松地在视图控制器或任何其他类中创建歌曲数组。例如:

var songArray : [Song] = [Song.init(songName: "Song One"), Song.init(songName: "Song Two"), Song.init(songName: "Song Three")]
最后,您可以使用歌曲数组中的每首歌曲初始化集合视图的每个单元格。为此,您将使用
cellForItemAt
功能:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! Cell
        cell.song = songArray[indexPath.item]
        cell.cellDelegate = self
        return cell
    }
现在,您将看到该单元格还有一个名为
var-celldegate:celldegate
的弱var,这是用于控制单元格播放和暂停功能的协议。稍后,您可以进一步了解代理以及代理如何帮助您尽可能多地将单元格与控制器分离。另外,另一个集合视图控制器可能符合此委托,并且您将拥有对单元格功能的相同访问权限,而无需重写所有代码

可以在您的单元类之外设置协议:

protocol CellDelegate : class {
    func didSelectCell (for cell: Cell)
}
最后,使视图控制器符合CellDelegate:

class ViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource, CellDelegate
现在,播放、暂停、上一个、下一个等的代码变得更加简单和干净

 func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        currentIndexPathItem = indexPath.item
        let cellToPlay = collectionView.cellForItem(at: IndexPath(item: currentIndexPathItem, section: 0)) as! Cell
        didSelectCell(for: cellToPlay)
    }

    func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
        let cellToStop = collectionView.cellForItem(at: indexPath) as! Cell
        if (cellToStop.song?.isPlaying)! { didSelectCell(for: cellToStop) }
    }

    @objc func previous () {
        let playingCell = collectionView.cellForItem(at: IndexPath(item: currentIndexPathItem, section: 0)) as! Cell
        if (playingCell.song?.isPlaying)! { didSelectCell(for: playingCell) }
        if currentIndexPathItem - 1 < 0 { return }
        else { currentIndexPathItem = currentIndexPathItem - 1 }
        let cellToPlay = collectionView.cellForItem(at: IndexPath(item: currentIndexPathItem, section: 0)) as! Cell
        didSelectCell(for: cellToPlay)
    }

    func didSelectCell(for cell: Cell) {
        cell.play()
    }
func collectionView(collectionView:UICollectionView,didSelectItemAt indepath:indepath){
currentIndexPathItem=indexPath.item
将cellToPlay=collectionView.cellForItem(位于:indexath(item:currentIndexPath,section:0))设为!Cell
didSelectCell(fo
class ViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource, CellDelegate
 func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        currentIndexPathItem = indexPath.item
        let cellToPlay = collectionView.cellForItem(at: IndexPath(item: currentIndexPathItem, section: 0)) as! Cell
        didSelectCell(for: cellToPlay)
    }

    func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
        let cellToStop = collectionView.cellForItem(at: indexPath) as! Cell
        if (cellToStop.song?.isPlaying)! { didSelectCell(for: cellToStop) }
    }

    @objc func previous () {
        let playingCell = collectionView.cellForItem(at: IndexPath(item: currentIndexPathItem, section: 0)) as! Cell
        if (playingCell.song?.isPlaying)! { didSelectCell(for: playingCell) }
        if currentIndexPathItem - 1 < 0 { return }
        else { currentIndexPathItem = currentIndexPathItem - 1 }
        let cellToPlay = collectionView.cellForItem(at: IndexPath(item: currentIndexPathItem, section: 0)) as! Cell
        didSelectCell(for: cellToPlay)
    }

    func didSelectCell(for cell: Cell) {
        cell.play()
    }