Hice algunas mejoras al trabajo de Ahmet. Aquí clases se generados:
/*
Copyright 2011 Ahmet Ardal
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Improved by Yuriy Umanets <[email protected]>
Changes:
- added new property customMenus, which is array of NamedAction instances describing names and selector action
for each of custom menus (not one of those copy, paste, etc). The class using CopyableCell can provide own actions
and they will be called by CopyableCell. This is implemented with dynamicMethodIMP() and resolveInstanceMethod();
- oldStyle field that saves old style of the cell before changing (highlighting) so that when action is taken old
style is set back to the cell without changing behaviour expected by author;
- (fix) in touchEnded() one needs to call [super touchEnded] in order to provide correct behaviour.
*/
#import "CopyableCell.h"
#import "NamedAction.h"
static const CFTimeInterval kLongPressMinimumDurationSeconds = 0.5;
@interface CopyableCell(Private)
- (void) initialize;
- (void) menuWillHide:(NSNotification *)notification;
- (void) menuWillShow:(NSNotification *)notification;
- (void) handleLongPress:(UILongPressGestureRecognizer *)longPressRecognizer;
@end
@implementation CopyableCell
@synthesize data, indexPath, delegate, customMenus;
- (id) initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
if (!(self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]))
return self;
[self initialize];
return self;
}
- (void) initialize
{
self.data = nil;
self.indexPath = nil;
self.delegate = nil;
self.customMenus = nil;
self.selectionStyle = UITableViewCellSelectionStyleNone;
UILongPressGestureRecognizer *recognizer =
[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
[recognizer setMinimumPressDuration:kLongPressMinimumDurationSeconds];
[self addGestureRecognizer:recognizer];
[recognizer release];
}
- (void) setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
}
- (void) dealloc
{
[self.customMenus release];
[self.data release];
[self.indexPath release];
[super dealloc];
}
#pragma mark -
#pragma mark Copy Menu related methods
- (BOOL) isCustomActionExists:(SEL)sel
{
if (self.customMenus != nil) {
for (int i = 0; i < customMenus.count; i++) {
NamedAction *namedItem = [customMenus objectAtIndex:i];
if (sel == namedItem.action)
return YES;
}
}
return NO;
}
- (BOOL) canPerformAction:(SEL)action withSender:(id)sender
{
if (self.customMenus != nil) {
if ([self isCustomActionExists:action])
return YES;
} else {
if (action == @selector(copy:))
return YES;
}
return [super canPerformAction:action withSender:sender];
}
- (void) copyToPastboard:(NSString *)dataText
{
[[UIPasteboard generalPasteboard] setString:dataText];
[self resignFirstResponder];
}
- (void) copy:(id)sender
{
if ((self.delegate != nil) &&
[self.delegate respondsToSelector:@selector(copyableCell:dataForCellAtIndexPath:)]) {
NSString *dataText = [self.delegate copyableCell:self dataForCellAtIndexPath:self.indexPath];
[self copyToPastboard:dataText];
} else if (self.data != nil) {
[self copyToPastboard:self.data];
}
}
- (BOOL) canBecomeFirstResponder
{
return YES;
}
- (BOOL) becomeFirstResponder
{
return [super becomeFirstResponder];
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
if ([self isFirstResponder] == NO)
return;
UIMenuController *menu = [UIMenuController sharedMenuController];
[menu setMenuVisible:NO animated:YES];
[menu update];
[self resignFirstResponder];
}
- (void) menuWillHide:(NSNotification *)notification
{
if ((self.delegate != nil) && [self.delegate respondsToSelector:@selector(copyableCell:deselectCellAtIndexPath:)])
[self.delegate copyableCell:self deselectCellAtIndexPath:self.indexPath];
self.selectionStyle = oldStyle;
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIMenuControllerWillHideMenuNotification object:nil];
}
- (void) menuWillShow:(NSNotification *)notification
{
oldStyle = self.selectionStyle;
self.selectionStyle = UITableViewCellSelectionStyleBlue;
if ((self.delegate != nil) && [self.delegate respondsToSelector:@selector(copyableCell:selectCellAtIndexPath:)])
[self.delegate copyableCell:self selectCellAtIndexPath:self.indexPath];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIMenuControllerWillShowMenuNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(menuWillHide:)
name:UIMenuControllerWillHideMenuNotification
object:nil];
}
#pragma mark -
#pragma mark UILongPressGestureRecognizer Handler Methods
#include <objc/runtime.h>
void dynamicMethodIMP(id self, SEL sel) {
if ([self isCustomActionExists:sel])
[((CopyableCell *)self).delegate performSelector:sel withObject:self withObject:nil];
}
+ (BOOL) resolveInstanceMethod:(SEL)sel {
class_addMethod([self class], sel, (IMP)dynamicMethodIMP, "[email protected]:");
return YES;
}
- (void) handleLongPress:(UILongPressGestureRecognizer *)longPressRecognizer
{
if (longPressRecognizer.state != UIGestureRecognizerStateBegan)
return;
if ([self becomeFirstResponder] == NO)
return;
UIMenuController *menu = [UIMenuController sharedMenuController];
[menu setTargetRect:self.bounds inView:self];
NSMutableArray *menuItems = nil;
if (self.customMenus != nil && customMenus.count > 0) {
menuItems = [[[NSMutableArray alloc] init] autorelease];
for (int i = 0; i < customMenus.count; i++) {
NamedAction *namedItem = [customMenus objectAtIndex:i];
UIMenuItem *emailItem = [[UIMenuItem alloc] initWithTitle:namedItem.name
action:namedItem.action];
[menuItems addObject:[emailItem autorelease]];
}
}
menu.menuItems = menuItems;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(menuWillShow:)
name:UIMenuControllerWillShowMenuNotification
object:nil];
[menu setMenuVisible:YES animated:YES];
}
@end
aquí es * archivo .h:
/*
Copyright 2011 Ahmet Ardal
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import <UIKit/UIKit.h>
@protocol CopyableCellDelegate;
@interface CopyableCell: UITableViewCell
{
NSString *data;
NSArray *customMenus;
NSIndexPath *indexPath;
UITableViewCellSelectionStyle oldStyle;
}
@property (nonatomic, retain) NSString *data;
@property (nonatomic, retain) NSArray *customMenus;
@property (nonatomic, retain) NSIndexPath *indexPath;
@property (nonatomic, assign) id<CopyableCellDelegate> delegate;
- (void) copyToPastboard:(NSString *)dataText;
@end
@protocol CopyableCellDelegate<NSObject>
@required
- (void) copyableCell:(CopyableCell *)cell selectCellAtIndexPath:(NSIndexPath *)indexPath;
- (void) copyableCell:(CopyableCell *)cell deselectCellAtIndexPath:(NSIndexPath *)indexPath;
@optional
- (NSString *) copyableCell:(CopyableCell *)cell dataForCellAtIndexPath:(NSIndexPath *)indexPath;
@end
aquí es encabezado clase de ayuda:
#import <Foundation/Foundation.h>
@interface NamedAction : NSObject {
NSString *name;
SEL action;
}
@property (nonatomic, retain) NSString *name;
@property (nonatomic, assign) SEL action;
- (id)initWithName:(NSString *)_name action:(SEL)_action;
@end
Implementación:
#import "NamedAction.h"
@implementation NamedAction
@synthesize name, action;
- (id)initWithName:(NSString *)_name action:(SEL)_action
{
if (self = [super init]) {
self.name = _name;
self.action = _action;
}
return self;
}
- (void)dealloc {
self.name = NULL;
self.action = NULL;
[super dealloc];
}
@end
@ nacho4d: Gracias por su respuesta. Mi clase es UITableViewController. SO I set "[theMenu setTargetRect: cell.frame inView: [self view]]". Pero no funciona. Intenté [self tableView], de nuevo, no funciona. ¿Qué vista tengo que establecer allí? – EmptyStack
@ nacho4d: UIMenuControllerWillShowMenuNotification se activa correctamente. No estoy seguro de que se muestre o no? Pero no es visible. ¿Cómo hacer que sea visible? – EmptyStack
@ nacho4d: Imprimí x, y, ancho y alto de menuFrame. Muestra 0 para ancho.Lo estoy configurando correctamente en el método setTargetRect: inView :. Pero el ancho muestra 0 al imprimirlo. ¿Alguna idea de por qué sucede esto? – EmptyStack