Why UICollectionView's UICollectionViewCell is

2019-02-02 20:26发布

问题:

I have a UICollectionView that is made up of a custom UICollectionViewCell subclass. The cell's are displaying correctly and are responding correctly to user's touches by firing this method:

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath

However, I am of the understanding that when a user touches the cell, it should highlight (in blue) and then the highlight should go away when the user lifts their finger. This is not happening. Any thoughts on why?

Here is some relevant code:

In the UICollectionView's datasource:

@implementation SplitCheckViewCollection

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
    static NSString *cellIdentifier = @"ReceiptCellIdentifier";
    SplitCheckCollectionCell *cell = (SplitCheckCollectionCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
    cell.cellName.text = [NSString stringWithFormat:@"%@%i",@"#",indexPath.row+1];

    return cell;
}

In the UICollectionViewCell's implementation:

@implementation SplitCheckCollectionCell

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        NSArray *arrayOfViews = [[NSBundle mainBundle] loadNibNamed:@"SplitCheckCollectionCell" owner:self options:nil];

        if ([arrayOfViews count] < 1) {
            return nil;
        }

        if (![[arrayOfViews objectAtIndex:0] isKindOfClass:[UICollectionViewCell class]]) {
            return nil;
        }

        self = [arrayOfViews objectAtIndex:0];    
    }
    return self;
}

回答1:

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.



回答2:

As SAE said,you have to do it yourself in a subclass. The other snag I just ran into is that when tapping a cell, it was receiving the highlight and redrawing if the cell was pressed and held. However, if tapped fast the redraw never happened.

I had created the cell in storyboard and the collection view has 'delays content touches' ticked as a default. I unticked this and it displayed instantly the finger touched the screen.

I am using a custom draw routine which checks the isHighlighted value. You also need to override setHighlighted in the custom cell as below or the draw routine never gets called.

-(void)setHighlighted:(BOOL)highlighted
{
    [super setHighlighted:highlighted];
    [self setNeedsDisplay];
}


回答3:

There are 2 delegate methods you should to implement:

- (void)collectionView:(UICollectionView *)colView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath;
- (void)collectionView:(UICollectionView *)colView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath;

Full code of highlighting collection view cell with animation:

- (void)collectionView:(UICollectionView *)colView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath {
     UICollectionViewCell* cell = [colView cellForItemAtIndexPath:indexPath];
     //set color with animation
    [UIView animateWithDuration:0.1
                      delay:0
                    options:(UIViewAnimationOptionAllowUserInteraction)
                 animations:^{
                     [cell setBackgroundColor:[UIColor colorWithRed:232/255.0f green:232/255.0f blue:232/255.0f alpha:1]];
                 }
                 completion:nil];
 }

- (void)collectionView:(UICollectionView *)colView  didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell* cell = [colView cellForItemAtIndexPath:indexPath];
    //set color with animation
    [UIView animateWithDuration:0.1
                      delay:0
                    options:(UIViewAnimationOptionAllowUserInteraction)
                 animations:^{
                     [cell setBackgroundColor:[UIColor clearColor]];
                 }
                 completion:nil ];
}


回答4:

You need to implement the UICollectionViewDataSource if you want to have Highlight and Unhighlight effect upon touch and release touch

here is the sample code

#pragma mark - UICollectionView Datasource

 - (void)collectionView:(UICollectionView *)colView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath {
 UICollectionViewCell* cell = [colView cellForItemAtIndexPath:indexPath];
 cell.contentView.backgroundColor = [UIColor colorWithRed:235/255.0f green:236/255.0f blue:237/255.0f alpha:.5];
 }

 - (void)collectionView:(UICollectionView *)colView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath {
 UICollectionViewCell* cell = [colView cellForItemAtIndexPath:indexPath];
 cell.contentView.backgroundColor = nil;
 }


回答5:

You can get a hilight to draw by adding these lines to your UICellView's setup.

UIView* selectedBGView = [[UIView alloc] initWithFrame:self.bounds];
selectedBGView.backgroundColor = [UIColor redColor];
self.selectedBackgroundView = selectedBGView;

From "Managing the Visual State for Selections and Highlights"... Collection views support single-item selection by default and can be configured to support multiple-item selection or have selections disabled altogether. The collection view detects taps inside its bounds and highlights or selects the corresponding cell accordingly. For the most part, the collection view modifies only the properties of a cell to indicate that it is selected or highlighted; it does not change the visual appearance of your cells, with one exception. If a cell’s selectedBackgroundView property contains a valid view, the collection view shows that view when the cell is highlighted or selected.



回答6:

As SAE points out you will have to manually do it in the cell on highlight. Easiest way I found is to use the tableview didHighlightRowAtIndexPath and didUnhighlightRowAtIndexPath methods which sets a bool "highlighted" in your UICollectionCell instance and then override that property in a subclassed UICollectionCell class. The beauty of this is that the animation is already there for you. You can also do the same in a UITableView/UITableViewCell situation.

So in your UICollectionView using the UICollectionViewDelegate method:

func collectionView(collectionView: UICollectionView, didHighlightItemAtIndexPath indexPath: NSIndexPath) {
    collectionView.selectItemAtIndexPath(indexPath, animated: true, scrollPosition: UICollectionViewScrollPosition.None)
}

func collectionView(collectionView: UICollectionView, didUnhighlightItemAtIndexPath indexPath: NSIndexPath) {
    collectionView.deselectItemAtIndexPath(indexPath, animated: true)
}

Then in your UICollectionViewCell subclass add this:

override var highlighted:Bool{
    didSet{
        println("Highlighted is set \(highlighted)")
        if(highlighted == true){
            self.backgroundColor = UIColor.redColor()
        }else{
            self.backgroundColor = UIColor.blueColor()
        }
    }
}


回答7:

you can try this code :

- (void)collectionView:(UICollectionView *)colView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell* cell = [colView cellForItemAtIndexPath:indexPath];
cell.contentView.backgroundColor = [UIColor blueColor];
}

and

- (void)collectionView:(UICollectionView *)colView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell* cell = [colView cellForItemAtIndexPath:indexPath];
cell.contentView.backgroundColor = nil;
}


回答8:

We can create our own highlight and unhighlight effect on collectionView cell by adding and removing a temporary view with some background color as follows:

 -(void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath

    {

         UICollectionViewCell *collectionViewCell = (UICollectionViewCell *)  
                            [collectionView cellForItemAtIndexPath:indexPath];

     UIView *tapHighlightView = (UIView*)[collectionViewCell.contentView 
                                  viewWithTag:10];

     if (!tapHighlightView) {

                tapHighlightView = [[UIView alloc] 
                        initWithFrame:collectionViewCell.contentView.frame];
                tapHighlightView.backgroundColor =[UIColor blackColor alpha:0.4];
                tapHighlightView.tag = 10;
                [collectionViewCell.contentView addSubview:tapHighlightView];
            }
    }

    -(void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath{

        UICollectionViewCell *collectionViewCell = (UICollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath];
        UIView *tapHighlightView = (UIView*)[collectionViewCell.contentView viewWithTag:10];
        if (tapHighlightView != nil) {
            [tapHighlightView removeFromSuperview];
        }
    }


回答9:

If you want to change the visuals you can set the cell to selected on the didHighlightItemAtIndexPath and deselect on didHighlightItemAtIndexPath like the following:

- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
    return YES;
}

- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
    [collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:NO];
}

- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
    [collectionView deselectItemAtIndexPath:indexPath animated:YES];
}