UITableViewCell select doesn't working in objective c - ios

I am new in Objective C and have a issue for using custom UITableViewCell.
I use touchesBegan in the my custom tableviewcell like following:
#import "UserListTableViewCell.h"
#implementation UserListTableViewCell
#synthesize userTableViewCellView, cellIndex;
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
... .. ...
}
-(void) touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
... ... ...
}
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
... ... ...
}
Then after that I can't use function didSelectRowAtIndexPath{}.
How can I use TableView selection even though use touchesBegan method.
Please advance me if you can fix this issue.
Thanks.

If didSelectRowAtIndexPath() isn't working properly after using touchesBegan you may want to check if you have [super touchesBegan] in your custom cell method. Like this:
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
... .. ...
}
.....
Hope it helps you!

This situation occurs because method
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
}
catches events, but doesn't send them further up the responder chain. As #Daniel mentioned above, if you add call to super like this:
[super touchesBegan:touches withEvent:event];
events will be sent further to - (void)didSelectRowAtIndexPath method.

Related

Table view cell (containing horizontal scroll view) not clickable [duplicate]

I have a tableview with 8 custom cells. in the 8th cell I added a scrollView with paging enabled so I can show page 1 and page 2 (or 3, 4... 10) without have a very high cell.
The problem is with the scrollView I can't use didSelectRowAtIndexPath because the cell is behind the scrollView so I'm trying to detect scrollView tap (not swipe).
I played with touchesBegan and touchesEnded but they are never called (I know touches work with UIView only, but maybe.....)
Any help is very appreciated.
Thanks,
Max
There is a trick Apple recommends to use in this case, in theirs WWDC 2014 session "Advanced scrollviews" (See Demo starting from 8:10):
[cell.contentView addSubview:_scrollView];
[_scrollView setUserInteractionEnabled:NO];
[cell.contentView addGestureRecognizer:_scrollView.panGestureRecognizer];
That's all what needs to be done, no need to override touchesBegan:, touchesMoved: and others.
I used solution based on overriding of touchesBegan:, touchesMoved:, touchesEnded: and touchesCancelled: previously, but sometimes it caused a weird behaviour: when select a certain cell, method -tableView:didSelectRowAtIndexPath: was called for cell with different indexPath.
Solution from Apple has no side effects so far and looks more elegant.
There is also an elegant resolution:
Create a SubClass from UIScrollView and override the following methods
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[[self superview]touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[[self superview]touchesMoved:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[[self superview]touchesCancelled:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[[self superview]touchesEnded:touches withEvent:event];
}
Passing every touch to the superview of the scroll view and then the didSelectRowAtIndexPath will be called.
Solved subclassing both uitableviewcell and uiscrollview.
It worked for my needs. Hope it can help.
Max
myScrollView.h
#import <UIKit/UIKit.h>
#interface myScrollView : UIScrollView {
}
#end
myScrollView.m
#import "myScrollView.h"
#implementation myScrollView
- (id)initWithFrame:(CGRect)frame {
return [super initWithFrame:frame];
}
- (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event
{
NSLog(#"touch scroll");
// If not dragging, send event to next responder
if (!self.dragging)
[self.nextResponder touchesEnded: touches withEvent:event];
else
[super touchesEnded: touches withEvent: event];
}
myCell.h
#import <UIKit/UIKit.h>
#interface myCell : UITableViewCell {
}
#end
myCell.m
#import "myCell.h"
#implementation myCell
- (id)initWithFrame:(CGRect)frame {
return [super initWithFrame:frame];
}
- (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event
{
NSLog(#"touch cell");
// If not dragging, send event to next responder
[super touchesEnded: touches withEvent: event];
}
RootViewController.h
#import <UIKit/UIKit.h>
#class myCell;
#class myScrollView;
#interface RootViewController : UITableViewController {
myCell *cell;
myScrollView *scrollView;
}
#end
RootViewController.m
#pragma mark -
#pragma mark Table view data source
// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 3;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
// my custom cell
cell = [[myCell alloc] init];
if (cell == nil) {
cell = [[[myCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// the custom scroll view
scrollView = [[myScrollView alloc] initWithFrame:cell.frame];
scrollView.contentSize = CGSizeMake(640, 40);
[cell.contentView addSubview:scrollView];
//something to add in scrollView
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 150, 20)];
label.text = #"some text";
[scrollView addSubview:label];
// Configure the cell.
return cell;
}
The selected answer is correct, but I updated the code based on a bug I was getting.
In the subclassed scroll view add the following code.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if (self.dragging) {
[super touchesMoved:touches withEvent:event];
} else {
if ([self.delegate isKindOfClass:[UITableViewCell class]]) {
[(UITableViewCell *)self.delegate touchesCancelled:touches withEvent:event];
}
[self.superview touchesMoved:touches withEvent:event];
}
}
If your self.delegate is not the UITableViewCell, than replace that property with a property to your cell.
The cell needs to retrieve the cancel touch event during movement to prevent the undesired results. It can be easily reproducible as follows.
Highlight the cell (assuming the scroll view is over the whole cell, if not highlight the scroll view)
While the cell is highlighted, drag the table view
Select any other cell and now the previously highlighted cell will retrieve the didSelectCell state
Another point to mention is that order matters! If the self.delegate is not called before the self.superview then the highlighted state wont happen.
I found the simplest solution for my needs:
subclass UIScrollView touchesEnded method and post a notification.
In the UITableview add an observer in viewdidAppear (remove it in viewdiddisappear) to call a function that call tableview didSelectRowForIndexPath.
Something like this (swift version)
// myScrollView.swift
import UIKit
class myScrollView: UIScrollView {
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
NSNotificationCenter.defaultCenter().postNotificationName("selectTVRow", object: nil)
}
}
In your tableView:
// ItemsList.swift
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "selectFourthRow", name: "selectTVRow", object: nil)
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
NSNotificationCenter.defaultCenter().removeObserver(self, name: "selectfourthrow", object: nil)
}
func selectFourthRow() {
let rowToSelect:NSIndexPath = NSIndexPath(forRow: 4, inSection: 0);
self.tableView(self.tableView, didSelectRowAtIndexPath: rowToSelect);
}
/*
.... rest of your tableview Datasource and Delegate methods...
numberOfSectionsInTableView, numberOfRowsInSection, cellForRowAtIndexPath
*/

CGPoint of tap on UITableViewCell using touchesBegan

I am needing the CGPoint of a tap on my UITableViewCell. To do this I want to use the touchesBegan:withEvent: method in my subclassed UITableViewCell.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
NSLog(#"%#", NSStringFromCGPoint(location));
}
How can I forward that from my UITableViewCell subclass to my current viewController so that I can make an action depending on where in the cell they tapped?
** I don't want to use a Gesture Recognizer on the cell since it will not allow the didSelectRowAtIndexPath: method to be called.
Either delegation or block call back would do it. Below is an example of using blocks
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
__weak __typeof(self) weakSelf = self;
cell.touchedAtPoint = ^(UITableViewCell *cell, CGPoint point) {
[weakSelf doSomethingWithPoint:point);
};
return cell;
}
In the cell
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
{
[super touchesBegan:touches withEvent:event];
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
void (^touchedAtPoint)(UITableViewCell *, CGPoint) = self.touchedAtPoint;
if (touchedAtPoint) {
touchedAtPoint(self, location);
}
}
- (void)prepareForReuse;
{
[super prepareForReuse];
self.touchedAtPoint = nil;
}
Declaration of ivar
#property (nonatomic, copy) void (^touchedAtPoint)(UITableViewCell *cell, CGPoint point);

get CGPoint inside didSelectItemAtIndexPath method of CollectionView

Is there a way that I can get coordinates of clicked point inside collectionViewCell? I want to do method A if I clicked at rect with Y coordinate < 50, and method B if Y >50.
There is also option B, to subclass the UITableViewCell and get the location from the UIResponder class:
#interface CustomTableViewCell : UITableViewCell
#property (nonatomic) CGPoint clickedLocation;
#end
#implementation CustomTableViewCell
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
UITouch *touch = [touches anyObject];
self.clickedLocation = [touch locationInView:touch.view];
}
#end
Then get the location from the TableViewCell it self:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//get the cell
CustomTableViewCell *cell = (CustomTableViewCell*)[tableView cellForRowAtIndexPath:indexPath];
//get where the user clicked
if (cell.clickedLocation.Y<50) {
//Method A
}
else {
//Method B
}
}
Assuming you have a custom UICollectionViewCell, you can add a UITapGestureRecognizer to the cell and get the touch point in the touchesBegan handler. Like this:
//add gesture recognizer to cell
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] init];
[cell addGestureRecognizer:singleTap];
//handler
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
if (touchPoint.y <= 50) {
[self methodA];
}
else {
[self methodB];
}
}

Add condition in macro

How to add following condition in macro
if (![NSStringFromClass([[self superview] class]) isEqualToString:#"_UIModalItemAlertContentView"])
I want to add these two methods only if superClass of tableView category is not alertView
#if ([NSStringFromClass([[self superview] class]) isEqualToString:#"_UIModalItemAlertContentView"])
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([self.customDelegate respondsToSelector:#selector(tableView:touchBegan:withEvent:)]) {
[self.customDelegate tableView:self touchBegan:touches withEvent:event];
}
[super touchesBegan:touches withEvent:event];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([self.customDelegate respondsToSelector:#selector(tableView:touchEnded:withEvent:)]) {
[self.customDelegate tableView:self touchEnded:touches withEvent:event];
}
}
#endif
#define YourMacroName(_view_) ([NSStringFromClass([[_view_ superview] class]) isEqualToString:#"_UIModalItemAlertContentView"])
if(YourMacroName){
//do something
}
Is this what you want?

uiscrollview won't cancel content touches for uisegmentedcontrol

I've subclassed th UIScrollView and overriden the touchesShouldCancelInContentView: method the following way:
-(BOOL)touchesShouldCancelInContentView:(UIView *)view
{
if ([view isKindOfClass:[UIButton class]] || [view isKindOfClass:[UISegmentedControl class]]) {
return YES;
}
if ([view isKindOfClass:[UIControl class]]) {
return NO;
}
return YES;
}
It works perfectly for UIButton, but it doesn't work for UISegmentedControl. Any help would be appreciated
Finally figured it out. Had to subclass both UISegmentedControl and UIScrollView.
1.) added a new property for UISegmentedControl:
#property (nonatomic, assign) BOOL touchProcessed;
2.) overloaded the following methods of the UISegmentedControl:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if (touchProcessed) {
[super touchesBegan:touches withEvent:event];
}
else {
[self.nextResponder touchesBegan:touches withEvent:event];
}
self.touchProcessed = NO;
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.nextResponder touchesMoved:touches withEvent:event];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.nextResponder touchesEnded:touches withEvent:event];
}
3.) overloaded the following methods of th UIScrollview:
-(BOOL)touchesShouldCancelInContentView:(UIView *)view
{
if ([view isKindOfClass:[self class]])
{
return YES; //if there are two nested custom scrollviews
}
if ([view isKindOfClass:[UIButton class]] || [view isKindOfClass:[CustomSegmentedControl class]] || [[view superview] isKindOfClass:[CustomSegmentedControl class]]) {
return YES;
}
if ([view isKindOfClass:[UIControl class]]) {
return NO;
}
return YES;
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (!self.dragging) {
for (UIView *sv in self.subviews) {
if ([sv isKindOfClass:[CustomSegmentedControl class]])
{ //if there is more than one add a tag or tomething
[(CustomSegmentedControl *)sv setTouchProcessed:YES];
[sv touchesBegan:touches withEvent:event];
return;
}
}
}
}
Works perfectly!

Resources