Showing UIMenuController loses keyboard - iphone

I'm making an iphone app similar to the Messages app that comes on the phone. I just set up the ability to copy messages via a UIMenuController, but if the keyboard is showing and someone tries to copy a message, the keyboard goes away (presumably because of my [cell becomeFirstResponder]; where cell is the message cell being copied).
Is there a way to show the Copy message without losing the keyboard?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:
(NSIndexPath *)indexPath {
//...other cell setup stuff...
UILongPressGestureRecognizer *longPressGesture =
[[UILongPressGestureRecognizer alloc]
initWithTarget:self action:#selector(showCopyDialog:)];
[cell addGestureRecognizer:longPressGesture];
return cell;
}
- (void)showCopyDialog:(UILongPressGestureRecognizer *)gesture
{
if (gesture.state == UIGestureRecognizerStateBegan)
{
ConvoMessageCell *cell = (ConvoMessageCell *)[gesture view];
NSIndexPath *indexPath = [self.tblConvo indexPathForCell:cell];
UIMenuController *theMenu = [UIMenuController sharedMenuController];
[cell becomeFirstResponder];
[theMenu setTargetRect:CGRectMake(menuX, menuY, 100, 100) inView:cell];
[theMenu setMenuVisible:YES animated:YES];
}
}

I solved this dilemma by subclassing UITextView to provide a way to override the nextResponder and disable the built-in actions (Paste), like so:
#interface CustomResponderTextView : UITextView
#property (nonatomic, weak) UIResponder *overrideNextResponder;
#end
#implementation CustomResponderTextView
#synthesize overrideNextResponder;
- (UIResponder *)nextResponder {
if (overrideNextResponder != nil)
return overrideNextResponder;
else
return [super nextResponder];
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
if (overrideNextResponder != nil)
return NO;
else
return [super canPerformAction:action withSender:sender];
}
#end
Then, in your gesture action handler, check whether the text view is already the first responder. If so, have it override the next responder; otherwise the keyboard is probably hidden anyway and you can simply becomeFirstResponder. You'll also have to reset the override when the menu hides:
if ([inputView isFirstResponder]) {
inputView.overrideNextResponder = self;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(menuDidHide:)
name:UIMenuControllerDidHideMenuNotification object:nil];
} else {
[self becomeFirstResponder];
}
- (void)menuDidHide:(NSNotification*)notification {
inputView.overrideNextResponder = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIMenuControllerDidHideMenuNotification object:nil];
}
Using the table view delegate methods introduced in iOS 5 (shouldShowMenuForRowAtIndexPath etc.) wasn't a solution for me as I needed control over the positioning of the menu (by default it's simply horizontally centered over the cell, but I'm displaying message bubbles and wanted the menu centered over the actual bubble).

In iOS 5, you can now use the table view delegate methods to show the Menu Controller:
- (BOOL) tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath
- (BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender;
- (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender;
Showing the Menu Controller in this manner will not resign the keyboard.
I'm still curious about this though as I have an app that supports pre-iOS 5 that I would like to do what you're saying also (not resign the keyboard when the copy menu appears).

Related

In ios7 tableView:didSelectRowAtIndexPath: is not called

I meagrate my project to adjust ios7 while I encountered a strange problem : the delegate method "tableView:didSelectRowAtIndexPath:" is not called in ios7 ,it works well in prior ios version.I was wonder if some specific property be changed in ios7
Here is the code:
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView setDelegate:self];
[self.tableView setDataSource:self];
[self.tableView setAllowsMultipleSelection:NO];
[self.tableView setMultipleTouchEnabled:NO];
}
- (void)tableView:(UITableView *)sender didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[sender deselectRowAtIndexPath:indexPath animated:YES];
_currentContact = [contactArr objectAtIndex:indexPath.row];
if ([_currentContact.accountNPC hasPrefix:#"0"]) {
isContactToNPC = NO;
}else{
isContactToNPC = YES;
}
....
}
Add the following in your viewController.h file
<UITableViewDelegate,UITableViewDatasource>
also connect the tableview's delegate and datasource to the File's Owner of .xib
I'm sorry,I found the answer
I just need set
[cell setExclusiveTouch:YES]
Tks #abhishekkharwar from https://stackoverflow.com/a/18826264/2396477

show alert while deleting a uitableViewCell ios5

I am implementing a swipe to delete functionality in uitableview. I am able to achieve that, but now i wish to display a alert message to confirm delete. I have created the tableview programmatically.
ViewController.h
#interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>
{
UITableView *tView;
NSMutableArray *myArray;
NSIndexPath *lastIndexPath;
}
#property(nonatomic,retain) UITableView *tView;
#property(nonatomic,retain) NSMutableArray *myArray;
#property(nonatomic,retain) NSIndexPath *lastIndexPath;
#end
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor=[UIColor lightGrayColor];
myArray = [[NSMutableArray alloc] initWithObjects:#"1",#"2",#"3",#"4",#"5",#"6",#"7",#"8",#"9",#"10", nil];
// Do any additional setup after loading the view, typically from a nib.
tView = [[UITableView alloc] initWithFrame:CGRectMake(30, 30, 700, 800) style:UITableViewStylePlain];
tView.delegate=self;
tView.dataSource=self;
[self.view addSubview:tView];
[tView release];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 100.0;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [myArray count];
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return YES if you want the specified item to be editable.
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Confirm Delete" message:#"Are you sure?" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Delete", nil];
[alert show];
[alert release];
if (editingStyle == UITableViewCellEditingStyleDelete) {
lastIndexPath = indexPath;
NSLog(#"%#......%d",lastIndexPath,lastIndexPath.row);
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex==0)
{
NSLog(#"cancel");
}
else {
NSLog(#"delete");
[myArray removeObjectAtIndex:lastIndexPath.row]; //memory error
[tView deleteRowsAtIndexPaths:[NSArray arrayWithObject:lastIndexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//..do required thing and return cell
}
I get a memory error in the clickButtonAtIndex method for alert view. I think it is for the lastIndexPath, but the nslog() give the correct value in lastIndexPath.
What am i doing wrong?
I hate it when answers just say "You should't do that"... So I'll explain why you are getting an error and then hopefully appeal to your better judgement as to why you really ought not to do this (from a UI point of view).
You are getting an error because you assign a value you do not own (you have not retained it) to an ivar directly. You probably meant to say self.lastIndexPath.
What happens is that the alert view does not really appear until the next time through the run loop at which point indexPath has been autoreleased and you try to access it through a pointer.
Changing lastIndexPath = indexPath; to self.lastIndexPath = indexPath; should solve the memory issue. (Since you marked the property as retain, assuming you synthesized it and did not write your own handler, when you use the self. prefix the synthesized accessor will retain it for you).
(Incidentally this is why is not a bad idea to name your ivars differently from your properties (e.g. Apple uses <property_name>_, on my site I use m<Property_name> it makes it hard to make this sort of mistake).
OK... But back to why you should not do this....
You user has, at this point, made a recognizable gesture by swiping left and has then pressed a red button marked 'delete'... And now you are going pop an alert and ask them to confirm? Really? OK, if you must...

How get rid of reorderControl while still using reorder?

Not long ago I asked about how to move reorderControl view close to the center of my custom cell, so this reorderControl break custom design. As I can't move this view and my cell always in editing mode - I just draw this reorderControl in right place of my cell background. But now I have two reorderControls ) one from my background in right place and one from iOS. If I set return value of - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath to NO, iOS reorderControl disappear but I can't reorder rows anymore.
How can I remove iOS reorderControl from screen and still be able to reorder my custom UITableViewCell?
ps cell.showsReorderControl=NO; is not working
It's kind of a hack but the following does work
for(UIView* view in self.subviews)
{
if([[[view class] description] isEqualToString:#"UITableViewCellReorderControl"])
{
for(UIImageView* cellGrip in view.subviews)
{
if([cellGrip isKindOfClass:[UIImageView class]])
[cellGrip setImage:nil];
}
}
}
The solution I got it work in iOS7 is to add another method to find reorder control. Since the tableview structure has changed in iOS7 It was a little bit hard to track UITableViewCellReorderControl. It is now in UITableViewCellScrollView.
The solution is like below
- (void)changeReorderControl:(UITableViewCell *)cell subviewCell:(UIView *)subviewCell
{
if([[[subviewCell class] description] isEqualToString:#"UITableViewCellReorderControl"]) {
[subviewCell.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
UIImageView *imageView= [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"hand"]];
imageView.center = CGPointMake(subviewCell.frame.size.width/2 , subviewCell.frame.size.height/2);
[subviewCell addSubview:imageView];
}
}
- (void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
for(UIView* subviewCell in cell.subviews)
{
if([[[subviewCell class] description] isEqualToString:#"UITableViewCellScrollView"]) {
for(UIView* subSubviewCell in subviewCell.subviews) {
[self changeReorderControl:cell subviewCell:subSubviewCell];
}
}
}
}
Hope you will get the idea.

UIButton in UITableViewCell

I have a UIButton with an image inside of a UITableViewCell. When the cell is being highlight, the button is also entering the highlighted state (i.e. a darker shade of the image), regardless of whether the user is clicking within the bounds of the button or not.
I don't want this functionality - I only want the button to be highlighted when the button is clicked, not when the entire cell is being clicked.
I've tried to set the image in the highlighted state to be the same as the normal image. This fixes the issue however it stops the button from changing color when it really is highlighted.
Any ideas how to achieve the desired effect?
This was driving me crazy. I figured out that you need to override setHighlighted:animated: and setSelected:animated:
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated {
[super setHighlighted:highlighted animated:animated];
self.yourButton.highlighted = NO;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
self.yourButton.selected = NO;
// If you don't set highlighted to NO in this method,
// for some reason it'll be highlighed while the
// table cell selection animates out
self.yourButton.highlighted = NO;
}
One approach would be to "deselect" or "unhighlight" the button when the table view cell is selected:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[yourButton setHighlighted:NO];
// do something cool
}
codecaffeine's suggestion didn't work for me (iOS 8.3), but it did put me on the right track. I modified it like this (it's in Swift though):
override func setHighlighted(highlighted: Bool, animated: Bool) {
var colorBefore = self.myButton.backgroundColor
super.setHighlighted(highlighted, animated: animated)
self.myButton.highlighted = false
self.myButton.backgroundColor = colorBefore
}
I've used a different approach, it's a little bit easier, I hope it works for you. Just set the button's highlighted state to false inside the two above delegate methods:
-(void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath {
UIButton *btnAction = (UIButton *) [[tableView cellForRowAtIndexPath:indexPath] viewWithTag:3];
btnAction.highlighted = NO;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UIButton *btnAction = (UIButton *) [[tableView cellForRowAtIndexPath:indexPath] viewWithTag:3];
btnAction.highlighted = NO;
}
Haven't actually tried this, but could you maybe add a target / action to the button for UIControlEventTouchDown that updated its highlighted-state image to what you wanted, then another target / action for UIControlEventTouchUpInside / UIControlEventTouchUpOutside / UIControlEventTouchCancel that reset the highlighted image to match the normal-state image?
A possible workaround would be that, you set the cell selection style to be none. In that case when you select the cell, it would not be highlighted.
This is only, the possible workaround. May be you have other things in your mind.
To make it work, I had to use the following subclassing on the UITableViewCell. The 'button' object is the button inside the custom cell:
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated {
[self.button setShowsTouchWhenHighlighted:NO];
[super setHighlighted:highlighted animated:animated];
self.button.highlighted = NO;
[self.button setShowsTouchWhenHighlighted:YES];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[self.button setShowsTouchWhenHighlighted:NO];
[super setSelected:selected animated:animated];
self.button.highlighted = NO;
// Configure the view for the selected state
[self.button setShowsTouchWhenHighlighted:YES];
}
Interverting the various line may result in the highlighting of the button.

how to detect touch event in table cells for iphone

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];
}
}