Where to Highlight Uicollectionviewcell: Delegate or Cell

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



Leave a reply



Submit