I'm using this custom component for hashtag detection in my app. I have added STTweetLabel's as subviews to my custom table view cells. However, clicking on any hashtag invokes the STTweetLabel handler block AND also calls the tableview's didSelectRowAtIndexPath delegate which results in a push to another controller. How do I disable this from happening? i.e. prevent the didSelectRowAtIndexPath behaviour on the STTweetLabels?
Code:
[hashtagLabel setDetectionBlock:^(STTweetHotWord hotWord, NSString *string, NSString *protocol, NSRange range) {
// call delegate to respond to hashtag selection
}];
Try to delete
[super touchesBegan:touches withEvent:event];
[super touchesMoved:touches withEvent:event];
[super touchesEnded:touches withEvent:event];
in STTweetLabel.m
I use TTTAttributedLabel now, you can also try it.
If your problem is cell highlight then use this.
cell.selectionStyle = UITableViewCellSelectionStyleNone;
Or use this for prevent invoke didSelectRowAtIndexPath.
tableView:willSelectRowAtIndexPath:
I hope it will help you
You can either prevent the cell from being selected at all in the interface builder or in code using the UITableViewCellSelectionStyleNone selection style.
or in your -(NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath method return nil for the indexPath of the cells you don't want to get selected
Actually didSelectRowAtIndexPath method always get called first and this solution may work if your label will not cover whole your cell.
If you are doing some task in didSelectRowAtIndexPath then do this steps
1> cell.selectionStyle = UITableViewCellSelectionStyleNone;
2> make custom cell put button back side of label .On button put uilabel then you can add action on that button and do some task when button tapped and as well you can detect label tap seperately
the dirty way:
put your STTweetLabel inside an UIButton without target and action
Related
I am working on a app using TableView now i am facing an issue listed below.
Inside my TableView there is UITextView on it, that MUST be selectable, but not editable (because I need to use and proceed links).
My issue is:
when I tap on a link as everybody does, it doesn't work. I need to hold it a bit longer to make it work. I thought that it is because of "Selectable" property brings in a Double Tap Gesture recognizer, so my textView checks if there is a second tap, but I don't know how to find and remove only double tap recognizer.
What should I do?
Thank you.
Have you considered replacing the TextView with a UIWebView, and just do a loadHTMLString function?
This way when you tap on a link, it will open instantly? You can even have a UIWebView delegate and do what you want when the link is pressed(Custom UIWebView instead of auto opening in safari etc)
You've to handle tap event.. Through this code
tapGesture.numberOfTapsRequired = 1
OR
To do this, you will need to embed one in your UITableViewCell. But there's no need to create a custom cell. Here is the basic idea of what you will want to do:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
UITextView *comment = [[UITextView alloc] initWithFrame:CGRectMake(cell.frame.origin.x, cell.frame.origin.y, cell.frame.size.width, tableView.rowHeight)];
comment.editable = NO;
comment.delegate = self;
[cell.contentView addSubview:comment];
[comment release];
}
return cell;
}
You will, of course, need to set your rowHeight if you don't want the standard 44pt height that comes with the cell. And if you want actual cells, you'll need to add your own logic so that only the cell you want is a textView, but this is the basic idea. The rest is yours to customize to your fitting. Hope this helps
EDIT: to bypass the textView to get to your cell, there are two ways to go about this.
1) you can make a custom textView class and overwrite touchesBegan to send the message to super:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
}
this will send the touch events to its superview, which would be your tableView. Considering you didn't want to make custom UITableViewCells, I imagine you probably don't want to make a custom textView class either. Which leads me to option two.
2) when creating the textView, remove comment.editable = NO;. We need to keep it editable, but will fix that in a delegate method.
In your code, you will want to insert a textView delegate method and we'll do all our work from there:
EDIT: changing this code to use with a UITableViewController
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
// this method is called every time you touch in the textView, provided it's editable;
NSIndexPath *indexPath = [self.tableView indexPathForCell:textView.superview.superview];
// i know that looks a bit obscure, but calling superview the first time finds the contentView of your cell;
// calling it the second time returns the cell it's held in, which we can retrieve an index path from;
// this is the edited part;
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
// this programmatically selects the cell you've called behind the textView;
[self tableView:self.tableView didSelectRowAtIndexPath:indexPath];
// this selects the cell under the textView;
return NO; // specifies you don't want to edit the textView;
}
If that's not what you wanted, just let me know and we'll get you sorted out
Finding and Removing Double Tap Gesture recognizer
Objective C
- (void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
{
if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]])
{
[(UITapGestureRecognizer *)gestureRecognizer setNumberOfTapsRequired:1];
gestureRecognizer.enabled = NO;
}
}
Swift
func addGestureRecognizer(gestureRecognizer: UIGestureRecognizer)
{
if gestureRecognizer.isKindOfClass(UITapGestureRecognizer)
{
(gestureRecognizer as! UITapGestureRecognizer).numberOfTapsRequired = 1
gestureRecognizer.enabled = false
}
}
I have created an app using a storyboard. In other screens, I have used a UITableViewController directly and the selection is working as expected.
In this case, I have a UITableView that is one of several controls within a UIViewController.
My custom ViewController.h file has a definition similar to the below:
#interface MyViewController : UIViewController <UITableViewDelegate,UITableViewDataSource>
#property (weak,nonatomic) IBOutlet UITableView *myTableView;
#end
Then within viewDidLoad I am doing this:
_myTableView.delegate = self;
_myTableView.dataSource = self;
Having done this, my numberOfSectionsInTableView, numberOfRowsInSection and cellForRowAtIndexPath methods are all being called and my table looks as I want it to.
The problem I have is that the rows do not select and the didSelectRowAtIndexPath method is not getting called.
I have checked that Selection is set to Single Selection in the storyboard view and I have also tried to set _myTableView.allowsSelection=YES; in viewDidLoad but this doesn't seem to make any difference.
I know that this is probably something to do with the fact that my table is within a normal view controller, but I can't figure out the magic step I've missed to make the selection work.
For now I have added a workaround. In cellForRowAtIndexPath I have attached a UITapGestureRecognizer to each view in the cell:
for(UIView *view in cell.contentView.subviews){
[view setUserInteractionEnabled:YES];
UITapGestureRecognizer *tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapRow:)];
[tap setNumberOfTapsRequired:1];
[view addGestureRecognizer:tap];
view.tag = row; // So that I can identify in the handler which row has been tapped
}
Then in the handler:
-(void)tapRow:(id)sender{
UITapGestureRecognizer *gesture = (UITapGestureRecognizer*)sender;
UIView *myView = (UIView*)gesture.view;
int row = myView.tag;
// Handle tap of row here
}
This achieves what I need, but I would still like to figure out what I've done wrong with the row selection!
Make sure there is not another view on top of the table view (e.g. a transparent view that would be stealing touch events). Also ensure that userInteraction is enabled for the tableview and all of its parent views.
We type sometime wrong delegate call didDeselectRowAtIndexPath instead of didSeselectRowAtIndexPath. Is it your case?
I see that you can update your content in the tableview so the connection should be OK. I think about mistakes with function names.
Just to test: Replace your didSelectRowAtIndexPath function with this (copy, paste).
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Selected %d",indexPath.row);
}
Just incase anyone still has this problem. I just realised -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath method won't work for any view or subview with a tap gesture recogniser set to it. So remove the tap gesture recogniser from that view of it's parent view. if you still want to handle touch events, then use "touchesBegan" function. ` - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
UITouch *touch = [touches anyObject];
}`
I had the exactly the same problem with my current project for two minutes yesterday when I realised that I didn't link my delegate and dataSource of the table view. You made it programmatically, so it should work. For me was a delegation problem, you can check your Attributes Inspector to make sure that everything is ok.
In cellForRowAtIndexPath method add this line
cell.userInteractionEnabled = NO;
I have a simple project that contains a UITableView with a custom cell, in this I cell have a UITextField, So I have a button that calls a function 'addField', When This function is called I increment +1 value for the variable numberOfRows, then I call the command responsible for updating the table, as you can see bellow:
-(void)AddField{
numberOfRows++;
[tableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return numberOfRows;
}
Doing so creates a new table row with a new textField to enter another value.
Inside My cell I connect the UITextField with the Outlet,:
IBOutlet UITextField *myFields;
Inside awakeFromNib I have a code who checks whether the user is typing:
- (void)awakeFromNib
{
[campoTexto addTarget:self
action:#selector(change:)
forControlEvents:UIControlEventEditingChanged];
}
-(void)change:(UITextField *)textField{
NSLog(#"What The textField I'm Typing? -> %ld",(long)textField.tag);
}
All I would do is try to find some way to differentiate which text field I'm typing, as well UITableView can differentiate their rows (0 .. n), I think I can differentiate this UITextField (0 ... n).
Can anyone give me some help, or maybe know a tutorial on the web that explain this kind of thing?
Thanks.
The best way to Identify custom controls in a tableView cell, or rather what I would prefer is to set a tag for the custom control in your tableView datasource method cellForRowAtIndexPath:.
cell.yourTextField.tag = indexPath.row;
You can then get the indexPath from the corresponding tag in your method as follows:
-(void)change:(UITextField *)textField
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:textField.tag inSection:0];
}
Hope this helps :) !
I have a UITableView with a UITextField inside of each cell. A model object that stores the index of the cell that is currently being edited. If the cell scrolls off-screen, my app takes away first-responder status. (Failing to do so may cause problems). Now, suppose a cell (possibly the same one, or possibly a different one) corresponding to that index is about to scroll back onto the screen. I want to make that cell's textField the firstResponder. My delegate does receive a call
tableView: willDisplayCell: forRowAtIndexPath:
corresponding to the new cell. However, calling becomeFirstResponder: at that point does not help as the cell won't accept firstResponder status until it has been displayed.
Short of using a timer, any ideas for how to call becomeFirstResponder: at a point when the cell is in fact able to become the first responder?
EDIT: cellForRowAtIndexPath: is always called before willDisplayCell:. So no help there.
I haven't tried this, but the first thing I'd try is in cellForRowAtIndexPath...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// standard stuff to build cell and setup it's state
if ([indexPath isEqual:self.myModel.indexPathOfTextFieldBeingEdited]) {
// you probably have a handle to the text field from the setup above
UITextField *textField = (UITextField *)[cell viewWithTag:SOME_TAG];
[textField performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0.0];
}
return cell;
}
You have to show cell on the screen to make it as first responder. Do at first:
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:NO];
and then call first responder on it's label/textField.
Here's what I did in MonoTouch - it's important that you do not animate the ScrollToRow() - i.e. "animated:NO" as shown in the answer by edzio27 (thanks edzio27 :) ).
var newCell = (UIOrderLineCell)tableView.CellAt(newIndexPath);
if (newCell == null)
{
tableView.ScrollToRow(newIndexPath, UITableViewScrollPosition.Middle, false);
newCell = (UIOrderLineCell)tableView.CellAt(newIndexPath);
}
I have a UITextField with a tag inside a prototype cell. The UITextField is set to become first responder when the UITableView is being built and a UISwitch in the cell above is turned on.
This works if the app starts from scratch or if it was closed and restarted. Once it's loaded the [tableView reloadData] doesn't trigger the becomeFirstResponder anymore.
If the UITextField becomes first responder by touching the textfield later on, I can trigger the becomeFirstResponder event with buttons, with pop ups,...
But not with my switch any more.
Any pointers as to what I can try?
Currently, I use the didSelectRowAtIndexPath method to trigger a pop up. A nice side effect is, that when I pull up the number keypad, I can provide an ok and cancel button within the pop up instead of having to fiddle with separate buttons on the keypad. But it just seems so obviously to be a workaround.
This is how I call firstresponder when building the UITableView (which works every time the app starts from scratch):
if ([settings doubleForKey:#"limitDouble"]==0 && [settings boolForKey:#"limitBool"]==YES) {
[dailyLimitEntry becomeFirstResponder];
}
dailyLimitEntry is a UITextField which is strong so it stays around.
Just for fun I added a button and connected it to my code like this:
UITextField *tmp = (UITextField *)[self.view viewWithTag:35];
[tmp becomeFirstResponder];
This works, too. When I use it with the switch, it's only called once the app is freshly loaded in the memory. Otherwise, my UITextField doesn't respond to the switch.
After the first comments, I found a method to check whether or not the UITableView has finished reloading
-(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if([indexPath row] == ((NSIndexPath*)[[settingsTableView indexPathsForVisibleRows] lastObject]).row){
//end of loading
//for example [activityIndicator stopAnimating];
NSLog(#"finished reload");
NSLog(#"%#",dailyLimitEntry);
if ([settings boolForKey:#"limitBool"]==YES) {
UITextField *tmp = (UITextField *)[self.view viewWithTag:35];
[tmp becomeFirstResponder];
}
}
}
Fun thing though is, become first responder is only triggered the first time the switch is used after the app loaded. Initially, the switch is off. So the cell containing the UITextField is not drawn yet. Once I switch to ON, the UITextField gets drawn in the second cell and becomes first responder. If I switch OFF and ON again, I still get my log "finished reload", but the UITextField doesn't become first responder. It's driving me nuts....
Must be something about the life cycle of the app.
Rather than checking the indexPath, check the cell's class.
Here's what I do to bring up the keyboard for a title cell that's blank (when I create a new item):
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([cell isKindOfClass:[FDSSampleTitleCell class]]) {
FDSSampleTitleCell *titleCell = (FDSSampleTitleCell *)cell;
if (titleCell.titleField.text.length == 0) {
[titleCell.titleField becomeFirstResponder];
}
}
}