Given the following scenario:
There is a UICollectionView containing UICollectionViewCells (naturally). Each UICollectionViewCell contains a UIButton with a target action associated with it.
Problem:
The UICollectionView does not scroll upon swipe/drag. The UIButtons instead intercept touches, and make it difficult to drag the UICollectionView.
Additionally:
The UIButtons are set to UIControlEventTouchUpInside
The UICollectionView is set to canCancelTouches = YES
**Why are the UIButtons inside UICollectionViewCells preventing the UICollectionView from responding to drag/swipe gestures? **
The reason that the UICollectionView doesn't scroll properly is because the UIButtons are intercepting and rerouting the responder chain.
Solution:
Remove the UIButtons from the UICollectionViewCell.
Instead use the delegate method for UICollectionViewDelegate :
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
Explanation:
When we added a UIButton to the UICollectionViewCell, we were thinking that the best way to capture a tap was to add a button to the cell. However, by adding the UIButton, we broke the responder chain.
We don't need the button inside the UICollectionViewCell, because the UICollectionViewCell already detects tap events with it's delegate method :
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
Use the provided method to detect taps on a collection cell, and replace the UIButtons with UIImageView-s or similar.
We don't need the event handing of a button when working with collection cells.
Related
I have a UITextField in one of my collection view cells. I want it to become first responder as soon as that cell is on screen.
So, I call [cell.textField becomeFirstResponder] in cellForItemAtIndexPath. However, this only works when the app is opened (the cell containing the uitextfield is already visible on app launch), if I scroll away from the cell and than scroll back to it, the textfield does not become first responder anymore.
What could be the problem?
EDIT: I am programatically scrolling the collection view to the cell containing the UITextField before calling becomeFirstResponder
It seems as the scrolling of the collection view made the collection view the first responder until the scrolling finished, so I made my textfield the first responder in this delegate method:
-(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
You should put the code in the
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
function as according to the class ref:
Tells the delegate that the specified cell is about to be displayed in the collection view.
I have a UICollectionView in every UITableViewCell of my UITableView.
The program should perform a segue there is a click on the UITableViewCell but the cell is clickable just out of the UICollectionView.
It is clickable just in the red portions.
Do you have any ideas?
You need to disable user interaction in each collection view:
In your storyboard uncheck here:
Or in your cellForRowAtIndexPath:
cell.collectionView.userInteractionEnabled = NO;
I put the iCarousel View in a table View and try to scroll the iCarousel, but the problem is it's not scrollable at all.
I can see iCarousel in the cell like following:
and I put iCarousel datasource and delegate in the tableView Controller, create a customer function to set the iCarousel datasource and delegate.
In the CustomTableViewCell I just define the setting delegate function:
- (void) setICarouselDataSourceDelegate: (id<iCarouselDelegate,iCarouselDataSource>)dataSourceDelegate {
self.carousel.dataSource = dataSourceDelegate;
self.carousel.delegate = dataSourceDelegate;
[self.carousel reloadData];
}
and in the MainTableView, I call the DataSourceDelegate in the
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
First of all iCarousel is not any standarad View ... you should put link of the control that you're using
Second it seems like iCarousel is uses UIScrollView and UITableView is also derived from UIScrollView It's never a good idea to put a scrollview inside another scrollview.
This might be the reason why your table view is not scrolling.... BTW are you talking about horizontal scrollign or vertical scrolling ?
Currently I am using the iCarousel in Table View cell and it scrolls easily.
Just add standard view to cell in Storyboard.
In IB mark the class of that view to iCarousel.
Furthermore !ENABLE! user interaction on that view. (Maybe because of that you can't scroll the content inside the cell)
Implement separate datasource & delegate for every cell. (It is more clear which data are loading in the cell and also the cell itself can handle the data. You just pass the data to cell and it handles it accordingly.) - But it depends on you if you want to let one class to handle two separate control datasources & delegates :-)
I'm trying to get a UIScrollView to work correctly inside of a UICollectionViewCell.
The custom cell is being loaded in via a xib file and is a subclass of UICollectionViewCell. I had problems getting other controls working, such as a button and a gesture recognizer since the UICollecitonView doesn't seem to be passing any touches to the cells, but I got around those with gesture recognizers on the UICollectionView itself. The one remaining issue I have is the UIScrollViews...
The UICollectionView scrolls horizontally, and the UIScrollView in the cells scroll vertically. I've tried using a UIPanGestureRecognizer to scroll them, but that seems to disable the UICollectionView's ability to scroll.
Anybody have any thoughts?
EDIT: Got it!
So I had converted to a collection view from a previous third party library we were using before iOS6. Turns out the problem was with the xib files we were using for the cells. With the library before, the cells were just subclasses of UIViews. I changed the classes to subclass UICollectionViewCell, and updated the Custom Class. Turns out this was not enough. In order for touches to get passed to the cells I needed to actually had to drag in a new UICollectionViewCell from the Object library, copy over all the subviews and reconnect the IBOutlets. After this, it worked!
I fixed this in my code by making sure resizing of the scroll view happens on main thread.
My collection view is using nsfetchedresultscontroller that is using block calls to refresh selected cells. On the first time a cell was selected the scrollview would not scroll. However if you clicked on another cell and clicked back it would work fine. The initial load of the cell seemed like size calc might not be where it needed to be on main thread to affect behavior.
-(UICollectionViewCell *) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"CustomCell" forIndexPath:indexPath];
dispatch_async(dispatch_get_main_queue(), ^{
// resizeScrollViewMethod should be where scrollview content size > scroll view frame.
[cell resizeScrollViewMethod];
});
return cell;
}
- (void) resizeScrollViewMethod {
//Do your scrollview size calculation here
}
No problem with UISCrollView in UICollectionViewCell. Use StoryBoard and you'll scroll OK.
UIScrollView overlay UICollectionViewCell, so that didSelect work only when tap outside ScrollView and inside Cell (scrollView.frame < cell.frame).
If you want to implement tap or other gesture, just add it to UIScrollView in awakeFromNib
Refer code:
https://github.com/lequysang/github_zip/blob/master/CollectionViewWithCellScrollViewStoryBoard.zip
I've subclassed UITableViewCell to display a UIImage and two UILabel subviews. In the view controller for the table view, in the method cellForRowAtIndexPath: I've enabled an accessory view via setAccessoryType:UITableViewCellAccessoryDetailDisclosureButton.
Cells display correctly.
When I tap on the accessory disclosure button I want to replace the two label subviews with two different label subviews. My approach was the following:
In the subclassed UITableViewCell, inside layoutSubviews, create the
CGRects for the "alternate" labels, position them in the same
places as the two "original" label and hide them via setAlpha:;
When the disclosure button is tapped swap out the set of two
label by adjusting their respective alphas.
The problem is I can't figure out what logic in layoutSubviews I'd use to know whether the accessory button has been tapped. I see that in the view controller accessoryButtonTappedForRowWithIndexPath: is called when that button is tapped and from there it seems like I would call layoutSubviews but can't figure out how to use that fact to accomplish what I'm trying to do.
Am I going about this all wrong? Instead of hiding/showing CGRects with alpha should I simply be creating another subclass of UITableViewCell?
When I tap on the accessory disclosure button I want to replace the two UILabel subviews with two different UILabel subviews.
I'll do the following. Create a public method in your UITableViewCell subclass like the following:
- (void)changeContentForCell;
In this method you could set the contentView as you prefer.
Then in your view controller implement
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
CustomCell* cCell = (CustomCell*)[tableView cellForRowAtIndexPath:indexPath];
[cCell changeContentForCell];
}
This is a simple example for change the content. In my opinion you don't have to use layoutSubviews to add views.
Leave this logic in changeContentForCell and then call setNeedsLayout to change your layout. Maybe you could have a variable that tracks the state for your cell: normal state or modified state.
Hope it helps.