Try as I might, I can't solve a UISegmentedControl bug for an iOS7 iPhone app.
When I create the segmented control, I use this code:
NSArray *segmentedControlItemArray = [NSArray arrayWithObjects: #"Nominal:\n27 inch", #"Actual:\n700c x 23mm", #"Actual:\n700c x 20mm", nil];
_wheelDiameterSegmentedControl = [[UISegmentedControl alloc] initWithItems:segmentedControlItemArray];
_wheelDiameterSegmentedControl.frame = CGRectMake(0, 102, 290, 50);
_wheelDiameterSegmentedControl.selectedSegmentIndex = 0;
_wheelDiameterSegmentedControl.tintColor = [UIColor colorWithRed:0.35 green:0.4 blue:0.9 alpha:1.0];
for (id segment in [_wheelDiameterSegmentedControl subviews]) {
for (id label in [segment subviews]) {
if ([label isKindOfClass:[UILabel class]]) {
UILabel *titleLabel = (UILabel *) label;
titleLabel.numberOfLines = 0;
}
}
}
[_wheelDiameterSegmentedControl addTarget:self
action:#selector(pickOne:)
forControlEvents:UIControlEventValueChanged];
[_wheelDiameterMenuContainer addSubview:_wheelDiameterSegmentedControl];
Sadly, I can't post images, or I would show you a picture of exactly the control I want: each of the segments in the UISegmented Control has two lines of text, with a line break exactly where I asked for it.
On rotation, though, I'd like to keep the segmented control full-width, and the line breaks look silly in segments that wide. So, in willAnimateRotationToInterfaceOrientation, I've included the following code, with no line breaks in the strings:
[_wheelDiameterSegmentedControl setFrame:CGRectMake(0, 102, 450, 50)];
[_wheelDiameterSegmentedControl setTitle:#"Nominal: 27 inch" forSegmentAtIndex:0];
[_wheelDiameterSegmentedControl setTitle:#"Actual: 700c x 23mm" forSegmentAtIndex:1];
[_wheelDiameterSegmentedControl setTitle:#"Actual: 700c x 20mm" forSegmentAtIndex:2];
And once again, if I could insert an image, I would show you an image of exactly what I want: a wide UISegmented Control with no line breaks in the labels (1 line of text per label).
Here's where I run in to trouble. My choices, when I rotate back to portrait, seem to be:
1 line of label text, truncated, with the format
"Actual: 7..."
when I just reset the size of the UISegmentedControl using
[_wheelDiameterSegmentedControl setFrame:CGRectMake(0, 102, 290, 50)];
2 lines of label text, truncated, with the format
"Actual:
700c x ..."
when I reset the size and also reset the string values and rerun the loop of code that sets the label's numberOfLines to 2, using
NSArray *segmentedControlItemArray = [NSArray arrayWithObjects: #"Nominal:\n27 inch", #"Actual:\n700c x 23mm", #"Actual:\n700c x 20mm", nil];
[_wheelDiameterSegmentedControl setTitle:[segmentedControlItemArray objectAtIndex:0] forSegmentAtIndex:0];
[_wheelDiameterSegmentedControl setTitle:[segmentedControlItemArray objectAtIndex:1] forSegmentAtIndex:1];
[_wheelDiameterSegmentedControl setTitle:[segmentedControlItemArray objectAtIndex:2] forSegmentAtIndex:2];
for (id segment in [_wheelDiameterSegmentedControl subviews]) {
for (id label in [segment subviews]) {
if ([label isKindOfClass:[UILabel class]]) {
UILabel *titleLabel = (UILabel *) label;
titleLabel.numberOfLines = 2;
}
}
}
[_wheelDiameterSegmentedControl setFrame:CGRectMake(0, 102, 290, 50)];
3 lines of label text, with the format
"Actual:
700c x
20mm"
which is what I get when I replace the forced numberOfLines = 2 above with the numberOfLines = 0 that worked when I set up the UISegmentedControl in the first place.
What I'd like is what I get when I create the control, which is
"Actual:
700c x 20mm"
But no matter what I've tried (putting the string and numberOfLines code into willRotateToInterfaceOrientation or didRotateFromInterfaceOrientation; re-setting the frame of the UISegmentedControl before changing the text; re-setting the frame after changing the text...), I can't get my nice, neat, two-line label back. What am I missing here?
Aha! Something about how the OS is handling the size of the label when it rotates is different from how it handles the label when it's created. So I forced the size of the frame of the label, using
for (id segment in [_wheelDiameterSegmentedControl subviews]) {
for (id label in [segment subviews]) {
if ([label isKindOfClass:[UILabel class]]) {
UILabel *titleLabel = (UILabel *) label;
//inserting line here, to make the frame behave nicely:
//
titleLabel.frame = CGRectMake(0, 0, 97, 50);
//
//continuing as before
titleLabel.numberOfLines = 0;
}
}
}
and now it displays exactly as I want/expect. Huzzah!
If you're just trying to get two (or more) lines of text in your UISegmentedControl. Using Herzian's amazing technology! Here's just another code example, that may help people...
self.yourSlider .. set the height manually (can't easily do it in XIB)
// now use amazing Herzian technology...
for (id segment in [self.yourSlider subviews])
for (id label in [segment subviews])
{
if ([label isKindOfClass:[UILabel class]])
{
UILabel *titleLabel = (UILabel *) label;
titleLabel .. set the width to say 80, per your layout;
(the width us typically too low)
titleLabel.numberOfLines = 0;
}
}
thank you so much, again.
working code in ios 7 :
I have a segment controller with four segments and I need it in 2 lines for text. So I have added UILabel as a subview in segment of UISegmentedControl and it is working good. I have tried all other ways but in ios 7 and ios 8 it is working good right now.
for(int k =0;k<4;k++)
{
NSString *text = #"title name";
UILabel *label = [[UILabel alloc] init];
label.frame = CGRectMake(10,2, (self.segmentcontroll.frame.size.width/4), 34);
label.font = [UIFont fontWithName:#"HelveticaNeue" size:12.0];
label.textColor = [UIColor whiteColor];
label.text = text;
label.numberOfLines = 0;
label.textAlignment = NSTextAlignmentCenter;
[label sizeToFit];
[[[self.segmentcontroll subviews] objectAtIndex:k] addSubview:label];
}
And Herzian's solution as a category if anyone wants it. Remember to call it in VWA instead of VDL so it happens after autosizing / rotation
#import "UISegmentedControl+MultiLine.h"
#implementation UISegmentedControl (MultiLine)
-(void)setupMultiLine
{
self.frame = CGRectMake(self.frame.origin.x,
self.frame.origin.y,
self.frame.size.width,
self.frame.size.height*1.6);
for (id segment in self.subviews)
{
for (id label in [segment subviews])
{
if ([label isKindOfClass:[UILabel class]])
{
UILabel *titleLabel = (UILabel*) label;
titleLabel.frame = CGRectMake(0,
0,
titleLabel.frame.size.width,
titleLabel.frame.size.height*1.6);
titleLabel.numberOfLines = 0;
}
}
}
}
#end
Related
I am trying to set the placeholder text alignment in Objective-C or Swift for iOS 9 and above. I have tried the following:
1.
for (UIView *subview in self.subviews) {
for(id field in subview.subviews) {
if ([field isKindOfClass:[UITextField class]]) {
[(UITextField*)field setTextAlignment:NSTextAlignmentLeft];
}
}
}
2.
[[UITextField appearanceWhenContainedInInstancesOfClasses:#[[UISearchBar class]]] setTextAlignment:NSTextAlignmentLeft];
3.
UITextField *searchTextField = [self valueForKey:#"_searchField"];
UILabel *placeholderLabel = [searchTextField valueForKey:#"_placeholderLabel"];
[placeholderLabel setTextAlignment:NSTextAlignmentLeft];
self.searchBar?.searchTextPositionAdjustment = UIOffset(horizontal: -100, vertical: 0)
But none of these have worked. Is there something else that I am missing? The view debugger shows that the textfield is centered, but changing its frame also has not been working for me.
I got a UISegmentedControl called mySegmentedControl
#property (nonatomic) IBOutlet UISegmentedControl *mySegmentedControl;
with 3 segments, and I would change text font for each segment.. Is possible?
Yes you can ----- Try this
for(uint i=0;i<[mySegmentedControl subviews].count;i++)
{
for(UIView *view in [[[mySegmentedControl subviews] objectAtIndex:i] subviews])
{
if([view isKindOfClass:[UILabel class]])
{
if(i==0) // set First segment font
[(UILabel*)view setFont:[UIFont fontWithName:#"HelveticaNeue-Light" size:27]];
if(i==1) // set Second segment font
[(UILabel*)view setFont:[UIFont fontWithName:#"HelveticaNeue-Light" size:17]];
if(i==2) // set Third segment font
[(UILabel*)view setFont:[UIFont fontWithName:#"HelveticaNeue-Light" size:7]];
}
}
}
You can use any images instead of text. This will give you flexible customization for appearance.
NSArray *segemtImages = [NSArray arrayWithObjects:[UIImage imageNamed:#"1st.png"],[UIImage imageNamed:#"2nd.png"],[UIImage imageNamed:#"3rd.png"], nil];
UISegmentedControl *segmentControl = [[UISegmentedControl alloc] initWithItems:segemtImages];
I don't think that is possible. Your only options are either use a custom open source implementation, or set a custom image with the text for each segment.
I modify #Anand Natan 's code:
In storyboard set the first label "1111111111111" is to change it default width. Because change the label don't change segmentcontroll size.
for(uint i=0;i<[_menuBarTop subviews].count;i++){
for(uint j=0;j<[[[[_menuBarTop subviews] objectAtIndex:i] subviews]count];j++){
UIView* view = [[[_menuBarTop subviews] objectAtIndex:i] subviews][j];
if([view isKindOfClass:[UILabel class]]){
UILabel* label = (UILabel*)view;
if([label.text isEqualToString:#"1111111111111"]){
label.text = LANGLOC(#"videolist_category_choosen");
}else if([label.text isEqualToString:#"2"]){
label.text = LANGLOC(#"videolist_category_followed");
}
break;
}
}
}
NSDictionary *textAttributes = [NSDictionary dictionaryWithObjectsAndKeys:[UIFont boldSystemFontOfSize:12], NSFontAttributeName, nil];
[_sgmntStatusUI setTitleTextAttributes:textAttributes forState:UIControlStateNormal];
for ios7 later varsions
This is a little different from all the other "How do I center the text in a UILabel" questions here...
I have a UILabel with some text in it, I want to center the text vertically in the UILabel. What's the big deal, right? That's the default. The problem comes because my text is dynamic and I have autoshrink turn on. As the text grows larger, the font size shrinks. You get this behavior.
Notice that the font baseline has not moved, I want it to move so the numbers are centered vertically in the UILabel's frame.
Easy, right? I just remember the frame's original center in viewDidLoad
self.workoutTimeCenter = _workoutTimeLabel.center;
and then I call sizeToFit after I change the the text, right?
[_workoutTimeLabel sizeToFit];
_workoutTimeLabel.center = _workoutTimeCenter;
Well, sizeToFit did, I guess, exactly what it was supposed to do, resize the frame so the text fits without shrinking!
How can I vertically center the text in a UILabel while respecting baselines and autoshrink? (Note, an iOS5 and later solution is fine and I can even deal with an iOS6 and later solution.)
In my experience you can just set the -[UILabel baselineAdjustment] property to UIBaselineAdjustmentAlignCenters to achieve the effect you're describing.
From the docs:
baselineAdjustment
Controls how text baselines are adjusted when text
needs to shrink to fit in the label.
#property(nonatomic) UIBaselineAdjustment baselineAdjustment
Discussion
If the adjustsFontSizeToFitWidth property is set to YES,
this property controls the behavior of the text baselines in
situations where adjustment of the font size is required. The default
value of this property is UIBaselineAdjustmentAlignBaselines. This
property is effective only when the numberOfLines property is set to
1.
and
UIBaselineAdjustmentAlignCenters
Adjust text based relative to the center of its bounding box.
EDIT: adding a full view-controller that demonstrates this:
#interface TSViewController : UIViewController
#end
#implementation TSViewController
- (void) addLabelWithFrame: (CGRect) f baselineAdjustment: (UIBaselineAdjustment) bla
{
UILabel* label = [[UILabel alloc] initWithFrame: f];
label.baselineAdjustment = bla;
label.adjustsFontSizeToFitWidth = YES;
label.font = [UIFont fontWithName: #"Courier" size: 200];
label.text = #"00";
label.textAlignment = NSTextAlignmentCenter;
label.backgroundColor = [UIColor lightGrayColor];
label.userInteractionEnabled = YES;
[self.view addSubview: label];
UIView* centerline = [[UIView alloc] initWithFrame: CGRectMake(f.origin.x, f.origin.y+(f.size.height/2.0), f.size.width, 1)];
centerline.backgroundColor = [UIColor redColor];
[self.view addSubview: centerline];
UITapGestureRecognizer* tgr = [[UITapGestureRecognizer alloc] initWithTarget: self action: #selector(onTap:)];
[label addGestureRecognizer: tgr];
}
- (void) viewDidLoad
{
[super viewDidLoad];
[self addLabelWithFrame: CGRectMake(0, 0, 320, 200)
baselineAdjustment: UIBaselineAdjustmentAlignCenters];
[self addLabelWithFrame: CGRectMake(0, 220, 320, 200)
baselineAdjustment: UIBaselineAdjustmentAlignBaselines];
}
- (void) onTap: (UITapGestureRecognizer*) tgr
{
UILabel* label = (UILabel*)tgr.view;
NSString* t = [label.text stringByAppendingString: #":00"];
label.text = t;
}
#end
when working in IB, be sure to set align baselines to center
Note: line break CANNOT be word wrap for this to work, so it will NOT work multiline (good to set the line break to Truncate tail)
-(void)fitVerticallyToLabel:(UILabel *)lbl
{
CGFloat fontSize = lbl.frame.size.width / lbl.text.length;
[lbl setFont:[UIFont fontWithName:#"Helvetica-Bold" size:fontSize]];
CGRect rect = lbl.frame;
rect.origin.y += rect.size.height - fontSize;
rect.size.height = fontSize;
[lbl setFrame:rect];
}
How to Use: Call this method after setting the text to your label.
label.text = #"text";
[self fitVerticallyToLabel:label];
Note: I ahev taken UILabel from xib. You can take it programmatically too in that case you will have to set its text alignment NSTextAlignMentCenter
Try to implement this logic:
-(void)adjustLabel1Text1:(NSString *)text1
{
UILabel *lbl_first = [UIFont fontWithName:#"Helvetica" size:12];
text1 = [text1 stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
float hedingLblHeight = [self calculateHeightOfTextFromWidth:text1 : [UIFont fontWithName:#"Helvetica" size:12] :118 :UILineBreakModeWordWrap];
lbl_first.text=text1;
[lbl_first setFrame:CGRectMake(lbl_first.frame.origin.x, lbl_first.frame.origin.y, 118, hedingLblHeight)];
lbl_first.lineBreakMode = UILineBreakModeWordWrap;
lbl_first.numberOfLines = 0;
[lbl_first sizeToFit];
//////////Adjust the lable or any UIControl below this label accordingly.
float endResultHeight=[self calculateHeightOfTextFromWidth:text2 : [UIFont fontWithName:#"Helvetica" size:15] :299 :UILineBreakModeWordWrap];
if(hedingLblHeight>secondImgTitleHeight)
{
[lbl_endResult setFrame:CGRectMake(lbl_endResult.frame.origin.x, lbl_first.frame.origin.y+lbl_first.frame.size.height+5, 299, endResultHeight)];
}
else
{
[lbl_endResult setFrame:CGRectMake(lbl_endResult.frame.origin.x, lbl_first.frame.origin.y+lbl_first.frame.size.height+5, 299, endResultHeight)];
}
lbl_endResult.lineBreakMode=UILineBreakModeWordWrap;
lbl_endResult.numberOfLines = 0;
[lbl_endResult sizeToFit];
}
-(float) calculateHeightOfTextFromWidth:(NSString*)text : (UIFont*) withFont:(float)width :(UILineBreakMode)lineBreakMode
{
CGSize suggestedSize = [text sizeWithFont:withFont constrainedToSize:CGSizeMake(width, FLT_MAX) lineBreakMode:lineBreakMode];
return suggestedSize.height;
}
It has helped me a lot.Hope it works for you.
Try
yourLabel.textAlignment = UITextAlignmentCenter;
I have dynamic UIButtons with subview is UIlabel.
My requirement is to display one label text in one button first time, after based on user selection(long press on the button) need to update the particular button subview label text and remove rest of the button subview label text.
I tried in this way
for (int i=0; i < [arr count]; i++)
{
UILabel *myLbl = [[UILabel alloc] initWithFrame:CGRectMake(30, 70, 60, 21)];
if (myissue.tag ==1) {
myLbl.text = #"Default";
}else {
myLbl.text = #"";
}
myLbl.backgroundColor = [UIColor clearColor];
myLbl.textColor = [UIColor colorWithRed:51.0/255.0 green:51.0/255.0 blue:51.0/255.0 alpha:1.0];
[myLbl setFont:[UIFont fontWithName:#"Helvetica" size:12]];
myLbl.textAlignment = NSTextAlignmentCenter;
myLbl.tag = i+1;
[myButton addSubview:defaultLbl];
[myLbl release];
}
And for retrieving the UILabel text
- (void)longPressTap:(UILongPressGestureRecognizer *)sender
{
if ([recognizer.view tag]) {
for (UIButton *btn in scrollView.subviews) {
UIButton *btnTag = (UIButton *)btn;
NSLog(#"--sv:%#", btn.subviews);
if (recognizer.view.tag == btnTag.tag){
[[btn.subviews objectAtIndex:3] text] ;
}else {
[[btn.subviews objectAtIndex:3] textAttributesForNil] ;
}
}
}
}
}
my problem is i was not able to selected button subview label text and removing rest of the button label text.
please help me.
You shouldnt need to add a label as a subview for a button, buttons already have their own text label that can be set using [button setTitle:(NSString *) forState:(UIControlState)]
and to remove the text just set seTitle:#""
is there an easy way, such that each item in my UISegmentedControl for instance,
has multiple lines of text?
Thanks.
ps. I've also checked there's no easy way to change the height of UISegmentedControl?
Say in Code? Changing the style to "Bar" does not suit me, and setFrame does not
seem to work in my case too... :((
pps. This is the approach I tried as recommended by Siba but still have some issues.
for (id segment in [segmentedControl subviews])
{
for (id label in [segment subviews])
{
if ([label isKindOfClass:[UILabel class]])
{
UILabel *label2 = label;
//hear u add any of delegate function to increase the height and other label functionality in this
[label2 setTextAlignment:UITextAlignmentCenter];
[label2 setFont:[UIFont boldSystemFontOfSize:12]];
//to adjust the label size manually with respect to text use below code
CGSize labelSize = CGSizeMake(100, 80);
CGSize theStringSize = [label2.text sizeWithFont:label2.font constrainedToSize:labelSize];
CGRect frame = label2.frame;
frame.size = theStringSize;
label2.lineBreakMode = UILineBreakModeWordWrap;
label2.numberOfLines = 0;
[label2 setText:#"text \n 10%"];
}
}
}
1.You can try the following.
create a multiline UILabel
fill the label with N lines of text
convert the label into an UIImage
set the image as a segments content
Like one Done in This Answer :
UISegmentedControl text with multiple lines?
2.You can Take An ImageView in the back of Segmented Control with Same frame And Change images as per SelectedSegmentedIndex Like below.
But Don't forget to set Alpha of SegmentedControl to 0.05. At ViewDidLoad.
segment_Control.alpha=0.05;
The Coding will be Like this.
- (IBAction)segmented_Changed:(id)sender {
if (segmented_control.selectedSegmentIndex==0) {
segment_image.image=[UIImage imageNamed:#"tab_Act1.png"];
}else
if (segmented_control.selectedSegmentIndex==2) {
segment_image.image=[UIImage imageNamed:#"tab_Act3.png"];
}
else if (segmented_control.selectedSegmentIndex==1) {
segment_image.image=[UIImage imageNamed:#"tab_Act2.png"];
}
}
3.Also You Can try This :
for (id segment in [segmentedControl subviews])
{
for (id label in [segment subviews])
{
if ([label isKindOfClass:[UILabel class]])
{
//hear u add any of delegate function to increase the height and other label functionality in this
[label setTextAlignment:UITextAlignmentCenter];
[label setFont:[UIFont boldSystemFontOfSize:12]];
//to adjust the label size manually with respect to text use below code
CGSize labelSize = CGSizeMake(100, 80);
CGSize theStringSize = [label.text sizeWithFont:label.font constrainedToSize:labelSize];
CGRect frame = label.frame;
frame.size = theStringSize;
}
}
}
Source : Multiline Text On UIsegment Control