可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
So I have a main object that has many images associated with it. An Image is also an object.
Say you have a collection view controller, and in that controller you have
cellForItemAtIndexPath
well based on the main object, if it has the current image associated with it I want to set selected to true. But I want the user to be able to "un-select" that current cell at any time to remove its association with the main object.
I find that if you set "selected to true" - if there is an relation between the main object and image in cellForItemAtIndexPath
, de-selection is no longer an option.
in
didDeselectItemAtIndexPath
and
didSelectItemAtIndexPath
I test with a log to see if they are called. If a cell is set to selected - nether gets called, but If I never set a cell to selected in cellForItemAtIndexPath
I can select and deselect all I want.
Is this the intended way a collection view is supposed to work? I read the docs and it does not seem to talk about this being so. I interpret the docs to mean it works the way a table view cell would. with a few obvious changes
This also shows the controller is set up correct and is using the appropriate delegate methods.... hmmmm
回答1:
I had the same issue, ie. setting cell.selected = YES
in [UICollectionView collectionView:cellForItemAtIndexPath:]
then not being able to deselect the cell by tapping on it.
Solution for now: I call both [UICollectionViewCell setSelected:]
and [UICollectionView selectItemAtIndexPath:animated:scrollPosition:]
in [UICollectionView collectionView:cellForItemAtIndexPath:]
.
回答2:
Do you have a custom setSelected
method in your Cell class? Are you calling [super setSelected:selected]
in that method?
I had a mysterious problem where, I was using multiple selection, I could not deselect cells once they were selected. Calling the super method fixed the problem.
回答3:
I had a Deselect issue with UICollectionView
and I found that I was not allowing multiple selection on collectionView. So when I was testing I tried always on the same cell and if single selection is ON you can't Deselect a cell already selected.
I had to add:
myCollectionView.allowsMultipleSelection = YES;
回答4:
This is kind of old but, since I encounter the same issue using swift I will add my answer.
When using:
collectionView.selectItemAtIndexPath(indexPath, animated: true, scrollPosition: [])
The cell didn't get selected at all. But when using:
cell.selected = true
It did get selected but I wasn't able to select/deselect the cell anymore.
My solution (use both methods):
cell.selected = true
collectionView.selectItemAtIndexPath(indexPath, animated: true, scrollPosition: .None)
When this two methods are called in:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
It worked perfectly!
回答5:
I don't know why UICollectionView
is so messy like this compared to UITableViewController
...
A few things I found out.
The reason why setSelected:
gets called multiple times is because of the sequence methods get called. The sequence is very similar to that of UITextFieldDelegate
methods.
The method collectionView:shouldSelectItemAtIndexPath:
is called before the collectionView
actually selects the cell because it's actually asking "should it be selected"?
collectionView:didSelectItemAtIndexPath:
is in fact called after the collectionView
selects the cell. Hence the name "did select."
So this is what is happening in your case (and my case, and I had to wrestle hours over this).
A selected cell is touched again by the user to deselect. shouldSelectItemAtIndexPath:
is called to check whether the cell should be selected. The collectionView
selects the cell and then didSelectItemAtIndexPath
is called. Whatever you do at this point is after the the cell's selected
property is set to YES
. That's why something like cell.selected = !cell.selected
won't work.
TL;DR - Have your collectionView
deselect the cell in the delegate method collectionView:shouldSelectItemAtIndexPath:
by calling deselectItemAtIndexPath:animated:
and return NO
.
Short example of what I did:
- (BOOL)collectionView:(OPTXListView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath {
NSArray *selectedItemIndexPaths = [collectionView indexPathsForSelectedItems];
if ([selectedItemIndexPaths count]) {
NSIndexPath *selectedIndexPath = selectedItemIndexPaths[0];
if ([selectedIndexPath isEqual:indexPath]) {
[collectionView deselectItemAtIndexPath:indexPath animated:YES];
return NO;
} else {
[collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
return YES;
}
} else {
[collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
return YES;
}
}
回答6:
Here is my answer for Swift 2.0.
I was able to set the following in viewDidLoad()
collectionView.allowsMultipleSelection = true;
then I implemented these methods
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.cellForItemAtIndexPath(indexPath) as! MyCell
cell.toggleSelected()
}
func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.cellForItemAtIndexPath(indexPath) as! MyCell
cell.toggleSelected()
}
finally
class MyCell : UICollectionViewCell {
....
func toggleSelected ()
{
if (selected){
backgroundColor = UIColor.orangeColor()
}else {
backgroundColor = UIColor.whiteColor()
}
}
}
回答7:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.cellForItemAtIndexPath(indexPath)
if cell?.selected == true{
cell?.layer.borderWidth = 4.0
cell?.layer.borderColor = UIColor.greenColor().CGColor
}
}func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.cellForItemAtIndexPath(indexPath)
if cell?.selected == false{
cell?.layer.borderColor = UIColor.clearColor().CGColor
}
}
Simple Solution i found
回答8:
Living in the age of iOS 9, there are multiple things to check here.
- Check do you have
collectionView.allowsSelection
set to YES
- Check do you have
collectionView.allowsMultipleSelection
set to YES
(if you need that ability)
Now comes the fan part.
If you listen to Apple and set backgroundColor
on the cell.contentView
instead of cell
itself, then you have just hidden its selectedBackgroundView
from ever being visible. Because:
(lldb) po cell.selectedBackgroundView
<UIView: 0x7fd2dae26bb0; frame = (0 0; 64 49.5); autoresize = W+H; layer = <CALayer: 0x7fd2dae26d20>>
(lldb) po cell.contentView
<UIView: 0x7fd2dae22690; frame = (0 0; 64 49.5); gestureRecognizers = <NSArray: 0x7fd2dae26500>; layer = <CALayer: 0x7fd2dae1aca0>>
(lldb) pviews cell
<MyCell: 0x7fd2dae1aa70; baseClass = UICollectionViewCell; frame = (0 0; 64 49.5); clipsToBounds = YES; hidden = YES; opaque = NO; layer = <CALayer: 0x7fd2dae1ac80>>
| <UIView: 0x7fd2dae26bb0; frame = (0 0; 64 49.5); autoresize = W+H; layer = <CALayer: 0x7fd2dae26d20>>
| <UIView: 0x7fd2dae22690; frame = (0 0; 64 49.5); gestureRecognizers = <NSArray: 0x7fd2dae26500>; layer = <CALayer: 0x7fd2dae1aca0>>
| | <UIView: 0x7fd2dae24a60; frame = (0 0; 64 49.5); clipsToBounds = YES; alpha = 0; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x7fd2dae1acc0>>
| | <UILabel: 0x7fd2dae24bd0; frame = (0 0; 64 17.5); text = '1'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fd2dae240c0>>
| | <UILabel: 0x7fd2dae25030; frame = (0 21.5; 64 24); text = '1,04'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fd2dae25240>>
(lldb) po cell.contentView.backgroundColor
UIDeviceRGBColorSpace 0.4 0.4 0.4 1
So if you want to use selectedBackgroundView (which is the one being turned on/off with cell.selected
and selectItemAtIndexPath...
) then do this:
cell.backgroundColor = SOME_COLOR;
cell.contentView.backgroundColor = [UIColor clearColor];
and it should work just fine.
回答9:
I don't know that I understand the problem, but selected status is set per cell and would include all subviews within the cell. You don't explain what you mean by "a main object has many images associated with it." Associated as in subviews? Or what kind of association exactly do you mean?
It sounds like a design problem to me. Perhaps you need a UIView subclass that contains whatever associated objects you need to have; that subclass can then be set as the content view. I do this, for example, where I have an image, a description, and a sound recording related to the image. All are defined in the subclass and then each of these subclasses becomes a content view for a single cell.
I've also used an arrangement to related images to a folder which contains them. Under this set up, folders and images each have a subclass and either one might be attached to a cell as a content view (these are stored in core data as a single entity).
Perhaps you can further explain your problem?
回答10:
Have you looked at:
- (BOOL)collectionView:(PSTCollectionView *)collectionView shouldDeselectItemAtIndexPath:(NSIndexPath *)indexPath;
Please state your problem more clearly and perhaps we can get to the bottom of it. I've just spent some time with UICollectionView.
I think your problem may be stemming from the confusion that if you set cell.selected = YES
programmatically, the reason didSelectItemAtIndexPath:
is not getting called is because that is only used when the collectionView itself is responsible for the cell's selection (eg. via a tap).
回答11:
I'm using a custom cell subclass, for me I just had to set self.selected = false
in prepareForReuse()
in the subclass.
回答12:
Cell selection and deselection is best handled by setting a backgroundView and a selected background view. I recommend making sure that both of these views' frames are set correctly in the layoutSubviews method (if you set the selected and background view via IB).
Don't forget to set your contentView's (if you have one) background color to clear so the correct background view shows through.
Never set the cell's selection directly (i.e. via cell.selected = YES), use the methods designed for this purpose in the collection view. It is clearly explained in the documents, although I will agree the information is somewhat fragmented across guides.
You should not need to poke into a cell's background colors directly in your collectionView datasource.
Also, as a final note, don't forget to call [super prepareForReuse] and [super setSelected:selected] if you are implementing these in your cell's class, as you might be preventing the cell's superclass from doing the cell selection.
Hit me up if you need further clarification on this subject.
回答13:
When calling both [UICollectionViewCell setSelected:]
and [UICollectionView selectItemAtIndexPath:animated:scrollPosition:]
in [UICollectionView collectionView:cellForItemAtIndexPath:]
doesn't work try calling them inside a dispatch_async(dispatch_get_main_queue(), ^{});
block.
That's what finally fixed it for me.