How to select item in collectionview programmatically?
You can simply use this after [self.collectionView reloadData]
[self.collectionView
selectItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]
animated:YES
scrollPosition:UICollectionViewScrollPositionCenteredVertically];
where index
is the index number for the selected student.
Select items programmatically in UICollectionView
I think you are missing this method from the UICollectionView Class Reference:
- (void)selectItemAtIndexPath:(NSIndexPath *)indexPath
animated:(BOOL)animated
scrollPosition:(UICollectionViewScrollPosition)scrollPosition
You can use this method multiple times if you want multiple selections.
Selecting UICollectionViewCell programmatically
Call them on mainThread they will work
DispatchQueue.main.async {
let indexPath = IndexPath(item: i, section: 0)
self.collectionView.selectItem(at: indexPath, animated: false, scrollPosition: .top)
self.collectionView(self.collectionView, didSelectItemAt: indexPath)
}
How can I programmatically select UICollection view cells and update a pointer array?
The code I posted before was just to show you a little bit about the logic of having a variable that tells you if the song is playing or not. But it is not a good production code, it was mostly for illustration purposes (it is not easy to maintain a dictionary and a pointer array). So, I'm gonna try to guide you in a different way so that your app becomes simpler to read later and you detach the function of playing as much as possible from your controller -> Reason: Imagine that later you would like to reuse the same cell to populate a collection view that displays the songs that correspond to an Album for example. Then you will have to refactor all the code to make your new collection view work as well. However, the point of any object oriented programming is that you can actually build "Objects" that can be reused as you may need.
So, first think what exactly your "song" object will have to be. Most probably is not only gonna be a path to a file that gets played anytime a user taps a cell from your collection view. I guess a song will also have an image, length, name, album, etc etc. If you continue creating arrays for each single variable that a song will need to display, you will probably end up with countless arrays that need to be maintained separately. That is not so easy and is surely more prone to fails.
The first thing the will be to create a class or an struct that actually contains all the data of you song. For example (using struct - you can use class if you want):
struct Song {
var songName : String
var isPlaying : Bool = false
init(songName : String) {
self.songName = songName
}
}
I'm only using two variables for the song object but you can add as many as you want. Just pay attention to which variable can be initialized when you create an instance of your "Song" object. In the example only the song name can be initialized, the Bool for playing is initialized by default to false and is the variable that tells you if the song is playing or not.
Then you can setup you Cell, which in this case will be the responsible for setting all the views depending on your "Song". For this you can create a custom class for the cell, in this case I just called it Cell, you can call it whatever you want.
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)!)
}
}
Notice that cell has play() function and a variable called song var song : Song?
. The reason is that I am going to let each cell decide when to play or pause. This detaches the cell from the play function that you would use in collection view.
Now that you have a "Song" object you can easily create an array of songs in your view controller or any other class. For example:
var songArray : [Song] = [Song.init(songName: "Song One"), Song.init(songName: "Song Two"), Song.init(songName: "Song Three")]
Finally you can initialize each of the cells of the collection view with each of the songs in your song array. For that you will use the cellForItemAt
function:
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
}
Now, you will see that the cell also has a weak var called var cellDelegate : CellDelegate
this is the protocol that you will use to control the cell play and pause function. You can read further about delegates later and how they help to detach your cell from the controller as much as possible. Also, another collection view controller may conform to this delegate and you will have the same access to the function of the cell without having to rewrite all the code.
The protocol can be set outside of your cell class:
protocol CellDelegate : class {
func didSelectCell (for cell: Cell)
}
Finally, conform the view controller to CellDelegate:
class ViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource, CellDelegate
And now the code for playing, pausing, previous, next, etc etc becomes way simpler and cleaner
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()
}
Notice the didSelectCell
function, that is all you need to add to conform to the delegate and play or pause your song. And that is it. Much cleaner and much simpler to code.
How to preselect and highlight a cell from a UICollectionView
For what you are trying to do, use isSelected
property of UICollectionViewCell
.
On how isSelected works, refer to: https://medium.com/@p.gpt10/uicollectionviewcell-selection-made-easy-41dae148379d
For initially selecting a UICollectionViewCell
use,
self.contentCollectionView.selectItem(at: IndexPath(row: 0, section: 0), animated: true, scrollPosition: .left)
Also, in didSelectItemAt
method, you don't need to change isSelected
or call above method. Just refer to the above tutorial and you will get everything you need.
Edit:
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate
{
@IBOutlet weak var aCollectionView: UICollectionView!
override func viewDidLoad()
{
super.viewDidLoad()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return 10
}
func numberOfSections(in collectionView: UICollectionView) -> Int
{
collectionView.allowsMultipleSelection = true
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "aCell", for: indexPath as IndexPath) as! myCollectionViewCell
cell.myLabel.text = "ok"
cell.isSelected = false
cell.layer.borderColor = UIColor.black.cgColor
cell.layer.borderWidth = 2
if indexPath.row == 5
{
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .left) //Add this line
cell.isSelected = true
}
return cell
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
}
class myCollectionViewCell: UICollectionViewCell
{
@IBOutlet weak var myLabel: UILabel!
override var isSelected: Bool{
didSet{
if self.isSelected
{
super.isSelected = true
self.contentView.backgroundColor = UIColor(red:0.08, green:0.28, blue:0.45, alpha:1)
}
else
{
super.isSelected = false
self.contentView.backgroundColor = UIColor(red:0.13, green:0.37, blue:0.58, alpha:0.7)
}
}
}
}
Related Topics
Measuring Time Accurately in Swift for Comparison Across Devices
Reordering Uitableview Without Reorder Control
Nsuserdefaults Synchronize Not Saving On
iOS 13 Set Uisearchtextfield Placeholder Color
Animating Calayer's Shadowpath Property
Custom Uitableviewcell with Progress Bar Download Update
How to Resolve iOS Link Errors with Opencv
In Swift, How to Get the Device Orientation Correctly Right After It's Launched
Missing iOS Development Signing Identity for (Null)
iPhone Only App Rejected for Not Running on iPad
Game Engine Collison Bitmask... Why 0X01 etc
How to Launch My Settings Bundle from My Application
All Notifications Disappearing After Opening One of Them
iOS Ibeacon: How to Get All of Proximityuuid Programmatically
iOS - Using Uisearchdisplaycontroller with Uisearchbar That Is Uibarbuttonitem in Uitoolbar
Rails: Redirect_To 'Myapp://' to Call iOS App from Mobile Safari