iOS: Why does UITextField with setCornerRadius cut off text - ios

I'm trying to load a UITextField with rounded corners into a table view for iOS. For the most part, everything is working fine. However, the left-most character gets partially cut off due to the corner radius property. Is there a way to set a margin on the text that's inputted into a UITextField, so that it displays properly? Here's my code:
textInput = [[UITextField alloc] init];
textInput.backgroundColor = [UIColor whiteColor];
textInput.placeholder = #"example#gmail.com";
textInput.textColor = [UIColor blackColor];
textInput.keyboardType = UIKeyboardTypeEmailAddress;
textInput.returnKeyType = UIReturnKeyDone;
[[textInput layer] setBorderColor:[[UIColor whiteColor] CGColor]];
[[textInput layer] setBorderWidth:2.3];
[[textInput layer] setCornerRadius:15];
[textInput setClipsToBounds: YES];
[textInput setDelegate:self];
[self.contentView addSubview:textInput];
[textInput release];

I figured out a solution. I created a custom textfield, subclassed from UITextField:
#import "CR_customTextField.h"
#implementation CR_customTextField
- (CGRect)textRectForBounds:(CGRect)bounds {
int margin = 10;
CGRect inset = CGRectMake(bounds.origin.x + margin, bounds.origin.y, bounds.size.width - margin, bounds.size.height);
return inset;
}
- (CGRect)editingRectForBounds:(CGRect)bounds {
int margin = 10;
CGRect inset = CGRectMake(bounds.origin.x + margin, bounds.origin.y, bounds.size.width - margin, bounds.size.height);
return inset;
}
#end

Use this
[textInput sizeToFit];
it May Helps you

textInput.layer.sublayerTransform = CATransform3DMakeTranslation(5, 0, 0);
//helps to start writing text from given pixel

Related

ios Setting the RoundCorner does not work after override drawRect,but normal UIView is ok

I wrote an example about Wave Animation.The animation is ok,but I don't understand why the custom UIView needs to add "self.layer.masksToBounds = YES" to have the round Corner.
This is a custom UIView. I have rewritten its drawRect. If i don't set "masksToBounds" to YES, the round corner disappear.
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.frame = CGRectMake(10, 40, 300, 300);
self.layer.cornerRadius = 150;
self.backgroundColor = [UIColor greenColor];
self.layer.borderColor = [UIColor blueColor].CGColor;
self.layer.borderWidth = 2;
// self.layer.masksToBounds = YES; //if write this line,the round corner appear
self.x_move = 0;
self.y_move = 300;
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGMutablePathRef path = CGPathCreateMutable();
CGContextSetLineWidth(context, 1);
CGContextSetFillColorWithColor(context, [UIColor grayColor].CGColor);
CGPathMoveToPoint(path, NULL, 0, 0);
for(float i=0; i<=300; i++){
float x=i;
float y = 5 * sin( 0.05 * x+ self.x_move) + self.y_move;
CGPathAddLineToPoint(path, nil, x, y);
}
CGPathAddLineToPoint(path, nil, 300, 0);
CGPathAddLineToPoint(path, nil, 0, 0);
CGContextAddPath(context, path);
CGContextFillPath(context);
CGContextDrawPath(context, kCGPathStroke);
CGPathRelease(path);
}
- (void)startAnimation {
if (self.waveTimer == nil) {
self.waveTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(refresh) userInfo:nil repeats:YES];
}
}
- (void)refresh {
self.x_move += 0.3;
self.y_move -= 0.2;
if(self.y_move - 100 < 0.00001){
[self.waveTimer invalidate];
}else{
[self setNeedsDisplay];
}
}
ViewController:
self.wave = [[waveAnimation alloc] init];
[self.wave startAnimation];
[self.view addSubview:self.wave];
This is a normal UIView. Its "masksToBunds" is NO, but its round corner shows normal. Compared with the examples above, why one should add, one does not need.
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(20, 60, 100, 100)];
view.backgroundColor = [UIColor greenColor];
view.layer.cornerRadius = 50;
view.layer.borderWidth = 2;
view.layer.borderColor = [UIColor blackColor].CGColor;
[self.view addSubview:view];
The reason for this is from your override of drawRect:(CGRect)frame.
You are attempting to set the corner radius of the layer that is not the element you assigned the fill color to. The reason setting masksToBounds achieves the desired rounded corner is because here you are telling the view to mask all of it's layers to the bounds from your frame.
In your second example with the UIView the corner radius appears as expected because you have not adjusted it's layers.
I suggest either adopting setting masksToBounds or redraw the view's bounds a different way if you need masksToBounds = NO. Since you have the "squiggle" sin curve and you want rounded corners, perhaps just create a generic rounded rect (one with the desired corner radius) then merge that with the path you have already created with the sin wave.
Merge multiple CGPaths together to make one path
That link may help you merge your rounded view with your custom view to achieve the desired end result.
Otherwise.. probably best bet to just set this to yes.

Vertical alignment between CALayer and CATextLayer

I'm currently working with CALayer and CATextLayer and I got a stuck when align them in vertical.
I'm create a CALayer for display an image inside it, then add a CATextLayer below CALayer after calculate the text size of CATexLayer, you can see my code for more details:
+ (instancetype)itemWithImage:(UIImage *)image andTitle:(NSString *)title {
CGSize size = CGSizeMake(MIN(image.size.width, [XFATLayoutAttributes itemWidth]), MIN(image.size.height, [XFATLayoutAttributes itemWidth]));
CALayer *layer = [CALayer layer];
layer.contents = (__bridge id)image.CGImage;
layer.bounds = CGRectMake(0, 0, MIN(size.width, [XFATLayoutAttributes itemImageWidth]), MIN(size.height, [XFATLayoutAttributes itemImageWidth]));
CATextLayer *label = [[CATextLayer alloc] init];
[label setFont:#"Helvetica"];
[label setFontSize:14];
label.alignmentMode = kCAAlignmentCenter;
label.backgroundColor = [UIColor redColor].CGColor;
label.string = title;
label.foregroundColor = [UIColor colorWithRed:138/255.0 green:138/255.0 blue:143/255.0 alpha:1.0].CGColor;
label.wrapped = YES;
label.contentsScale = [UIScreen mainScreen].scale;
CGSize stringSize = [title sizeWithAttributes:#{NSFontAttributeName: [UIFont fontWithName:#"Helvetica" size:14.0]}];
label.frame = CGRectMake(-5, layer.bounds.size.height + 5, stringSize.width, stringSize.height + 1);
[layer addSublayer:label];
return [[self alloc] initWithLayer:layer];
}
But the problem is the text size are not the same and my CATextLayer was misalignment a little bit like this image:
How can I align them in X axis? Please help.
Thanks in advance.
You can calculate right X offset this way:
label.frame = CGRectMake((size.width - stringSize.width) / 2, layer.bounds.size.height + 5,
stringSize.width, stringSize.height + 1);
Or you can simply make your label width equal to image width since you align text to center:
label.frame = CGRectMake(0, layer.bounds.size.height + 5,
size.width, stringSize.height + 1);
BTW I could not make work your method with return [[self alloc] initWithLayer:layer], so I had to return constructed subclass instance itself:
AlignLayer *layer = [AlignLayer layer]; // my subclass
// ...
return layer;
And Apple warns against using initWithLayer: in such situations:
This initializer is used to create shadow copies of layers, for example, for the presentationLayer method. Using this method in any other situation will produce undefined behavior. For example, do not use this method to initialize a new layer with an existing layer’s content.

UILabel Pixelated on Zoom in iOS App

I have a UILabel which added in UIView and this view add as subview of UIScrollViewand zooming is enabled. Working every thing fine but when I zoom in then UILabel and other properties too and this look quite odd.I also added following code for flexible size.
userResizableView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
userResizableView.autoresizesSubviews = YES;
Above View is `UIView Type.
And below is code of Label
UILabel * lbl_FormFieldName = [[UILabel alloc]initWithFrame:CGRectMake(1, 1, rect.size.width, 15)];
lbl_FormFieldName.attributedText = attrText;
// lbl_FormFieldName.text = text;
lbl_FormFieldName.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
lbl_FormFieldName.textColor = [UIColor blackColor];
lbl_FormFieldName.backgroundColor = [UIColor clearColor];
lbl_FormFieldName.font = customFont;
lbl_FormFieldName.numberOfLines = 0;
lbl_FormFieldName.baselineAdjustment = UIBaselineAdjustmentAlignBaselines; // or UIBaselineAdjustmentAlignCenters, or UIBaselineAdjustmentNone
lbl_FormFieldName.clipsToBounds = YES;
lbl_FormFieldName.textAlignment = NSTextAlignmentCenter;
Kindly give me any suggestion how to make good. Looking for suggestion.
Thanks
Maybe the frame label is using floating numbers. Try this to force integers value for your frame:
[label setFrame:CGRectIntegral(label.frame)];
As per my requirement I have added pinch gesture on uilabel like this :
1. Add this line before implementation.
CG_INLINE CGRect CGRectScale(CGRect rect, CGFloat wScale, CGFloat hScale)
{
return CGRectMake(rect.origin.x * wScale, rect.origin.y * hScale, rect.size.width * wScale, rect.size.height * hScale);
}
2. Add gesture on label
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(viewDidPinch:)];
pinch.delegate =self;
[self addGestureRecognizer:pinch];
3. Add method in your file. Add scrollview bounds instead of self.bounds as I have different scenario in my case.
- (void)viewDidPinch:(UIPinchGestureRecognizer*)sender
{
CGFloat scale = sender.scale;
CGRect scaleRect = CGRectScale(self.bounds, scale, scale);
if (scaleRect.size.width >= 5 && scaleRect.size.height >= 5) {
[self._label setAttributedText:[self getScaledStringFrom:self._label.attributedText withScale:scale]];
[self._label setFrame:self.bounds];
}
sender.scale=1.0;
}
4. Rewrite text with new scale
- (NSMutableAttributedString*) getScaledStringFrom:(NSMutableAttributedString*)string withScale:(CGFloat)scale
{
[string beginEditing];
[string enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0, string.length) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) {
if (value) {
UIFont *oldFont = (UIFont *)value;
UIFont *newFont = [oldFont fontWithSize:oldFont.pointSize * scale];
[string removeAttribute:NSFontAttributeName range:range];
[string addAttribute:NSFontAttributeName value:newFont range:range];
}
}];
[string endEditing];
return string;
}

IOS - Have UITableViewCells scroll over UIView (like the shazam app)

I have a UIView above my UITableView. When the user scrolls down I want the UIView to stay in place at the top of the screen and have the cells scroll over it. The first page of the Shazam app does what I want.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
if (self.tableView.contentOffset.y > 0) {
CGRect newframe = self.publicTopView.frame;
newframe.origin.y = -self.tableView.contentOffset.y;
self.publicTopView.frame = newframe;
}
}
This is what I've tried so far, but it doesn't do anything. Thanks
I would set the tableView.backgroundView to your view, and then set your cells to be clear (or whatever transparency you like). This will allow the cells to move over the view.
You need to have a scrollView with a transparent background. Then add a subview to it that is not transparent and offset down a bit. Here's an overkill example. The TextureView is just so you can see that the background isn't moving.
#import "ViewController.h"
#interface TextureView : UIView
#end
#implementation TextureView
-(void)drawRect:(CGRect)rect{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextBeginPath(context);
CGContextMoveToPoint(context, 0, 0);
CGContextAddLineToPoint(context, rect.size.width, rect.size.height);
CGContextMoveToPoint(context, 0, rect.size.height);
CGContextAddLineToPoint(context, rect.size.width, 0);
CGContextSetStrokeColorWithColor(context, [[UIColor whiteColor]CGColor]);
CGContextSetLineWidth(context, 8);
CGContextStrokePath(context);
}
#end
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
CGRect scrollViewFrame = self.view.frame;
CGFloat sectionHeight = 300;
int numberSections = 3;
CGFloat clearSpaceAtTop = 300;
CGRect sectionsViewFrame = CGRectMake(0, clearSpaceAtTop, scrollViewFrame.size.width, sectionHeight * numberSections);
CGSize contentSize = CGSizeMake(scrollViewFrame.size.width, CGRectGetMaxY(sectionsViewFrame));
TextureView *backGroundView = [[TextureView alloc]initWithFrame:scrollViewFrame];
backGroundView.backgroundColor = [UIColor blueColor];
[self.view addSubview:backGroundView];
UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:scrollViewFrame];
scrollView.contentSize = contentSize;
scrollView.backgroundColor = [UIColor clearColor];
[self.view addSubview:scrollView];
UIView *sectionViewsParent = [[UIView alloc]initWithFrame:sectionsViewFrame];
sectionViewsParent.backgroundColor = [UIColor lightGrayColor];
[scrollView addSubview:sectionViewsParent];
NSArray *colors = #[[UIColor redColor],[UIColor greenColor],[UIColor purpleColor]];
CGFloat spacer = 4;
CGRect colorViewFrame = CGRectMake(0, 0, sectionsViewFrame.size.width, sectionHeight - spacer);
for (UIColor *color in colors){
UIView *sectionView = [[UIView alloc]initWithFrame:colorViewFrame];
sectionView.backgroundColor = color;
[sectionViewsParent addSubview:sectionView];
colorViewFrame.origin.y += sectionHeight;
}
}
#end
If the UIView instance is called iconView, the UITableView instance is called tableView,
If your view controller is UIViewController.
[self.view addSubview:iconView];
[self.view addSubview:tableView];
//and you need set tableView.background to transparent.
If your view controller is UITableViewController, read this question:
UITableViewController Background Image
basically all you have to do is to use UIScrollView's contentInset property
let topInset = topViewHeight.constant //based on your needs
sampleTableView.contentInset = UIEdgeInsets(top: topInset, left: 0, bottom: 0, right: 0)
see my github sample here

How does one find a UIView... when there's no self.view?

So I've been fighting this one for a while as novice with iOS - I'm sure it's either a basic concept I'm missing, or a property I haven't run across yet that I need to reference.
Scenario: View controller creates a UIScrollView. UIView is created as a container for several UILabels (describing an event, venue and time). Method is called repeatedly to create these UILabels within the block. Creating these labels one by one works fine - simply adding each to the view - but when I move the code to a method and reuse it, abstracting such things as text size, indent, etc, I can't refer to the same parent view (because it's not a View Controller?), or search using viewWithTag (returns nothing) to find the parent.
Is this a simple fix, or is my basic structure flawed? Many thanks in advance for your time!
Header:
//
// ScheduleColumn.h
//
#import <Foundation/Foundation.h>
#interface ScheduleColumn : UIView {
}
- (void)makeTextBlock:(int)parentViewID label:(NSString*)label textSize:(int)textSize indent:(int)indent y:(int)y width:(int)width height:(int)height;
#end
Implementation:
//
// ScheduleColumn.m
//
#import "ScheduleColumn.h"
#implementation ScheduleColumn
// makeTextBlock: type, text, textSize, indent, build_y, width, height
// type: 0 = Title, 1 = Subtitle, 2 = Times
// text: Line content
// textSize: self-explanatory
// indent: indent from left side of parent
// build_y: # of units down from top of parent view to build
// width & height: self-explanatory
- (void)makeTextBlock:(int)parentViewID label:(NSString*)label textSize:(int)textSize indent:(int)indent y:(int)y width:(int)width height:(int)height {
double unixTime;
unixTime = [[NSDate date] timeIntervalSince1970];
NSLog(#"makeTextBlock called");
NSLog(#"parentViewID: %u", parentViewID);
NSLog(#"label: %#", label);
NSLog(#"textSize: %u", textSize);
NSLog(#"indent: %u", indent);
NSLog(#"y: %u", y);
NSLog(#"width: %u", width);
NSLog(#"height: %u", height);
NSLog(#"time: %u", unixTime);
UILabel *textView = [[UILabel alloc] initWithFrame:CGRectMake(indent, y, width, height)];
textView.backgroundColor = [UIColor clearColor];
textView.textColor = [UIColor whiteColor];
textView.lineBreakMode = UILineBreakModeWordWrap;
textView.numberOfLines = 0;
textView.tag = unixTime;
textView.font = [UIFont fontWithName:#"PetitaMedium" size: textSize];
textView.text = label;
CGSize constraintTextSize;
constraintTextSize.width = width;
constraintTextSize.height = MAXFLOAT;
CGSize theTextSize = [label sizeWithFont:[UIFont fontWithName:#"PetitaMedium" size: textSize] constrainedToSize:constraintTextSize lineBreakMode:UILineBreakModeWordWrap];
CGRect newTextFrame = textView.frame;
newTextFrame.size.height = theTextSize.height;
textView.frame = newTextFrame;
UIView *parentView = (UIView *)[self.view viewWithTag:parentViewID];
[parentView addSubview:textView];
[textView release];
NSLog(#"--- break ---");
}
.. and finally, the calls from the View Controller:
int build_y;
int subtitle_indent;
build_y = 30;
subtitle_indent = 20;
UIView *blockView = [[UIView alloc] initWithFrame: CGRectMake ( 0, build_y, 185, 50)];
blockView.tag = 100;
[FireworksContent addSubview:blockView];
// Add top line
UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, blockView.bounds.size.width, 0.5)];
lineView.backgroundColor = [UIColor whiteColor];
[blockView addSubview:lineView];
// Add Block Text
ScheduleColumn *blockText = [ScheduleColumn alloc];
[blockText makeTextBlock:blockView.tag label:#"Venue" textSize:18 indent:subtitle_indent y:build_y width:blockView.bounds.size.width height:20];
[blockText makeTextBlock:blockView.tag label:#"ShowTitle" textSize:12 indent:subtitle_indent y:build_y width:blockView.bounds.size.width height:20];
[blockText makeTextBlock:blockView.tag label:#"Showtime" textSize:36 indent:subtitle_indent y:build_y width:blockView.bounds.size.width height:20];
[lineView release];
[blockText release];
[blockView release];
... the viewWithTag line fails because "self" doesn't have a view... changing the class to a UIViewController lets it run, but still no joy.
A class method that returns a new view rather than an instance method that returns void would make more sense.
+(UIView *)makeTextBlock:(int)parentViewID label:(NSString*)label textSize:(int)textSize indent:(int)indent y:(int)y width:(int)width height:(int)height
Create the view as you want, and return that view at the end of the method.
Then you can create several of these views and hold a reference to them in your view controller if you want.
UIView *blockText1 = [ScheduleColumn makeTextBlock .....];
[self.view addSubview: blockText1];

Resources