问题
I have a UICollectionView that I have created programmatically. I would like for the collection view to behave in the following way:
1. User touches cell
2. Cell background color changes
3. User releases touch
4. Cell background color changes
This should be a quick color change that happens just before the selector related to the tap action is executed in which the viewcontroller containing the collection view is popped off the stack.
I have been looking at this question: UICollectionView cell change background while tap
in which there is the following summary of methods to use for this purpose:
// Methods for notification of selection/deselection and highlight/unhighlight events.
// The sequence of calls leading to selection from a user touch is:
//
// (when the touch begins)
// 1. -collectionView:shouldHighlightItemAtIndexPath:
// 2. -collectionView:didHighlightItemAtIndexPath:
//
// (when the touch lifts)
// 3. -collectionView:shouldSelectItemAtIndexPath: or - collectionView:shouldDeselectItemAtIndexPath:
// 4. -collectionView:didSelectItemAtIndexPath: or -collectionView:didDeselectItemAtIndexPath:
// 5. -collectionView:didUnhighlightItemAtIndexPath:
I am assuming I only need to implement one of the above methods from 'when touch begins' and 'when touch ends.' But no matter what I do, it appears that a background color changes and then remains changed. Here is an example of something I attempted which did not work:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
//pop vc
}
- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell* cell = [collectionView cellForItemAtIndexPath:indexPath];
cell.contentView.backgroundColor = [UIColor redColor];
}
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
cell.contentView.backgroundColor = [UIColor greenColor];
}
This results in the cell background color being changed only to red. I also looked at this question: UICollectionView Select and Deselect issue and tried implementing [UICollectionView selectItemAtIndexPath:animated:scrollPosition:] and calling it inside of didSelectItemAtIndexPath, but this did not work either. Collection view data source and delegate are set.
回答1:
The problem is that you are changing the color on highlight and changing it back on deselect instead that on unhighlight
You should simply change this:
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
cell.contentView.backgroundColor = [UIColor greenColor];
}
to this:
- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
cell.contentView.backgroundColor = [UIColor greenColor];
}
Also, if you don't want to wait a bit before getting your highlight happen you should set the delaysContentTouches
property of the collection view to NO
Edit: also ensure that you call
[collectionView deselectItemAtIndexPath:indexPath animated:NO];
inside the -didSelectItemAtIndexPath method
回答2:
Swift 3 version
Add the following two methods to your view controller class:
// change background color when user touches cell
func collectionView(_ collectionView: UICollectionView, didHighlightItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
cell?.backgroundColor = UIColor.red
}
// change background color back when user releases touch
func collectionView(_ collectionView: UICollectionView, didUnhighlightItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
cell?.backgroundColor = UIColor.green
}
See here for help in setting up a basic collection view in Swift.
回答3:
Edit: Answer in Swift 3
var selectedIndex = Int ()
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
cell.backgroundColor = selectedIndex == indexPath.row ? UIColor.green : UIColor.red
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
{
selectedIndex = indexPath.row
self.yourCollctionView.reloadData()
}
回答4:
Here is my solution. And I'm sure it really works.
I provide three methods to highlight a cell (selectedBackgroundView, tint cell.contentView
and tint a special area).
How to use:
1. just inherit BaseCollectionViewCell
and do nothing;
2. inherit and set specialHighlightedArea = UIView()
, and contentView.addSubView(specialHighlightedArea)
, then layout it or add constraint to use Auto Layout;
3. if you don't need highlight effect, just write a method named 'shouldHighlightItemAtIndexPath' defined by UICollectionViewDelegate
and make it return false, or set cell.shouldTintBackgroundWhenSelected = false
and set specialHighlightedArea = nil
and remove it from superView.
/// same with UITableViewCell's selected backgroundColor
private let highlightedColor = UIColor(rgb: 0xD8D8D8)
/// you can make all your collectionViewCell inherit BaseCollectionViewCell
class BaseCollectionViewCell: UICollectionViewCell {
/// change it as you wish when or after initializing
var shouldTintBackgroundWhenSelected = true
/// you can give a special view when selected
var specialHighlightedArea: UIView?
// make lightgray background display immediately(使灰背景立即出现)
override var isHighlighted: Bool {
willSet {
onSelected(newValue)
}
}
// keep lightGray background until unselected (保留灰背景)
override var isSelected: Bool {
willSet {
onSelected(newValue)
}
}
func onSelected(_ newValue: Bool) {
guard selectedBackgroundView == nil else { return }
if shouldTintBackgroundWhenSelected {
contentView.backgroundColor = newValue ? highlightedColor : UIColor.clear
}
if let area = specialHighlightedArea {
area.backgroundColor = newValue ? UIColor.black.withAlphaComponent(0.4) : UIColor.clear
}
}
}
extension UIColor {
convenience init(rgb: Int, alpha: CGFloat = 1.0) {
self.init(red: CGFloat((rgb & 0xFF0000) >> 16) / 255.0, green: CGFloat((rgb & 0xFF00) >> 8) / 255.0, blue: CGFloat(rgb & 0xFF) / 255.0, alpha: alpha)
}
}
回答5:
Simple binary logic solution. Works with Swift 3 and 4:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt
indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! CategoryCell
let lastCellColor = cell.backgroundColor
if cell.isSelected {cell.backgroundColor = .green} else {cell.backgroundColor = lastCellColor}
}
来源:https://stackoverflow.com/questions/23392485/change-background-of-uicollectionview-cell-on-tap