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.
Related
custom UITextField: In the click TextField input,After the keyborad popup,enter the background to get enter foreground again,The app crash!
if you don't click TextField input,background or foreground conversion ,It is normal;Part of the code:
#implementatio BKSearchViewController
- (void)setNavgationView {
BKSearchBar *searchBar = [[BKSearchBar alloc] initWithFrame:CGRectMake(20, 27, kScreenWidth - 90, 30)];
searchBar.placeholder = #"输入昵称/拜托号";
searchBar.delegate = self;
[searchBar setKeyboardType:UIKeyboardTypeDefault];
[searchBar setReturnKeyType:UIReturnKeySearch];
[searchBar setPlaceholderColor:kcallColor(#"a4a4a4")];
[searchBar setPlaceholderFont:kFont(14)];
[searchBar addTarget:self action:#selector(SearchTextFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
[navgationView addSubview:searchBar];
}
#end
//BKSearchBar The key code
#implementation BKSearchBar
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// 设置背景
self.backgroundColor = kcallColor(#"7d1d57");
self.returnKeyType = UIReturnKeySearch;
// 设置内容 -- 垂直居中
self.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
[self UI];
}
return self;
}
- (void)UI{
// 设置左边显示一个放大镜
UIImageView *leftView = [[UIImageView alloc] init];
omit...
//右边的view
UIImageView *rightView = [[UIImageView alloc] init];
omit...
}
- (CGRect)placeholderRectForBounds:(CGRect)bounds{
CGRect rect = CGRectMake(self.leftView.right, (self.height - 24) / 2, bounds.size.width, 14);
return rect;
}
- (void)clearText{
self.text = nil;
}
- (void)setPlaceholderColor:(UIColor *)color{
[self setValue:color forKeyPath:#"_placeholderLabel.textColor"];
}
- (void)setPlaceholderFont:(UIFont *)font{
[self setValue:font forKeyPath:#"_placeholderLabel.font"];
}
Thank all!The problem is resolved!because of the runtime!
+ (void)swizzleInstanceMethod:(Class)class originSelector:(SEL)originSelector otherSelector:(SEL)otherSelector
{
Method otherMehtod = class_getInstanceMethod(class, otherSelector);
Method originMehtod = class_getInstanceMethod(class, originSelector);
// 交换2个方法的实现
method_exchangeImplementations(otherMehtod, originMehtod);
}
When I bring up a UIImagePickerController and then close it, it duplicates the content in my modal window. Below are the before and after pictures:
Here's the code that shows the image picker:
-(void) choosePhotos
{
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
[imagePicker setDelegate:self];
[imagePicker setAllowsEditing:YES];
[imagePicker setSourceType:UIImagePickerControllerSourceTypeCamera];
[self presentViewController:imagePicker animated:YES completion:nil];
}
Here's the rest of my code (if needed):
-(id) init
{
self = [super init];
if (self)
{
[self.navigationItem setTitle:#"Deposit"];
UIBarButtonItem *closeButton = [[UIBarButtonItem alloc] initWithTitle:#"Cancel" style:UIBarButtonItemStyleDone target:self action:#selector(cancel)];
[self.navigationItem setLeftBarButtonItem:closeButton];
toItems = #[#"Account...5544", #"Account...5567"];
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(hideKeyboard)];
[self.view addGestureRecognizer:recognizer];
}
return self;
}
-(void) hideKeyboard
{
for (UITextField *field in [scrollView subviews])
{
[field resignFirstResponder];
}
}
-(void) cancel
{
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return [toItems count];
}
-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return [toItems objectAtIndex:row];
}
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
[self.view setBackgroundColor:[UIColor whiteColor]];
UILabel *toLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 0, 50, 100)];
[toLabel setText:#"To:"];
toPicker = [[UIPickerView alloc] initWithFrame:CGRectMake(130, -30, 220, 100)];
[toPicker setDataSource:self];
[toPicker setDelegate:self];
UILabel *amountLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 100, 70, 100)];
amountLabel.lineBreakMode = NSLineBreakByWordWrapping;
amountLabel.numberOfLines = 0;
[amountLabel setText:#"Check Amount:"];
UITextField *amountField = [[UITextField alloc] initWithFrame:CGRectMake(130, 100, 270, 100)];
[amountField setPlaceholder:#"Enter Amount"];
[amountField setReturnKeyType:UIReturnKeyDone];
[amountField setKeyboardType:UIKeyboardTypeDecimalPad];
UILabel *imagesLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 200, 70, 100)];
imagesLabel.lineBreakMode = NSLineBreakByWordWrapping;
imagesLabel.numberOfLines = 0;
[imagesLabel setText:#"Check Images:"];
UIButton *imagesButton = [[UIButton alloc] initWithFrame:CGRectMake(120, 200, 244, 99)];
[imagesButton setBackgroundImage:[UIImage imageNamed:#"photos.png"] forState:UIControlStateNormal];
[imagesButton addTarget:self action:#selector(choosePhotos) forControlEvents:UIControlEventTouchUpInside];
CGRect bounds = [[UIScreen mainScreen] bounds];
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, bounds.size.width, bounds.size.height)];
[scrollView setAlwaysBounceVertical:YES];
[scrollView setShowsVerticalScrollIndicator:YES];
[scrollView addSubview:toLabel];
[scrollView addSubview:toPicker];
[scrollView addSubview:amountLabel];
[scrollView addSubview:amountField];
[scrollView addSubview:imagesLabel];
[scrollView addSubview:imagesButton];
[self.view addSubview:scrollView];
}
I recommend you use viewDidLoad as the place to create and add your views:
- (void)viewDidLoad {
[super viewDidLoad];
//init and add your views here
//example view
self.someLabel = [[UILabel alloc] init];
self.someLabel.text = #"someExampleText";
[self.view addSubview:self.someLabel];
}
And either viewWillAppear or viewDidLayoutSubviews as the place to configure their sizes (i prefer viewDidLayoutSubviews so i'll use it as an example):
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.someLabel.frame = CGRectMake(kMargin,kMargin,kLabelWidth,kLabelHeight);
}
Of course, in order to do this you need to have a reference to all the views you wish to configure this way by creating a property to them in the interface:
#interface YourViewController ()
#property (nonatomic, strong) UILabel *someLabel;
#end;
static CGFloat const kMargin = 20.0f;
static CGFloat const kLabelHeight = 30.0f;
static CGFloat const kLabelWidth = 100.0f;
Also, it is recommended you avoid using hard coded values for their sizes (doing it like CGRectMake(20,20,100,70) but this it not completely wrong.
Not using hard coded values does not mean setting them yourself, it just means to make their values more readable (and on most cases, dynamic).
In my example, i created kMargin, kLabelHeight and kLabelWidth, meaning that anyone who looks at this code will understand what they mean, they will know what to change if needed, and these values can be used in other places.
For example, you could have 4 labels, and in order to keep them all following the same layout rules, all of them will use the kMargin value on the origin.x.
You could also, instead of using a static value for the width, you can implement a dynamic value, like this:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
CGFloat labelWidth = self.view.bounds.size.width - (kMargin * 2);
self.someLabel.frame = CGRectMake(kMargin,kMargin,labelWidth,kLabelHeight);
}
What i did here is to make my label to have the same width as my super view, but i made it account for the left and the right margins (by taking the total view width and reducing twice the margin value).
Since we are doing this on the viewDidLayoutSubviews method, which gets called whenever the superview changes its size (for example, orientation change) this will ensure your UILabel can be shown on any size of view and orientation without extra code to handle 'specific cases'.
Your UI elements are being added to your view every time viewWillAppear is called. This is called when your image picker dismisses and returns to your view, so they're being duplicated. Either check to see whether your UI elements already exist before creating them again, or do your UI setup in the viewDidLoad method which will only be run once. You could try this perhaps, using a BOOL property to keep track:
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
if (!self.alreadyAppeared) {
self.alreadyAppeared = YES;
// Create labels and buttons
}
}
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
This question already has answers here:
iOS - Dismiss keyboard when touching outside of UITextField
(38 answers)
Closed 8 years ago.
I have one TableViewCell that has UITextField in it.
I want when click out of UITextField hidden keyboard but I don't about that.
this is my code:
#implementation TextFieldCell
#synthesize Textfield,placeholder;
- (void)awakeFromNib
{
// Initialization code
Textfield = [self makeTextField];
[self addSubview:Textfield];
placeholder = [self PlaceHolderLabel];
[self addSubview:placeholder];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (UITextField *)makeTextField
{
CGRect TextFrame = CGRectMake(0,0,300,80);
UITextField *textfield = [[UITextField alloc]initWithFrame:TextFrame];
textfield.delegate = self;
textfield.textColor = [UIColor colorWithRed:0/256.0 green:84/256.0 blue:129/256.0 alpha:1.0];
textfield.backgroundColor = [UIColor yellowColor];
textfield.placeholder = [NSString stringWithFormat:#"Mamal"];
UIView *spacerleftView = [[UIView alloc] initWithFrame:CGRectMake(0,0,20,20)];
UIView *spacerrightView = [[UIView alloc] initWithFrame:CGRectMake(0,0,20,20)];
[textfield setLeftViewMode:UITextFieldViewModeAlways];
[textfield setRightViewMode:UITextFieldViewModeAlways];
textfield.leftView = spacerleftView;
textfield.rightView = spacerrightView;
return textfield;
}
- (UILabel *)PlaceHolderLabel{
NSString *labelText = Textfield.placeholder;
Textfield.placeholder = nil;
CGRect labelFrame = CGRectMake(0,0,280,80);
UILabel *placeholderLabel = [[UILabel alloc] initWithFrame:labelFrame];
[placeholderLabel setTextColor:[UIColor lightGrayColor]];
[placeholderLabel setText:labelText];
placeholderLabel.textAlignment = NSTextAlignmentRight;
return placeholderLabel;
}
- (UILabel *)clearPlaceHolderLabel{
NSString *labelText = nil;
CGRect labelFrame = CGRectMake(0,0,280,80);
UILabel *placeholderLabel = [[UILabel alloc] initWithFrame:labelFrame];
[placeholderLabel setText:labelText];
return placeholderLabel;
}
-(void)textFieldDidBeginEditing:(UITextField *)textField {
//Keyboard becomes visible
//perform actions.
NSLog(#"start");
}
-(void)textFieldDidEndEditing:(UITextField *)textField{
NSLog(#"end");
}
Add gesture recogniser in viewDidLoad :
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(closeKeyboard:)];
[self.view addGestureRecognizer:tap];
and then implement closeKeyboard:
- (IBAction)closeKeyboard:(id)sender {
[self.view endEditing:YES];}
my friend I had this problem but I can solve that.
you don't need add UITextField in TableViewCell , you can create TextField in ViewController or TableViewController that your tableView is inner it and then add TextField inside any cell that you want.
like this code:
ViewController.h
#interface ViewController : UIViewController <UITableViewDataSource,UITableViewDelegate,UITextFieldDelegate>
#property (nonatomic,strong) UITableView *table;
#property (weak,nonatomic) UITextField *Textfield;
ViewController.m
#implementation ViewController
#synthesize table,Textfield;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//add table in view
table = [self makeTableView];
[self.view addSubview:table];
[self.view setBackgroundColor: RGB(193,60,46)]; //will give a UIColor objct
//run textfield programmatically
Textfield = [self makeTextField];
//hide keyboard with hideKeyboard selector
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(hideKeyboard)];
[self.table addGestureRecognizer:gestureRecognizer];
}
- (void) hideKeyboard {
[Textfield resignFirstResponder];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.view endEditing:YES];
}
Try to use
[self.view setEditing:YES];
in -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
try this:
// somewhere in viewDidLoad
UITapGestureRecognizer * tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapOnBackground)];
[self.view addGestureRecognizer:tapRecognizer];
self.view.userInteractionEnabled = YES;
// ...
- (void)tapOnBackground
{
[self.view endEditing:YES];
}
Add this code in your textField implementation method.
//Set to Remove Keyboard from view
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(dismissKeyboard)];
[self.view addGestureRecognizer:tap];
After that create dismissKeyboard method.
//First Responder Remove Keyboard
-(void)dismissKeyboard {
[Textfield resignFirstResponder];
}
i have this code for textFieldShouldEndEditing:
-(void)textFieldDidEndEditing:(UITextField *)textField
{
NSDecimalNumber *testIfNumber = [[NSDecimalNumber alloc] initWithString:[textField text]];
if (![testIfNumber isEqualToNumber:[NSDecimalNumber notANumber]])
{
NSLog(#"%#",[testIfNumber stringValue]);
[[self labelTotal]setText:[self getTotalforRate:[expenseCategorySelected categoryRate] forAmmountField:textField]];
}
}
Now my problem is that in my ViewController I have two or more textField and when a user goes directly from one to another textField this method is not fired.
Is there a method or a way to know when I'm going from a textField to another?
Thx.
You are wrong... textFieldShouldEndEditing is not for this purpose.
Just using textFieldDidEndEditing
Do like this if u dont get
#import "ViewController.h"
#interface ViewController ()<UITextFieldDelegate>//heare set the delegate
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UITextField *textField1 = [[UITextField alloc]initWithFrame:CGRectMake(30, 40, 200, 35)];
UITextField *textField2 = [[UITextField alloc]initWithFrame:CGRectMake(30, 80, 200, 35)];
UITextField *textField3 = [[UITextField alloc]initWithFrame:CGRectMake(30, 125, 200, 35)];
textField1.placeholder = #"I am 1st field";
textField2.placeholder = #"I am 2nd field";
textField3.placeholder = #"I am 3rd field";
//set the delegate for all text fields
textField1.delegate = self;
textField2.delegate = self;
textField3.delegate = self;
textField1.tag = 100;
textField2.tag = 200;
textField3.tag = 300;
[self.view addSubview:textField1];
[self.view addSubview:textField2];
[self.view addSubview:textField3];
}
//implement the delegate methods
- (void)textFieldDidEndEditing:(UITextField *)textField
{
if(textField.tag == 100)
{
NSLog(#"i am end editing -> %#",textField.text);
}
else if (textField.tag == 200)
{
NSLog(#"i am end editing -> %#",textField.text);
}
else if (textField.tag == 300)
{
NSLog(#"i am end editing -> %#",textField.text);
}
}
Hope this helps u .. :)