Where to highlight UICollectionViewCell: delegate or cell?
As the documentation says, you can rely on highlighted
property to be changed while the cell is highlighted. For example the following code will make the cell red when highlighted (not its subviews though):
- (void)setHighlighted:(BOOL)highlighted {
[super setHighlighted:highlighted];
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
if (self.highlighted) {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(context, 1, 0, 0, 1);
CGContextFillRect(context, self.bounds);
}
}
And if you add something like this the background will become purple (red + opaque blue):
- (void)collectionView:(UICollectionView *)colView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [colView cellForItemAtIndexPath:indexPath];
cell.contentView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:1 alpha:0.5];
}
- (void)collectionView:(UICollectionView *)colView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [colView cellForItemAtIndexPath:indexPath];
cell.contentView.backgroundColor = nil;
}
So you can use both together (not necessarily both changing the cell appearance). The difference is that with delegate methods you also have indexPath
. It might be used to create multi-selection (you will use this methods together with selection delegate methods), to show some preview while the cell is highlighted, to show some animation with other views... There's quite a few appliance for this delegate methods in my opinion.
As a conclusion, I would leave the cell appearance to be handled by the cell itself and use delegate methods to let controller make something cool in the same time.
highlighting uicollectionview cell on tap
I had the exact same problem and the solution is actually much simpler then the one posted above.
In your view controller, add collectionView.delaysContentTouches = false
.
And then your other code within the cell was fine as is:
class SlideOutMenuCells: UICollectionViewCell {
//Setup code...
override var isHighlighted: Bool {
didSet {
if self.isHighlighted {
backgroundColor = UIColor.green
} else {
backgroundColor = UIColor.red
}
}
}
}
But now that annoying delay is gone!
How can I highlight selected UICollectionView cells? (Swift)
you can use border change on didSelectItemAtIndexPath
override event like the below code and assign new settings on the cell.
Swift 3.x:
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
addToList.append(objectsArray[indexPath.row])
let cell = collectionView.cellForItem(at: indexPath)
cell?.layer.borderWidth = 2.0
cell?.layer.borderColor = UIColor.gray.cgColor
}
UICollectionView cell selection and cell reuse
Your observation is correct. This behavior is happening due to the reuse of cells. But you dont have to do any thing with the prepareForReuse. Instead do your check in cellForItem and set the properties accordingly. Some thing like..
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cvCell" forIndexPath:indexPath];
if (cell.selected) {
cell.backgroundColor = [UIColor blueColor]; // highlight selection
}
else
{
cell.backgroundColor = [UIColor redColor]; // Default color
}
return cell;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *datasetCell =[collectionView cellForItemAtIndexPath:indexPath];
datasetCell.backgroundColor = [UIColor blueColor]; // highlight selection
}
-(void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *datasetCell =[collectionView cellForItemAtIndexPath:indexPath];
datasetCell.backgroundColor = [UIColor redColor]; // Default color
}
Highlight collection cell when selected
You are getting the cell in the wrong way
FilterCell *filterCell = (FilterCell *)[collectionView dequeueReusableCellWithReuseIdentifier:@"FilterCell" forIndexPath:indexPath];
will dequeue a cell which is not used right now or allocate a new one with the specified identifier.
Use
FilterCell *filterCell = (FilterCell *)[collectionView cellForItemAtIndexPath:indexPath];
instead.
Anyway a cleaner solution would be to set the backgroundView
and selectedBackgroundView
properties of the cell, without touching the backgroundProperty
color (that will stay clear
as default). In this way you can avoid the delegate method and achieve the same behavior.
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)
}
}
}
}
Highlight UICollectionViewCells with PanGesture using Objective-C
First, I believe tracking selected cells via "native" UICollectionView
mechanism is reasonable and consistent. There isn’t any need for custom gesture handlers inside of the cells. In order to represent selected state however, you need to set selectedBackgroundView
property, something like this:
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"RingCollectionViewCell" forIndexPath:indexPath];
if (!cell.selectedBackgroundView) {
cell.selectedBackgroundView = [[UIView alloc] initWithFrame:cell.bounds];
cell.selectedBackgroundView.backgroundColor = [UIColor grayColor];
}
return cell;
}
I don't know how your RingCollectionViewCell
class is designed, but be advised that you will need to ensure contentView
of this cell has transparent background color otherwise it will obscure the selectedBackgroundView
.
Now the tricky part. UIPanGestureRecognizer
gets events very quickly and the handle method will be called quite often when the user just keeps his/her fingers still on the screen. Thus you need to somehow suppress events which are not supposed to switch selected state of a cell.
My suggestion is to ignore all consequence events if they happen in the same cell. In order to implement such behavior we need to store index path of the last cell touched. Let’s use a simple property for that:
@interface ViewController ()
@property (strong, nonatomic, nullable) NSIndexPath *trackingCellIndexPath;
@end
Now you need to assign index path of last touched cell to this property in your gesture handle method. You also need to reset this property when the gesture is finished or cancelled. Switch selection of the given index path if it is not equal to the tracked index path and ignore the touch event otherwise:
- (void)handlePanGesture:(UIPanGestureRecognizer *)recognizer {
// Reset the tracking state when the gesture is finished
switch (recognizer.state) {
case UIGestureRecognizerStateEnded:
case UIGestureRecognizerStateCancelled:
self.trackingCellIndexPath = nil;
return;
default:
break;
}
// Obtain the cell the user is currently dragging over
CGPoint location = [recognizer locationInView:self.collectionView];
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:location];
// If the user currently doesn't touch any cell, reset the tracking state and prepare to listen to another cell
if (!indexPath) {
if (self.trackingCellIndexPath) {
self.trackingCellIndexPath = nil;
}
return;
}
// If current event is subsequent gesture event which happens within the same cell, ignore it
if (self.trackingCellIndexPath == indexPath) {
return;
}
// If the cell hasn't been previously tracked, switch the selected state and start tracking it
self.trackingCellIndexPath = indexPath;
if ([self.collectionView.indexPathsForSelectedItems containsObject:indexPath]) {
[self.collectionView deselectItemAtIndexPath:indexPath animated:YES];
} else {
[self.collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionNone];
}
}
The last thing to change is the selection mode of the collection view. As you expect multiple cells to remain selected, just switch allowsMultipleSelection
of your collection view somewhere in viewDidLoad
:
- (void)viewDidLoad {
...
self.collectionView.allowsMultipleSelection = YES;
}
Set selected color of cell in UiCollectionView in swift
For two different colors based on selected state of the cell, you may need to subclass your UICollectionViewCell like this:
import UIKit
class YourCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var imageView: UIImageView! // for example - some UI element inside cell ...
override var isSelected: Bool {
didSet {
self.contentView.backgroundColor = isSelected ? UIColor.blue : UIColor.yellow
self.imageView.alpha = isSelected ? 0.75 : 1.0
}
}
}
// and below you will have your original code
class YourViewController: UICollectionViewController {
... etc
Answering your question - for exceptional style of the first cell:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell ...
if(indexPath.row == 0) { //for first cell in the collection
cell.backgroundColor = UIColor.orange
} else {
cell.backgroundColor = UIColor.green
}
Why UICollectionView's UICollectionViewCell is not highlighting on user touch?
The class only tells you about the highlight state, but doesn't change the visual appearance. You'll have to do it programmatically by e.g. changing the background of the cell.
Details are described in the CollectionView Programming Guide.
pre select/highlight UICollectionViewCell on first load of view
In viewDidAppear
:
NSIndexPath *indexPathForFirstRow = [NSIndexPath indexPathForRow:0 inSection:0];
[self.dateCollectionView selectItemAtIndexPath:indexPathForFirstRow animated:NO scrollPosition:UICollectionViewScrollPositionNone];
[self collectionView:self.dateCollectionView didSelectItemAtIndexPath:indexPathForFirstRow];
Related Topics
How to Debug an Issue with a Release Mode Build in iOS
What Is the Impact of the "Requires Full Screen" Option in Xcode for an Iphone-Only App
App Crashing When Using Firebase Auth, Reason: 'Default App Has Already Been Configured.'
Trouble Creating Xmpp Muc Room: Code 503 (Service Unavailable)
#Import <Libxml/Tree.H> File Not Found After Xcode Update
Using Apple's Reachability Class in Swift
Where to Set Environment Variables for App
Uisearchcontroller Not Redisplaying Navigation Bar on Rotate
How to Set the Cornerradius of a Uistackview
How to Use Mbprogresshud with Swift
Import Framework in Swift Project, Xcode
Invalid Redeclaration in Auto Code Generate Nsmanagedobject Subclass Swift 3
Encryption with Rsa Public Key on iOS
Programmatically Creating Uilabel