I have a UITableView where each UITableViewCell contains a UICollectionView. The UICollectionView has UICollectionViewCells.
My problem is: Some of these UICollectionViewCells should react to tap-gestures, others should forward the event to the UITableViewCell (so it triggers displaying of the detail-view for that UITableViewCell).
I've been studying the apple-docs and several questions here but I can't get it to work.
(I think it should be possible to solve this generally, but just in case: Each UICollectionViewCell contains an UIImageView.)
Suggestions are very appreciated.
If I understand you correctly, you can do it like this:
Set cell.userInteractionEnabled = NO on the cells you don't want to handle events.
Override hitTest in your UICollectionView with this method:
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *hitTest = [super hitTest:point withEvent:event];
return hitTest == self ? nil : hitTest;
}
So tapping anywhere outside of a cell with user interaction enabled, super returns the collection view and we return nil, causing the table view cell to handle the event.
Why don't you let only the uicollectionview cell's handle the taps and then in the callback determine what action to take. For some you could do what you do now when tapping the cell, for others whatever you want.
Related
I have a Custom UITableView Cell as xib.
I have taken an Scroll View inside it.
I Know how to set the delegate but I have confusion.Their is two of doing this.
I don't knw which is best and How to decide which way I have to choose.
1 Way : To set Delegate To Files Owner
2 Way : setting Delegate to UITableViewCell
In a tableviewcell the delegate of scrollview will always be set to UITableViewCell
That means your second step will work .
Let me know if you find any difficulty.
The choice depends on what the delegate function for the inner scroll view must do. It is simpler to point the delegate to the custom cell and handle the inner scrolling events there.
But if handling that inner scrolling requires a lot of data and logic from the view controller, then point the delegate to the vc. To make that work, we'll need to know that the scroll event was from an inner scroll view, not the table, and we probably need the row where the scrolling happened, so:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
// if the table view's delegate points here (likely), then to distinguish...
if (scrollView != self.tableView) {
// one of the scroll views in the table, but which one?
NSIndexPath = [self indexPathContainingView:scrollView];
// here we know that horizontal scrolling happened on indexPath.row
}
}
// return the indexPath of the tableView cell containing a view
- (NSIndexPath *)indexPathContainingView:(UIView *)view {
while(view && ![view isKindOfClass:[UITableViewCell self]])
view = view.superview;
return [self.tableView indexPathForCell:(UITableViewCell *)view];
}
I have a non scrollable UITableView inside an UIScrollView. And I'm having the problem that when I touch a row, the callback didSelectRowAtIndexPath: is not being called on the first tap, but after the first tap everithing works.
A few considerations:
After the first tap, the table view works normally, every tap works in every cell.
This happens just after I scroll the UIScrollView. If I don't scroll the UIScrollView, this never happens.
I have overriden the UIScrollView's touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view and the event does pass throw here, the view is a UITableViewCellContentView effectively.
I just don't know why the event is not been sent to the UITableView on the first time, and on the following ones it does.
If you have UIScrollView that contains vertical content and UITableView as part of this content, you must at least disable scrolling on UITableView - otherwise it's confusing for the user when he will scroll your mainView and when tableView, and also confusing for the framework because it's not clear where to send panning gestures.
As a rule of thumb - you should avoid putting table views inside scrollViews, unless you really know what you're doing.
Please disable scrolling of your table view and check the datasource and delegate are connected to your table view. If not follow the bellow code
#interface myClass ()<UITableViewDataSource, UITableViewDelegate>
- (void)viewDidLoad {
[super viewDidLoad];
self.myTableView.scrollEnabled = NO;
self.myTableView.delegate = self;
self.myTableView.dataSource = self;
}
I overrode hitTest, and that works just fine. I want it to behave as if I hadn't overridden this method under certain conditions, and that's where the problem lies.
I'm using a subclassed UICollectionView to render cells over a MKMapView using a custom UICollectionViewLayout implementation. I needed to override hitTest in the UICollectionView subclass so that touch events can be passed to the mapView and it can be scrolled. That all works fine.
I have a toggle mechanism which animates between my UICollectionViewLayout (map) to a UICollectionViewFlowLayout (animate items on a map to a grid format). This works good too, but when I'm showing the flow layout, I want the user to be able to scroll the UICollectionView like a normal one (act as though hitTest isn't overridden). I can't figure out what to return in hitTest to have it's default behavior.
-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
if(self.tapThrough == YES){
NSArray *indexPaths = [self indexPathsForVisibleItems];
for(NSIndexPath *indexPath in indexPaths){
UICollectionViewCell *cell = [self cellForItemAtIndexPath:indexPath];
if(CGRectContainsPoint(cell.frame, point)){
return cell;
}
}
return nil;
} else {
return ???
}
}
I've tried returning a number of things. self, self.superview, etc... Nothing get it to behave normally (I cannot scroll the cells up and down).
If you want the normal behaviour of your hit test:
return [super hitTest:point withEvent:event];
This will return what the hit test usually returns when it is not overridden.
I have a custom UITableViewCell i.e. I subclassed UITableViewCell class
when populating each cell (or row) of the uitableview, i am creating my custom UITableViewCell, which composes of an image and some labels.
now when I override the following method in my custom 'UITableViewCell' class,
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"CLICKED CLICKED CELL CLICKED CLICKED");
[super touchesBegan:touches withEvent:event];
}
it never gets called if i click on the custom views i added to the my custom uitableviecell, but it is fine (event triggered) when i click on the region where there is no custom view on top of it.
my goal is simple, i want to detect any touches in each row (uitableviewcell) in the uitableview.
I have experienced a similar problem today, I was unable to select the cell, since it had a custom UIView with a scrollView on it. Try setting userInteractionIsEnabled = false on your subviews of your UIView.
plz try to override this method
- (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event {}
This is what I'm trying to achieve:
I want a UITextField that is in UITableViewCell to become first responder only when the cell touched. I would like the text field to become the first responder only when I set it to first responder in the method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath`
Any idea how I can achieve this? When the textfield is touched directly, tableView:didSelectRowAtIndexPath: is never called.
Thanks in advance.
I guess, u have a custom UITableViewCell. In that u could have a UITextField member. Right?
In the custom cell class, override the method,
- (void)setSelected:(BOOL)selected animated:(BOOL)animated:
In that , if selected == YES, then make the text field as first responder. Else , resign the first responder.
Let an object be the delegate of the UITextField and implement textFieldShouldBeginEditing:; return NO if the cell hasn't been selected. (You might be able to always return NO from this method, if calling becomeFirstResponder directly bypasses the check.)
For having the textField become the first responder when a uitableviewcell is selected, use your textField as your property, and call [self.textField1 becomeFirstResponder];
Note: You will need as many properties as your the number of UITableViewCells as each cell has a textField.
When a textField is touched, the compiler will not know that the corresponding row got selected.
For this you will need to use tags, such as textField.tag == 0 for the first textField, textField.tag ==1 for the second TextField and so on. And in the textFieldDidBeginEditing you should check for the tag, and then link that value with the corresponding row selected.
Did any of these make sense ? :)
First, you need a custom table cell, your own subclass of UITableViewCell. In that implementation, you need to implement hitTest: to determine where the touch occurred. In that method you can determine if the touch was in fact inside the rect of your UITextField, and if it was, make it the first responder. Here's an example from some code I wrote for a project:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if (self.editing) {
if ([nickname pointInside:[self convertPoint:point toView:nickname] withEvent:nil])
return [nickname hitTest:[self convertPoint:point toView:nickname] withEvent:event];
return [super hitTest:point withEvent:event];
}
return [self contentView];
}
The attribute nickname, in this case, was a UITextField inside the custom UITableViewCell.
The condition around self.editing may or may not be relevant to your application. The idea here is show you how hitTest: might be used, in general.