I have a UITableViewController and want to detect touches.
Basically, I want the user to be able to hold down a touch for 3 seconds, when they let go I want to pop up a small view with a few options for the table.
I've tried this...
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
self.lastTouch = [event timestamp];
NSLog(#"TLC.touchesBegan:touchBeginEndInterval %f", self.lastTouch);
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSTimeInterval touchBeginEndInterval = [event timestamp] - self.lastTouch
NSLog(#"TLC.touchesEnded:touchBeginEndInterval %f %f", self.lastTouch, touchBeginEndInterval);
}
And it isn't picking up my touches at all...
Any ideas about the best way to implement this?
TableViews have sort of a "touch" delegate method. Implement this method for your tableView delegate:
// What happens when a row is touched
- (void)tableView:(UITableView *)table didSelectRowAtIndexPath:(NSIndexPath *)indexPath {}
You shouldn't make them press for 3 seconds... just use the standard.
Assuming that code comes from your UITableViewController subclass ... UIViewControllers don't receive methods like touchesBegan:withEvent. Only UIResponders like UIView an its subclasses like UITableView do. So you are trying to get the touches in the wrong place.
What are you trying to accomplish? Do you want to respond to touches in the UITableView or in a UITableViewCell? In case of the latter, you can deal with the touches in your custom cell implementation.
Now it's easy to accomplish with UILongPressGestureRecognizer:
-(void)viewDidLoad{
[super viewDidLoad];
UILongPressGestureRecognizer *longPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPressHandlerMethod:)];
[self.tableView addGestureRecognizer:longPressRecognizer];
}
-(void)longPressHandlerMethod:(UIGestureRecognizer *)gestureRecognizer{
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:[gestureRecognizer locationInView:self.tableView]];
...
}
Related
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Dismiss keyboard on touch anywhere outside UITextField
MyViewController in interface builder :
In my custom TableViewCell I have a TextField. My plan is disappear KeyPad when User Clicks outside the touchpad.
I could not make it works using UITapGestureRecognizer
in viewDidLoad:
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(hideKeyboard)];
[self.tableView addGestureRecognizer:gestureRecognizer];
Then how should I make it work with cell.TextField ?
I read about this solution here:
[self.view endEditing:YES];
or
[[self.tableView superView] endEditing];
I couldn't make it work neither. Where should I use them?
Or if you have any better way, please let me know.
Edit
I could not make it work:
#property (nonatomic, strong) UITextField *cellTextField;
in viewDidLoad:
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(hideKeyboard)];
[self.settingTableView addGestureRecognizer:gestureRecognizer];
And we have:
- (void) hideKeyboard {
[self.cellTextField resignFirstResponder];
}
And :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
SettingTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
self.cellTextField = cell.dataEdit;
What is my fault?
you could add a property to your view controller, say
#property (nonatomic, strong) UITextField *cellTextField
and then assign cell.TextField to it.
in hideKeyboard: you can dismiss the keyboard by doing
[cellTextField resignFirstResponder];
You should call resignFirstResponder on the textField itself, not the controller's view.
Add [cellTextField resignFirstResponder]; hope this works...
Maybe look at UITextFieldDelegate, and in particular - (BOOL)textFieldShouldReturn:(UITextField *)textField
You Can hide Keyboard if You Put the Whole Screen Custom UIButton.Then Attached this Method With this Custom UIButton.set the UITextField tag =1 in Interface builder before implementation of this method.
-(IBAction)HideKeyboard
{
[[self.view viewWithTag:1]resignFirstResponder];
}
Note: if You Want to hide keyboard by Click in CustomCell then Put this UIButton there or You Can Call this Method using Gesture Recognization as you did in Your Code without Using Custom UIButton.
And also make sure You Connect UITextField delegate.Hope this Work .
You may try this.
- (void) hideKeyboard {
[self.view endEditing:YES];
}
You can achieve this task by inserting the following method
You must implement UITextFieldDelegate
you must set a tag for the textfield in the storyboard or in when you start loading the cells of the table
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
self.currentIndexPath = [(UITableView*)textField.superview.superview.superview indexPathForCell:(UITableViewCell*)textField.superview.superview];
self.currentTableView = (UITableView*)textField.superview.superview.superview;
self.keyboardIsShown = YES;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.view];
if(self.keyBoardIsShown)
{
[self dismissKeyboard:currentPoint UsedTableView:self.myTableView IndexPathForRow:self.currentIndexPath TexFieldTag:tag];
self.keyBoardIsShown = NO;
}
}
-(void)dismissKeyboard:(CGPoint)currentPoint UsedTableView:(UITableView*)table IndexPathForRow:(NSIndexPath*)indexPath TexFieldTag:(int)tag
{
UITableViewCell *cell = [table cellForRowAtIndexPath:indexPath];
if(!CGRectContainsPoint([self.view convertRect:[cell viewWithTag:tag].frame fromView:[cell viewWithTag:tag].superview.superview], currentPoint))
{
[(UITextField*)[cell viewWithTag:tag] resignFirstResponder];
}
}
Is it possible to distinguish which side of a row in a uitableview has been clicked?
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//which side of row has been detected left or right
}
You can subclass UITableViewCell. In your subclass, you can make an iVar wasTouchOnLeft. Then override touchesBegan or touchesEnded like the example below:
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch=(UITouch *)[touches anyObject];
if([touch locationInView:self].x< (0.5 * self.frame.size.width) )
{
NSLog(#"Touched Left");
wasTouchOnLeft=YES;
}
else {
NSLog(#"Touched Right");
wasTouchOnLeft=NO;
}
[super touchesEnded:touches withEvent:event];
}
In the didSelectRowAtIndexPath of your UITableViewController you can then access the wasTouchOnLeft variable for the cell.
You can't determine this directly in this method.
But if you really want this feature create a custom tableview cell that has two big buttons (one left one on the right side) or apply a touch recognizer on the cell.
If you have this delegate the action to your controller
(You could also store it in the cell and access it via)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(((YourCustomTableCell*)[tableView cellForRowAtIndexPath:indexPath]).clickedSideProperty) action;
else anotherAction;
}
But better delegate it from the table cell than access it from didSelectRow…
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
*/
I have a text field that is being shown in a UITableViewCell and I want to be able to hide the keyboard when the user touches anywhere else on the screen aside from the text field. I know about [field resignFirstResponder];, but I don't know how to intercept touches on the background of the UITableView in order to call "resignFirstResponder".
Any help would be greatly appreciated.
The only way to do this is to subclass the UITableView, implement the touchesBegan method in your subclassed UITableView and send your UITextField objects to the UITableView. Here's how it should look like -
// GRTableView.h
// StackOverflow Example
//
// Created by Raphael Caixeta on 8/13/10.
// Copyright 2010 Raphael Caixeta. All rights reserved.
//
#import <UIKit/UIKit.h>
#interface GRTableView : UITableView <UITableViewDelegate> {
UITextField *textField;
}
#property(nonatomic, retain) UITextField *textField;
#end
//
// GRTableView.m
// StackOverflow Example
//
// Created by Raphael Caixeta on 8/13/10.
// Copyright 2010 Raphael Caixeta. All rights reserved.
//
#import "GRTableView.h"
#implementation GRTableView
#synthesize textField;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[textField resignFirstResponder];
[super touchesBegan:touches withEvent:event];
}
- (void)dealloc {
[super dealloc];
}
#end
And then in your regular file where you'll allocate a UITableView, just allocate the subclassed view and pass your textfield to the subclass. Hope that helps.
Try implementing the - (void)textFieldDidEndEditing:(UITextField *)textField method of the UITextFieldDelegate.
It's very simple: create a transparent UIView object that receives touches in the area you want, and when the touch is in the bounds of that view, call resignFirstResponder.
// somewhere in a view controller
UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
[self.view addSubview:backgroundView];
// in the touchesBegan:withEvent: method, for example
UITouch *touch = [[event allTouches] anyObject];
if ([field isFirstResponder] && [touch view] == backgroundView) {
[field resignFirstResponder];
}
Alternatively, you could skip the backgroundView stuff and just add a conditional statement like the following in your touchesBegan:withEvent: method:
UITouch *touch = [[event allTouches] anyObject];
if ([field isFirstResponder] && [touch view] != field) {
[field resignFirstResponder];
}
If the touch is ! (not) in the bounds of field, then you want to remove the keyboard.
You can hide the key board in following conditions,
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { }
(void)TextField:(UITextField *)TxtFld textDidChange:(NSString *)searchText{ }
In this two condition you should place [TxtFld resignFirstResponder]; And also when your work for textfield is over you are performing some actions on that event also you should write [TxtFld resignFirstResponder]; where TxtFld is an object for UIText field.
By using this thing the keyboard will dismissed. The touch method you are writing may not work on the UITableviewCell. so this will be the way to hide the key board.
still it not work then specify the exact problem occurs.
There's an easier way to do this than the standard "subclass UITableView" or "add a subclass of UIView and handle touches". I create a UIButton with a clear background color over the area that I want to handle touches. When I add it to the view, I set its hidden property to YES.
When the text field begins editing, I set the button's hidden property to NO.
Then the button simply responds to UITouchUpInside control event, in a method which calls [textField resignFirstResponder] and button.hidden = YES.
how to detect touch event for table cells
i tried this
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//<my stuff>
[super touchesBegan:touches withEvent:event];
}
but its not working actuallly i have aUIimage view in table cell and i want to chnage imgae based on tap so my touch event is not working for that cell
If you want to detect a touch on the UITableViewCell you don't really need to detect touch events. In your UITableViewController subclass, you need to implement the following delegate method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
Then you modify the image of the table cell for the selected index path.
You probably need to set myImageView.userInteractionEnabled = YES;.
In one of my projects I needed any tap on the tableView to dismiss the keyboard so the underlying tableView would show. Since a UITableView is really a UIScrollView, it will respond to the scrollView delegate methods. Using these 2 methods will dismiss if either the user taps on a cell or scrolls the tableView at all:
IMPORTANT: Make sure you implement the UIScrollViewDelegate in your .h file as well as the UITableViewDelegate and UITableViewDataSourceDelegate!!!
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//remove keyboard if table row is clicked
if ([self.firstName isFirstResponder] || [self.lastName isFirstResponder]) {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
[self.firstName resignFirstResponder];
[self.lastName resignFirstResponder];
}
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
//remove keyboard if table scrolls
if ([self.firstName isFirstResponder] || [self.lastName isFirstResponder]) {
[self.firstName resignFirstResponder];
[self.lastName resignFirstResponder];
}
}