I have a UITextField subclass object and leftView with leftViewMode set to UITextFieldViewModeUnlessEditing. However, the left view remains visible during editing until the user enters at least one character.
Before entering text:
After entering Text:
Questions:
Is this behavior expected and documented? How can I ensure that the
left view is invisible during editing, before any character is
entered?
In answer to your questions:
Yes, that appears to be expected UITextField behavior, though it's not clearly spelled out in any official documentation that I could find.
You can further customize the default behavior by implementing UITextFieldDelegate methods to, for example, remove the overlay view as soon as editing begins, even if the text field is empty.
For example, let's assume you defined a property to hold a strong reference to a custom overlay view:
#interface ViewController () <UITextFieldDelegate>
#property (strong, nonatomic) IBOutlet UITextField *textField;
#property (strong, nonatomic) UIView *customView;
#end
You could then configure the overlay view and register for delegate notifications in viewWillAppear:, as shown below:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.customView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 30.0, 30.0)];
self.customView.backgroundColor = [UIColor orangeColor];
self.textField.leftView = self.customView;
self.textField.leftViewMode = UITextFieldViewModeUnlessEditing;
self.textField.delegate = self;
}
To make the overlay view disappear as soon as the user touches the text field, set the leftView (or rightView) property to nil when editing begins. Just make sure to set it to point to your custom view again when editing ends.
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
self.textField.leftView = nil;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
self.textField.leftView = self.customView;
}
Edit
A more generalized approach would be to simply toggle the mode on editing beginning and ending, which would eliminate the need to maintain a reference to the overlay view.
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
self.textField.leftViewMode = UITextFieldViewModeNever;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
self.textField.leftViewMode = UITextFieldViewModeUnlessEditing;
}
Please try this code with UITextFieldViewModeAlways and assign padding with as par star image width.
Put this code in viewDidLoad method
UIImageView *iView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#" "]];
[UITextField appearanceWhenContainedIn:[UISearchBar class], nil].leftView = iView;
It will manage place holder text as well as textField text with left padding.
I hope it will help you.
You need to set Mode of textfield after that it will work perfect. So use this one
leftViewMode = UITextFieldViewModeAlways;
instead of
leftViewMode = UITextFieldViewModeUnlessEditing;
create leftview
UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 20)];
textField.leftView = paddingView;
textField.leftViewMode = UITextFieldViewModeAlways;
and you can add UIImageView on this paddingView for your star.png
UIImageView *img=[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"star.png"]];
img.frame=CGRectMake(0, 0,5, 20);
[paddingView adsubview:img];
Related
I've placed a UIButton inside a custom UIView, CustomButtonView. The UIButton is not responding to tap/click events, and its appropriate selector method is not being triggered. Here's my code below; what have I done wrong?
As well, the custom view has a background color of red. When I add the custom view to my view controller's view, the red rectangle displays. However, when I add my UIButton to my custom view (with the background color of red), only the UIButton displays, not the red rectangle. Why is this happening?
//
// CustomButtonView.h
//
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
#interface CustomButtonView : UIView
#property (strong, nonatomic) UIImageView *buttonImageView;
#property (strong, nonatomic) UIButton *button;
#end
NS_ASSUME_NONNULL_END
//
// CustomButtonView.m
//
#import "CustomButtonView.h"
#implementation CustomButtonView
- (instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor redColor];
_button = [UIButton buttonWithType:UIButtonTypeSystem];
_button.backgroundColor = [UIColor greenColor];
[_button setTitle:#"john doe" forState:UIControlStateNormal];
[_button setTitle:#"john doe" forState:UIControlStateHighlighted];
_button.translatesAutoresizingMaskIntoConstraints = NO;
_button.titleLabel.font = [UIFont boldSystemFontOfSize:14.0];
_button.titleLabel.textColor = [UIColor whiteColor];
self.userInteractionEnabled = NO;
self.button.userInteractionEnabled = YES;
//[self addSubview:_button];
//[_button.topAnchor constraintEqualToAnchor:self.topAnchor].active = YES;
//[_button.leadingAnchor constraintEqualToAnchor:self.leadingAnchor].active = YES;
}
return self;
}
#end
//
// ViewController.m
// TestApp
//
//
#import "ViewController.h"
#import "CustomButtonView.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor yellowColor];
_customButtonView = [[CustomButtonView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
_customButtonView.backgroundColor = [UIColor redColor];
_customButtonView.translatesAutoresizingMaskIntoConstraints = NO;
[_customButtonView.button addTarget:self action:#selector(customButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_customButtonView];
}
- (void)customButtonTapped:(id)sender{
NSLog(#"Button tapped!");
}
#end
Here are some screenshots, below. Please click on the links.
When I display the UIButton inside the custom-view, only the button displays. The red rectangle of the custom-view doesn't display.
When I simply add the custom-view to my view-controller (ie with no UIButton added to the custom view), the red rectangle of the custom-view displays.
When you disable user interaction for a specific view then this user interaction is not forwarded to its subviews. Or in other words; for user interaction to work you need to make sure that all superviews in chain (superview of superview of superview) do have user interaction enabled.
In your case you have self.userInteractionEnabled = NO; which means that any subview of self (including your button) will not accept any user interaction.
Next to this issues it is still possible that other issues are present. For instance: A subview will accept user interaction only within physical area of all of its superviews. That means that if a button with frame { 0, 0, 100, 100 } is placed on a superview of size { 100, 50 } then only the top part of the button will be clickable.
As for the size changes this is a completely different story...
You decided to disable translation of autoresizing mask on your custom view by writing _customButtonView.translatesAutoresizingMaskIntoConstraints = NO;. That means that you will not use frame in conjunction with other constraints. It means that whatever frame you set (in your case CGRectMake(0, 0, 100, 100)) this frame will be overridden by anything else that may effect the frame of your custom view.
In case where your button code is commented out there is no such thing that "may effect the frame of your custom view" and the view stays as size of { 100, 100 }. But as soon as you added a button you added additional constraints which most likely lead to resizing your button to sizeToFit and with it its superview which is your custom view.
To avoid this you need to either remove disabling of translation of autoresizing mask into constraint on your custom view. Or you need to define custom view size by adding constraints to it so that they are set to { 100, 100 }. You can simply constrain heightAnchor and widthAnchor to 100.
I have a GameOver UIView that I call from inside my main UIViewController. It is just a 'popover' window that has the text game over, the score, and some blur effects to blur the main UIViewcontroller.
I try to pass an int to the UIView, but it doesn't accept it unless it is in the - (void)drawRect:(CGRect)rect method.
If I move the score label to drawRect method, the label is updated. But the blur effects go away.
What am I doing wrong?
MainViewController.m
#import "GameOverView.h"
#interface ViewController () {
GameOverView * gov;
}
- (void) showGameOver {
gov = [[GameOverView alloc] initWithFrame:self.view.bounds];
NSLog(#"Passing score of: %i", self.score);
gov.finalScore = self.score;
[self.view addSubview:gov];
}
GameOverView.h
#interface GameOverView : UIView {}
#property (nonatomic) int finalScore;
#end
GameOverView.M
#implementation GameOverView
- (id) initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code
//self.backgroundColor = [UIColor redColor];
NSLog(#"Score:%i", self.finalScore );
UIVisualEffect *blurEffect;
blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *visualEffectView;
visualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
visualEffectView.frame = super.bounds;
[super addSubview:visualEffectView];
UILabel * lblGameOver = [[UILabel alloc] initWithFrame:CGRectMake(0,0, frame.size.width, 200)];
lblGameOver.center = CGPointMake(frame.size.width/2, 100);
lblGameOver.text = [NSString stringWithFormat: #"GAME OVER %i", self.finalScore];
[self addSubview:lblGameOver];
UIButton * button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, 200)];
button.center = CGPointMake(frame.size.width/2, 200);
[button setTitle:#"Start New Game" forState:UIControlStateNormal];
[button addTarget:self action:#selector(removeSelfFromSuperview) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:button];
}
return self;
}
- (void) removeSelfFromSuperview{
[self removeFromSuperview];
}
You are using the finalScore property in the init method of the GameOverView class, but you are only setting its value after initializing it.
Change your initialization method to
- (id) initWithFrame:(CGRect)frame finalScore:(int)fs{
// use 'fs' instead of 'self.finalScore'
}
It should work.
I wonder how there isn't any problem with the view background color. You are initializing the view and adding it as subview like this:
gov = [[GameOverView alloc] initWithFrame:self.view.bounds];
gov.finalScore = self.score;
[self.view addSubview:gov];
This will give the view background color as black which is default color. So you don't find much difference if you use blur effect.
you need to give the color for the view during the initialization :
gov = [[GameOverView alloc] initWithFrame:self.view.bounds];
[gov setBackgroundColor:[UIColor yourColor]];
[self.view addSubview:gov];
If you are planning to keep the code in initWithFrame, you don't need to worry about setting the background color. If you keep the code in drawRect, then you must set the background color,else it will be black color.
When coming to setting the score label, it doesn't matter whether you put it in drawRect or initWithFrame method. Make sure you use drawRect method only if you really have to draw on the view,so that you can call it later by using setNeedsDisplay
This question already has answers here:
Add lefthand margin to UITextField
(9 answers)
Padding in UITextField
(1 answer)
Closed 8 years ago.
I am adding a UITextField programatically into a tableViewCell and currently the cursor starts right up against the left hand side of the textField. The textFields I have added using the xib file always have a gap here.
Does anyone know how to apply this gap manually?
This is my textField:
This is what I want my textField to look like:
Also are there any specifics on the expected dimensions, font, color or a UITextField?
I think the height should be 31 but I'm not sure what other characteristics I should set to make my custom one look like the added xib one.
Thanks for your help :)
EDIT:
Thanks for the help - looking at the answers provided my situation is slightly different as I am using keepLayout rather than setting up a frame with a rectangle. Is there any way to solve this using keepLayout or do I need to use a frame?
use category for that follow the Bellow steps. You can create category like this:-
#import <UIKit/UIKit.h>
#interface UITextField (mytextFiled)
- (CGRect)textRectForBounds:(CGRect)bounds;
- (CGRect)editingRectForBounds:(CGRect)bounds;
#end
.m file
#import "UITextField+bgImageset.h"
#implementation UITextField (mytextFiled)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
- (CGRect)textRectForBounds:(CGRect)bounds {
return CGRectMake(bounds.origin.x + 20, bounds.origin.y + 5,
bounds.size.width - 20, bounds.size.height - 10);
}
- (CGRect)editingRectForBounds:(CGRect)bounds {
return [self textRectForBounds:bounds];
}
#end
using above category that my textfiled Look's Like bellow I am setting image for textfiled so that look bit different..
The way I achieved this in a recent app is this -
usernameTextField = [[UIView alloc]
initWithFrame:CGRectMake(0.0f, 0.0f, 10.0f, 40.0f)];
usernameTextField.leftView.backgroundColor = [UIColor clearColor];
usernameTextField.leftViewMode = UITextFieldViewModeAlways;
It is not a good practice to extend UITextField with a category as discussed here.
This can be done by using a textField.leftView here you add any view i.e. image or empty view just like
txtField.leftViewMode = UITextFieldViewModeAlways;
txtField.leftView = imageView;
My answer is similar to #Nitin's. But instead of creating a category, I have subclassed UITextField to achieve :
The code is as follows :
.h :
#import <UIKit/UIKit.h>
#interface W3BTextField : UITextField
#property (nonatomic, assign) UIEdgeInsets edgeInsets;
#end
.m :
#import "W3BTextField.h"
#implementation W3BTextField
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.edgeInsets = UIEdgeInsetsMake(6.5, 10, 6.5, 5);
}
return self;
}
- (CGRect)textRectForBounds:(CGRect)bounds {
return [super textRectForBounds:UIEdgeInsetsInsetRect(bounds, self.edgeInsets)];
}
- (CGRect)editingRectForBounds:(CGRect)bounds {
return [super editingRectForBounds:UIEdgeInsetsInsetRect(bounds, self.edgeInsets)];
}
#end
Now all this is done programmatically, without using XIBs/storyboards.
Used in class like this :
W3BTextField* registrationFullName = [[W3BTextField alloc] initWithFrame:CGRectMake(30, 25, 260, 35)];
registrationFullName.placeholder = #"Full name";
registrationFullName.font = [UIFont fontWithName:#"HelveticaNeue" size:15];
registrationFullName.textColor = UIColorFromRGB(0x333333);
registrationFullName.layer.cornerRadius = 1.0f;
registrationFullName.backgroundColor = [UIColor whiteColor];
registrationFullName.delegate = self;
[registrationFullName addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
I want to show UITableView on tapping of UITextView.
key board should not be shown.
the problem is on tapping UITextView both UITableView and keyboard are shown.
I want only table view to be shown. I want to display data got from web service in UITextView which is not editable.on pressing edit button in navigation bar that time on tapping UITextView ,UITableView should be popped up and not keyboard.
My code is below:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
if([text isEqualToString:#"\n"]) {
[textView resignFirstResponder];
return NO;
}
return YES;
}
-(void)textViewDidBeginEditing:(UITextView *)textView{
[self.view endEditing:YES];
tableVw=[[UITableView alloc]initWithFrame:CGRectMake(0, 0, 320, 500)];
tableVw.dataSource=self;
tableVw.delegate=self;
[self.view addSubview:tableVw];
}
-(void)viewDidLoad{
[super viewDidLoad];
txtVwDescription=[[UITextView alloc]initWithFrame:CGRectMake(10, 270, 300,stringSize.height+10)];
txtVwDescription.backgroundColor=[UIColor clearColor];
txtVwDescription.layer.cornerRadius=5;
txtVwDescription.backgroundColor=[UIColor colorWithRed:0.662745 green:0.662745 blue:0.662745 alpha:0.3];
[txtVwDescription setFont:[UIFont systemFontOfSize:13.0]];
txtVwDescription.contentInset=UIEdgeInsetsMake(0, 0, 0, 0);
[txtVwDescription setUserInteractionEnabled:NO];
txtVwDescription.editable=NO;
txtVwDescription.delegate=self;
[self.view addSubview:txtVwDescription];
}
-(void)edit{
[txtVwDescription setUserInteractionEnabled:YES];
txtVwDescription.editable=NO;
[txtVwDescription resignFirstResponder];
}
you can use UITextViewDelegate's textViewShouldBeginEditing method returning NO, and presenting there the UITableView. In such a way the keyboard should not be presented.
Rather than having to mess with textViewDelegate methods, I find it easier to simply disable editing for the textView and add a gesture recognizer to it like this:
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(showTableView)];
UITextView *textView = [[UITextView alloc] initWithFrame:....];
textView.editable = NO;
[textView addGestureRecognizer:tapGestureRecognizer];
This way, no keyboard is shown and you don't have to mess around with navigation inside the delegate methods. All you need to do now is handle the tap with the method you provided the recognizer:
- (void)showTableView {
// do stuff here
}
EDIT:
You might want to also consider using a UILabel instead of a UITextView if you are not planning on making it editable at all. You can implement the same gesture recognizer code as well, just add it to the label instead of the textView.
UITextField and UITextView classes has a property named inputView for displaying custom views instead of the default keyboards. The system shows whatever UIView descendant class you set to that property when the textfield/view becomes first responder. So simply add,
UITextView *textView = [[UITextView alloc] initWithFrame:someFrame];
textView.inputView = self.myTableView; //this is your already initialised tableview
I have a little bit specific question. It might not matter for most people but I have had to deal with it and I had to solve the issue described below. I tried to find some information about it using Google and the Apple SDK documentation but did not succeed.
I was a designing a screen where there were many images in horizontal scrolls. There three three same scrolls. Every scroll had title. I have implemented custom class derived from UIView and placed there UIScrollView for scroll and UILabel for title text:
#interface MyView : UIView {
UIScrollView *iScrollView;
UIView *iTitleView;
}
I then put objects of this class on the view of a UIViewController:
#implementation MyViewController
- (void) viewDidLoad {
[super viewDidLoad];
...
iScrollViewTop = [[MyView alloc] init];
[self.view addSubview:iScrollViewTop];
...
}
#end
When I filled the internal scroll view with images and ran my application it looked OK. But there was some strange behavior. First, scroll did not have bounces as if I had set
iScrollView.bounces = NO;
and second, when I swiped to scroll, after the scroll stopped, the scroll bar did not disappear within one second. It was strange for me, because when I usually create a UIScrollView and add it to the UIViewController's view it has bounces and scroll bar disappears immediately when it stops. I tried to change UIScrollView's properties, such as directionalLockEnabled, pagingEnabled, canCancelContentTouches, delaysContentTouches, decelerationRate and others. In fact, I have tried to change almost all properties of UIScrollView but I could not get the scroll bars to immediately disappear.
If I try to add UIScrollView instead MyView to the UIViewController.view, it bounces and scroll bar disappears immediately after it stops. Also I get correct behavior if I subclass MyView from UIScrollView but in this case I cannot manage the title label because it scrolls together with other content.
So here are my questions:
Do you know why I am seeing this behavior?
How can I get "usual" behavior for scroll encapsulated by UIView?
ok, hacky code follows, so ignore all my other issues, but follow this pattern (westie.jpg = image that was 360x200)
#interface MyView : UIView
{
UIScrollView *sv;
UILabel *l;
}
-(MyView*)initWithFrame:(CGRect)frame;
#end
#implementation MyView
-(MyView*)initWithFrame:(CGRect)frame;
{
self = [super initWithFrame:frame];
sv = [[UIScrollView alloc] initWithFrame:CGRectMake(0,0,360,200)];
sv.scrollEnabled = YES;
sv.contentSize = CGSizeMake(360*3,200);
[self addSubview:sv];
UIImage *i1 = [UIImage imageNamed:#"westie.jpg"];
UIImageView *iv1 = [[UIImageView alloc] initWithImage:i1];
iv1.frame = CGRectMake(360*0, 0, 360, 200);
[sv addSubview:iv1];
UIImageView *iv2 = [[UIImageView alloc] initWithImage:i1];
iv2.frame = CGRectMake(360*1, 0, 360, 200);
[sv addSubview:iv2];
UIImageView *iv3 = [[UIImageView alloc] initWithImage:i1];
iv3.frame = CGRectMake(360*2, 0, 360, 200);
[sv addSubview:iv3];
l = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 100, 20)];
l.text = #"Hello World";
l.backgroundColor = [UIColor blueColor];
[self addSubview:l];
return self;
}
#end
later, in your outer view creation:
[window addSubview:[[MyView alloc] initWithFrame:CGRectMake(0, 20, 360, 200)]];