Customize select,copy/paste in iPad - ipad

I am working on eBook App in iPad,And using UIMenuController.And i want to customize select,copy and paste function which default in menu-controller. I am not able to customize that function Please help me out with source code
Thanks
Kunal

Derive UITextView as follows.
//MyUITextView.h
#import <Foundation/Foundation.h>
#interface MyUITextView : UITextView {
}
#end
//MyUITextView.m
#import "MyUITextView.h"
#implementation MyUITextView
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if (action == #selector(menu1:))
return YES;
if (action == #selector(menu2:))
return YES;
return NO;//[super canPerformAction:action withSender:sender];
}
- (void)menu1:(id)sender
{
NSLog(#"in menu1");
}
- (void)menu2:(id)sender
{
NSLog(#"in menu2");
}
#end
In your view controller under viewDidLoad
UIMenuItem *menu1 = [[[UIMenuItem alloc] init]autorelease];
menu1.title = #"MyMenu1";
menu1.action = #selector(menu1:);
UIMenuItem *menu2 = [[[UIMenuItem alloc] init]autorelease];
menu2.title = #"MyMenu2";
menu2.action = #selector(menu2:);
UIMenuController* mc = [UIMenuController sharedMenuController];
mc.menuItems = [NSArray arrayWithObjects: menu1, menu2, nil];
You need to assign class to your TextView from interfacebuilder if it is on nib and if you create it dynamically create object of MyUITextView instead of UITextView.
Above code adds 2 custom menu while you select text and when you select option it will fire selector accordingly.
Hope it helps.

Related

UITextField, hided Keyboard, TopBar still there

i have a VC with a UITextField. Thats my Code:
.h
#interface GameOverViewController : UIViewController <UITextFieldDelegate> {
}
.m
#implementation UITextField (DisableCopyPaste)
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
return NO;
return [super canPerformAction:action withSender:sender];
}
#end
#implementation GameOverViewController
NSString *text1;
text1 = #"";
UIView* testView = [[UIView alloc] init];
_nameField.inputView = testView;
[_nameField becomeFirstResponder];
_nameField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
This is for hiding the Keyboard:
UIView* testView = [[UIView alloc] init];
_nameField.inputView = testView;
But now there is still the TopBar of the Keyboard on my View:
If i take out this two lines of code, the whole Keyboard appears:
i can't get it hided. i don't want this bar.
if i disable the UITextField, the Bar is gone.
Found the solution:
in iOS 9 there is an UITextInoutAssistantItem, and here is my Solution for this Bar:
if ([self respondsToSelector:#selector(inputAssistantItem)]) {
UITextInputAssistantItem *item = [self inputAssistantItem];
item.leadingBarButtonGroups = #[];
item.trailingBarButtonGroups = #[];
}

iOS - Copying a UITextView

In my app users can send messages to each other. I use UITextView inside of a bubble image to display the chat history.
[messageTextView setFrame:CGRectMake(padding, padding+5, size.width, size.height+padding)];
[messageTextView sizeToFit];
messageTextView.backgroundColor=[UIColor clearColor];
UIImage *img = [UIImage imageNamed:#"whiteBubble"];
UIImageView *bubbleImage=[[UIImageView alloc] initWithImage:[img stretchableImageWithLeftCapWidth:24 topCapHeight:15]];
messageTextView.editable=NO;
[bubbleImage setFrame:CGRectMake(padding/2, padding+5,
messageTextView.frame.size.width+padding/2, messageTextView.frame.size.height+5)];
[cell.contentView addSubview:bubbleImage];
[cell.contentView addSubview:messageTextView];
Currently, when a user holds down on the message text, they see the 'Copy' and 'Define' options with cursors to select text.
However, I would rather have the basic iOS messaging option of holding down on a chat bubble to copy the entire message. How can this be achieved?
I would subclass UITextView to implement your own version of the copy menu. You can do it a number of ways, but one possible way is like below.
The basic idea is that the text view sets up a UILongPressGestureRecognizer that will create the popup menu when a long press is detected.
UILongPressGestureRecognizer has several default system menus that will show up unless you tell them not to. The way to do that is to return NO for any selectors that you don't want to handle in canPerformAction:withSender:. In this case, we're returning NO for any selector except for our custom copyText: selector.
Then that selector just gets a reference to the general UIPasteboard and sets it's text to the text of the TextView.
In your subclass's implementation:
#implementation CopyTextView
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
[self setup];
}
return self;
}
- (instancetype)init
{
self = [super init];
if (self) {
[self setup];
}
return self;
}
- (void)setup {
self.editable = NO;
self.selectable = NO;
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPressDetected:)];
longPress.minimumPressDuration = 0.3f; // however long, in seconds, you want the user to have to press before the menu shows up
[self addGestureRecognizer:longPress];
}
- (void)longPressDetected:(id)sender {
[self becomeFirstResponder];
UILongPressGestureRecognizer *longPress = (UILongPressGestureRecognizer *)sender;
if (longPress.state == UIGestureRecognizerStateEnded) {
UIMenuItem *menuItem = [[UIMenuItem alloc] initWithTitle:#"Copy" action:#selector(copyText:)];
UIMenuController *menuCont = [UIMenuController sharedMenuController];
[menuCont setTargetRect:self.frame inView:self.superview];
menuCont.arrowDirection = UIMenuControllerArrowDown;
menuCont.menuItems = [NSArray arrayWithObject:menuItem];
[menuCont setMenuVisible:YES animated:YES];
}
}
- (BOOL)canBecomeFirstResponder { return YES; }
- (void)copyText:(id)sender {
UIPasteboard * pasteboard = [UIPasteboard generalPasteboard];
[pasteboard setString:self.text];
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
if (action == #selector(copyText:)) return YES;
return NO;
}
#end
Useful documentation:
UILongPressGestureRecognizer Documentation
UIMenuController Documentation

Objective C Subclass UITextField to copy only

I'm trying to create a class that makes a read only text field that allows the user to copy its contents. Here is my code:
CopyOnly.h
#import <UIKit/UIKit.h>
#interface CopyOnly : UITextField
#end
CopyOnly.m
#import "CopyOnly.h"
#implementation CopyOnly
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self attachTapHandler];
}
return self;
}
- (void) attachTapHandler
{
[self setUserInteractionEnabled:YES];
UIGestureRecognizer *touchy = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
[self addGestureRecognizer:touchy];
}
- (BOOL) canPerformAction: (SEL) action withSender: (id) sender
{
return (action == #selector(copy:));
}
- (void) handleTap: (UIGestureRecognizer*) recognizer
{
[self becomeFirstResponder];
UIMenuController *menu = [UIMenuController sharedMenuController];
[menu setTargetRect:self.frame inView:self.superview];
[menu setMenuVisible:YES animated:YES];
}
- (void)copy:(id)sender
{
UIPasteboard *board = [UIPasteboard generalPasteboard];
[board setString:self.text];
self.highlighted = NO;
[self resignFirstResponder];
}
- (BOOL) canBecomeFirstResponder
{
return YES;
}
#end
This works great, only the keyboard is coming up. I don't want any keyboard to come up.
I tried adding this to initWithFrame:
UIView* noKeyboard = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1, 1)];
self.inputView = noKeyboard;
This does not give me the result I'm expecting. Anyone know how I can do this?
Extending on my comment. This is easily accomplished using a UITextView (not UITextField) with editable property set to NO.
UITextView* tf = [[UITextView alloc] initWithFrame:CGRectMake(50, 50, 200, 50)];
tf.editable = NO;
tf.text = #"Hey this is a test!";
[self.view addSubview:tf];
Adding this to -(BOOL)canBecomeFirtResponder seemed to do the trick. Hacky, but it works.
- (BOOL) canBecomeFirstResponder
{
UIView* noKeyboard = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1, 1)];
self.inputView = noKeyboard;
return YES;
}
If you stuck with text field that doesn't allow editing try totally different approach. Follow instructions in this article http://nshipster.com/uimenucontroller/ to implement UILabel that supports copying.

objective c remove copy button from menu bar

I'm writing an application that uses webkit to read epubs. When I'm selecting text by long press , the menu bar opens, and there should only be Facebook, and Twitter buttons. So here is my code how do I did it :
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
if (action == #selector(facebookItemClicked:) || action == #selector(twitterItemClicked:)) {
return YES;
}else if (action == #selector(copy:)){
NSLog(#"copy");
} return NO;}
Here is how I initialize menu Items
UIMenuItem *facebookMenuItem = [[UIMenuItem alloc] initWithTitle:#"Facebook" action:#selector(facebookItemClicked:)];
UIMenuItem *twitterMenuItem = [[UIMenuItem alloc] initWithTitle:#"Twitter" action:#selector(twitterItemClicked:)];
But the problem is that copy selector never appears it as action so I cannot catch it and every time menu bar is shown there is also a copy button beside Facebook and Twitter.
It would be great if someone could help me.
Thanks in advance.
Solved problem.
Default UIWebView was overriding my menuBar actions. So I created a class CustomWebView inherited from UIWebView added
+ (void)initialize{
UIMenuItem *itemA = [[UIMenuItem alloc] initWithTitle:#"A" action:#selector(a:)];
UIMenuItem *itemB = [[UIMenuItem alloc] initWithTitle:#"B" action:#selector(b:)];
[[UIMenuController sharedMenuController] setMenuItems:[NSArray arrayWithObjects:itemA, itemB, nil]];
// [itemA release];
// [itemB release];
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
BOOL can = [super canPerformAction:action withSender:sender];
if (action == #selector(a:) || action == #selector(b:))
{
can = YES;
}
if (action == #selector(copy:))
{
can = NO;
}
NSLog(#"%# perform action %# with sender %#.", can ? #"can" : #"cannot", NSStringFromSelector(action), sender);
return can;
}
which overrides menubar actions in webview and then I use this CustomWebView in other classes that use webvew.

iOS: How to get the selected UIMenuItem from UIMenuController

I am trying to use UIMenuCnotroller to show a list of dynamically generated items, they share the same action method, and so I need to know which item is selected in the single action method.
However, in the action method - (void)menuItemAction:(id)sender;the sender is actually the UIMenuController object, and I didn't find any method of UIMenuController can tell me which menuitem is selected.
One solution I can think of is to dynamically generate different action selectors for different items, and do some tricks in forwardInvocation
But is there any easier way?
You can use UIMenuCnotroller like:
1) creation:
UIMenuController *menuController = [UIMenuController sharedMenuController];
UIMenuItem *open = [[UIMenuItem alloc] initWithTitle:#"Open" action:#selector(open:)];
UIMenuItem *reDownload = [[UIMenuItem alloc] initWithTitle:#"Re-Download" action:#selector(reDownload:)];
[menuController setMenuItems:[NSArray arrayWithObjects:open, reDownload, nil]];
[menuController setTargetRect:cell.frame inView:self.view];
[menuController setMenuVisible:YES animated:YES];
[open release];
[reDownload release];
2) To catch actions should implement next methods:
- (BOOL) canPerformAction:(SEL)selector withSender:(id) sender
{
if (selector == #selector(open:))
{
return YES;
}
if (selector == #selector(reDownload:))
{
return YES;
}
return NO;
}
- (BOOL) canBecomeFirstResponder
{
return YES;
}
3) And realization of yours methods:
- (void) open:(id) sender
{
[self doSomething];
}
- (void) reDownload:(id) sender
{
[self doSomething];
}
Hope, this helps.
Okay, I've solved this one. It involves messing with [NSObject forwardInvocation:] and is a bit dirty, but the resulting code is quite minimal. Answered over here: https://stackoverflow.com/a/9874092/790036
One easiest way would be to use different #selector method for each menu item
Examples:
UIMenuItem *oneObj = [[UIMenuItem alloc] initWithTitle:#"One" action:#selector(One:)];
UIMenuItem *twoObj = [[UIMenuItem alloc] initWithTitle:#"Two" action:#selector(Two:)];

Resources