Make only part of a sentence a link (add selector) - ios

so I am trying to implement the following. I have a view, which has a sentence. Only part of the sentence links to another view. This is what it looks like:
I am a cat. Learn More
The Learn More would be a link (blue in color), which when clicked would open another view.
Currently I am using a UILabel to write "I am a cat". I realize that the best way to add selectors is to use a button, so "Learn More" should be a button?
Is there any way to write this sentence out without using two different UIComponents?
If not, then how do I make the UILabel and the UIButton completely horizontally aligned with each other?
The following is my code for the label in -layoutSubviews:
CGSize labelSize = [_label.text sizeWithFont:_label.font constrainedToSize:bounds.size lineBreakMode:_label.lineBreakMode];
_label.frame = CGRectMake(0, 0, bounds.size.width - kMarginForText, labelSize.height);
_label.center = CGPointMake(horizontalCenter, CGRectGetMaxY(_previousLabel.frame) + kDistanceBetweenPreviousAndCurrentLabel);
And the code for the label itself.
_label = [[UILabel alloc] initWithFrame:CGRectZero];
_label.text = "I am a cat";
_label.font = [UIFont systemFontOfSize:14];
_label.textAlignment = NSTextAlignmentCenter;
_label.numberOfLines = 0;
_label.lineBreakMode = UILineBreakModeWordWrap;
[self addSubview:_label];
Any help would be appreciated!

To answer your question about a single UIComponent, you could use a UILabel in conjunction with a UITapGestureRecognizer to create the intended effect. Granted this would make the whole label tappable... but having a bigger tap target area is almost never a bad thing.
In particular you would use an NSAttributedString to set the label text (NSAttributedString change color at end of string):
UILabel *label = [[UILabel alloc] init];
//Use initwithframe or setup your constraints after initialization here
label.attributedText = (your nsattributed string here)
Then to initialize the tap recognizer onto the UILabel you would do something like this:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(userDidTapLearnMore)];
label.userInteractionEnabled = YES;
[label addGestureRecognizer:tap];

What you want to do is to align them by their baselines, which you can easily do in Interface Builder by selecting them and choosing Editor > Align > Baselines, as shown in this illustration:

Related

What is the best way to add UITapGestureRecognizer to a specific part of UILabel?

This question might have asked few times, but I'm still struggling to find best solution. addAttributes with NSMutableAttributedString won't work as I only can give a link to a part of the string.
I have a label with string "Already sign up? Login here". I can get NSRange of text "Login" but how can I give UITapGesture to it? I don't want to use 3rd party library here. Please suggest me some ideas. Thanks
You cannot add a gesture recognizer to a "part of a UILabel". For your case, I would just use two different UILabels: one that is not-tappable that says "Already signed up?", and one that is tappable that says "Sign in here". Honestly, I'd put the tappable part into a UIButton to make it clear. One more option would be to put an empty UIView as a subview of the UILabel, making it the size of the text you want to tap. Then add a gesture recognizer to THAT subview.
(In my opinion, one of the biggest traps developers get into when working with iOS is trying to force it to act differently than designed; like mimicking a web link or something. It always works best, and with a minimum of code, when written to take advantage of its design patterns)
All of the tap location nonsense can be ignored, because that is the point of a recognizer. The recognizer handles all of that for you, and will call your target with the action you set when the UIView is tapped.
So it would basically be:
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:someObject action:#selector(someMethod:)];
[loginLabel addGestureRecognizer:tapRecognizer];
And that's it. The rest will be handled for you by the system. Your target object will be called when the label is tapped. At least, it seems simple from the problem as described in the original post. If there are other complications, please include those points in your question.
Gesture recognizers can't be added to specific parts of a UI component.
However, inside tap handler action, you might want to check
CGPoint tapLocation = [tapRecognizer locationInView:tapRecognizer.view];
You can check if the point lies in your targetRect
if(CGRectContainsPoint(myTargetRect, tapLocation))
{
// Do your action here
}
Hope it helps.
Update:
Here's the Objective-C version for getRect() from #Code 's answer as you needed.
-(CGRect)getRectForString:(NSAttributedString*)str withRange:(NSRange)textRange usingMaxWidth:(CGFloat)maxWidth
{
// Create a layoutManager
NSLayoutManager* layoutManager = [[NSLayoutManager alloc] init];
// Create a textContainer with maxWidth size and add it to layoutManager
NSTextContainer* textContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(maxWidth, CGFLOAT_MAX)];
[layoutManager addTextContainer:textContainer];
textContainer.lineFragmentPadding = 0;
// Create a textStorage with 'str' variable and add the layoutManager to this textStorage
NSTextStorage* textStorage = [[NSTextStorage alloc] initWithAttributedString:str];
[textStorage addLayoutManager:layoutManager];
// Query the actualGlyphRange from layoutManager for specified textRange
NSRange actualGlyphRange;
[layoutManager characterRangeForGlyphRange:textRange actualGlyphRange:&actualGlyphRange];
// Find out the boundingRect for actualGlyphRange
return [layoutManager boundingRectForGlyphRange:actualGlyphRange inTextContainer:textContainer];
}
You can't add tap gesture to a specific part of UILabel or if you tried to do so, you will stuck in finding frames and part of label that might help you at this point but it will be more problematic if it is inside some other view like UITableViewCell etc. It may require some calculation for point conversion with respect to parent/child view.
To keep it simple, my suggestion would be to create a UIView with a UILabel and UIButton embedded in it and button is set next to UILabel.
An example:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Create label
UILabel *lbl = [[UILabel alloc] init];
[lbl setText:#"Already Sign up ? "];
[lbl sizeToFit];
// Create button
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
[btn setTitle:#"Login Here" forState:UIControlStateNormal];
[btn addTarget:self action:#selector(didTapLink:) forControlEvents:UIControlEventTouchUpInside];
[btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[btn sizeToFit];
[btn setFrame:CGRectMake(lbl.frame.size.width, lbl.frame.origin.y, btn.frame.size.width, lbl.frame.size.height)];
// Create container that embeds the label and button
UIView *customLabel = [[UIView alloc] initWithFrame:CGRectMake(0, 50, lbl.frame.size.width + btn.frame.size.width, lbl.frame.size.height)];
[customLabel addSubview:lbl];
[customLabel addSubview:btn];
// Add this custom label to UI
[self.view addSubview:customLabel];
}
-(void)didTapLink:(id)sender
{
NSLog(#"Button tapped");
}
Screenshot:
Hope that helps!

how to programmatically align a label to an x, y coordinate

below are some other properties of the label. obviously nstextalignmentleft is not what i'm going for. having trouble understanding where to enter coordinates.
self.lblTimer = [[UILabel alloc] init];
self.lblTimer.translatesAutoresizingMaskIntoConstraints = NO;
self.lblTimer.textAlignment = NSTextAlignmentLeft;
self.lblTimer.font = [UIFont systemFontOfSize:10];
self.lblTimer.textColor = [UIColor redColor];`self.lblTimer = [[UILabel alloc] init];
I think you're misunderstanding what textAlignment does. This simply controls the alignment within the label, not on the screen. If you want to position the label on screen you must change its frame property:
self.lblTimer.frame = CGRectMake(x,y,width,height);
As you've set self.lblTimer.translatesAutoresizingMaskIntoConstraints to NO I am guessing you want to use Auto Layout and if so, I highly recommend taking a look at Masonry.
An alternative is to set the frame property on the label with requires a CGRect where you give it the x and y coordinates as well as the width and height.

Text Alignment issue when I set the custom font

When I set the custom font for the segmented control then it changes the vertical text alignment. I am using below code to set the font .
// I dont think these lines are creating any issue but just wanted to paste all the code
self.segmentType.layer.borderColor = navigationTintColor.CGColor;
self.segmentType.layer.cornerRadius = 0.0;
self.segmentType.layer.borderWidth = 1.5;
// These are the lines that are changing the text alignment
UIFont *font = [UIFont fontWithName:ftHelveticaNeueLTPro_Th size:13.5];
NSDictionary *attributes = [NSDictionary dictionaryWithObject:font
forKey:UITextAttributeFont];
[self.segmentType setTitleTextAttributes:attributes
forState:UIControlStateNormal];
Here is the screenshot of whats is happening . If you observer, the text is not vertically centre aligned .
Please help me . Thank you in advance !!
The below code suggested by #Emmanuel works perfectly fine. You can change the vertical offset to align the text vertically at the center .
[self.segmentType setContentPositionAdjustment:UIOffsetMake(0, 2) forSegmentType:UISegmentedControlSegmentAny barMetrics:UIBarMetricsDefault];
Can you please try it using custom UILabel on custom view on it. Change & modify frame value of either titleLabel or customSegmentView as per convenience on actual view. And add this whole view as subview on your segmented control.
UIView *customSegmentView = [[UIView alloc] init];
UILabel *segmentTitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 7.0f,180.0f,22.6f)];
segmentTitleLabel.text = #"your-text";
segmentTitleLabel.backgroundColor = [UIColor clearColor];
segmentTitleLabel.textAlignment = UITextAlignmentCenter;
segmentTitleLabel.font = [UIFont fontWithName:#"ftHelveticaNeueLTPro_Th" size:13.5f];
customSegmentView.frame = CGRectMake(60, 20, 180, 35);
[customSegmentView addSubview:segmentTitleLabel];
[self.segmentType setTitleView:customSegmentView];
Hope that will work for your issue. Please check and let me know if we have to go with another solution.
In InterfaceBuilder on XCode 6 there is a Content Offset control for the segments, which affects the baseline of the text. I had this problem because my Content Offset was 2 in the Y dimension instead of 0.

Cannot make programmatically created UITextField editable (iOS)

I created a UITextField programatically, (I do not use storyboard) and added it as a subview to ViewController with this code:
#interface ViewController ()
#property (nonatomic, strong) UITextField *searchLocationBar;
#end
...
#synthesize searchLocationBar;
...
self.searchLocationBar = [[UITextField alloc] init];
self.searchLocationBar.frame = CGRectMake(0.0f, 0.0f, 320.0f, 40.0f);
self.searchLocationBar.delegate = self;
self.searchLocationBar.borderStyle = UITextBorderStyleRoundedRect;
self.searchLocationBar.placeholder = #"a temporary placeholder";
self.searchLocationBar.userInteractionEnabled = YES;
self.searchLocationBar.clearButtonMode = UITextFieldViewModeAlways;
[self.view addSubview:self.searchLocationBar];
However, I cannot enter any text - nothing happens, when I tap on a textfield. It's not overlapped by any other view.
I've checked UITextfield not editable-iphone but no effect
I'm newbie and totally sure I simply miss something - please advice.
Thanks!
EDIT:
One more thing: I have a Google Maps GMSMapView assigned to self.view as
self.view = mapView_; as written in Google API documentation.
After some tests I found that with this declaration all controls work perfectly, but not textfields. I would prefer not to move a map view to any subview as I will need to rewrite lots of things.
Can someone please add any suggestions?
you forget add:
[self.view bringSubviewToFront:self.searchLocationBar];
In Xcode 5 your code should work.Better you check your Xcode version.May be the problem with your code with Xcode versions.You can try by following way.
UITextField *lastName = [[[UITextField alloc] initWithFrame:CGRectMake(10, 100, 300, 30)];
[self.view addSubview:lastName];
lastName.placeholder = #"Enter your last name here"; //for place holder
lastName.textAlignment = UITextAlignmentLeft; //for text Alignment
lastName.font = [UIFont fontWithName:#"MarkerFelt-Thin" size:14.0]; // text font
lastName.adjustsFontSizeToFitWidth = YES; //adjust the font size to fit width.
lastName.textColor = [UIColor greenColor]; //text color
lastName.keyboardType = UIKeyboardTypeAlphabet; //keyboard type of ur choice
lastName.returnKeyType = UIReturnKeyDone; //returnKey type for keyboard
lastName.clearButtonMode = UITextFieldViewModeWhileEditing;//for clear button on right side
lastName.delegate = self; //use this when ur using Delegate methods of UITextField
There are lot other attributes available but these are few which we use it frequently.if u wanna know about more attributes and how to use them refer to the following link.
You can also make property for UITextField.Either way should work fine in Xcode.
http://developer.apple.com/library/ios/#documentation/uikit/reference/UITextField_Class/Reference/UITextField.html

How can I embed UIViews (or, more specifically, UITextAreas) programmatically in-line with Text?

For reasons of reusability, I'm interested in finding a way to programmatically add text and custom UITextFields to a view in an efficient manner, similar to how you can combine strings using NSString's stringWithFormat: and then assign the result to a UILabel's text attribute. Ideally, with 2-3 statements I could write text and include my UITextField Objects in a string, and get an automatically text-wrapped, nicely formatted UIView that I can embed directly into my view. Basically, it would function like a UILabel with the ability to add UIView objects. For an example of the output this image would be a combination of both text and underlined UITextFields:
If this exists, it would allow me to reuse a single UITableViewCell subclass rather than having 5-6 xibs and 3-4 subclasses. I've searched about 2 hours with no real luck for a pre-existing solution, so has anyone ever encountered this problem before and used or released a library to handle this, or is there a simple solution I'm overlooking?
Thank you!
you can use CSLinearLayoutView (https://github.com/scalessec/CSLinearLayoutView)
and create a class
#implementation LabledView
+ (UIView*)create :(CGRect) frame view:(UIView*) view labelTitle:(NSString*)labelTitle viewLinearLayoutMakePadding :(CSLinearLayoutItemPadding)viewLinearLayoutMakePadding labelLinearLayoutMakePadding :(CSLinearLayoutItemPadding)labelLinearLayoutMakePadding font:(UIFont*)font textColor:(UIColor*)textColor
{
CSLinearLayoutView *container = [[CSLinearLayoutView alloc] initWithFrame:frame];
container.orientation = CSLinearLayoutViewOrientationHorizontal;
UILabel *label = [[UILabel alloc] init];
label.textColor = textColor;
[label setText:labelTitle];
[label setFont:font];
[label sizeToFit];
CSLinearLayoutItem *itemLabel = [CSLinearLayoutItem layoutItemForView:label];
itemLabel.padding = labelLinearLayoutMakePadding;
CSLinearLayoutItem *itemView = [CSLinearLayoutItem layoutItemForView:view];
itemView.padding = viewLinearLayoutMakePadding;
[container addItem:itemLabel];
[container addItem:itemView];
return container;
}
example :
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 260, 40)];
UIView *customView = [LabledView create:CGRectMake(0, 0, 280, 40) view:textField
labelTitle:#"your label" viewLinearLayoutMakePadding:CSLinearLayoutMakePadding(0, 10, 0, 0)
labelLinearLayoutMakePadding:CSLinearLayoutMakePadding(10, 0, 0, 0)
font:[UIFont fontWithName:#"Helvetica" size:12] textColor:[UIColor blackColor]];
You can underline specific ranges of a string with NSAtttibutedString. You can setAttributedString to UILabel in ios6... So that's the way I'd do it, then it can indeed be in a single label with the desired parts underlined (or in a different font/colour/etc) only. Be careful when you look into attributed string, it's attributes dictionary uses different keys for working with UIKit (these are the ones you need here) to what it uses with CoreText

Resources