Adding text to a UIScrollView - objective-c

I'm creating a tape measure in a UIScrollView, it has horizontal lines from an image and I want to add the numbers programatically.
(Note the blue was to help getting the layout right)
I tried this:
for (NSInteger i = 0; i < self.maxUnits.integerValue; i++) {
static CGFloat labelWidth = 40;
CGFloat x = (halfScreen - (labelWidth/2)) + (i * self.widthOfOneFraction.floatValue * self.numberOfFractions.floatValue);
CGRect frame = CGRectMake(x-1, 41, labelWidth, 70);
UILabel *label = [[UILabel alloc] initWithFrame:frame];
label.text = [NSString stringWithFormat:#"%d", i];
label.textAlignment = NSTextAlignmentCenter;
label.textColor = [UIColor tlbBlueColor];
label.font = [UIFont fontWithName:#"HelveticaNeue-Light" size:20.0];
[self addSubview:label];
}
Which works, but uses about 40Mb of RAM. I thought that adding the text in a CATextLayer might be more efficient, but I can't get it working:
for (NSInteger i = 0; i < self.maxUnits.integerValue; i++) {
CATextLayer *label = [[CATextLayer alloc] init];
[label setFont:#"HelveticaNeue-Light"];
[label setFontSize:20];
[label setFrame:frame];
[label setString:[NSString stringWithFormat:#"%d", i]];
[label setAlignmentMode:kCAAlignmentCenter];
[label setForegroundColor:[[UIColor whiteColor] CGColor]];
[self.layer addSublayer:label];
}
The numbers don't appear on the screen.
So my question is can I either make the first way more efficient, and if not is the second way more efficient when it works and if so how do I get it working?

I changed the way the loading worked so as to only load items on display and to load a few more as you scroll.
This seems to have totally fixed the high memory issue and even if you scroll to both ends it doesn't use the same high amount of memory. I guess there was a leak in how my original code worked.

Related

UIButton is not setting text

I seem to have a problem in my Objective C iOS app where I am creating multiple buttons depending on the amount of objects in an array. I know Swift, so I replicated the logic into Swift, and it worked. Yet in Objective C, I am unable to see the text of the button (after I remove the for loop) or create multiple buttons. For example, I have an array full of three names. I would like to create a button for each name with the title set to the corresponding name. So far, I have this:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray *ages = [[NSMutableArray alloc] init];
for (int i = 0; i > 10; i++) {
[ages addObject:[NSString stringWithFormat:#"%i", i]];
}
UIScrollView *scrollView= [[UIScrollView alloc]initWithFrame:self.view.frame];
scrollView.delegate= self;
self.automaticallyAdjustsScrollViewInsets= NO;
scrollView.backgroundColor= [UIColor clearColor];
scrollView.scrollEnabled= YES;
scrollView.userInteractionEnabled= YES;
[scrollView setShowsHorizontalScrollIndicator:NO];
[scrollView setShowsVerticalScrollIndicator:NO];
CGFloat xValue = 0;
for(int x=0; x > ages.count; x++){
UIButton *button= [[UIButton alloc] initWithFrame:CGRectMake(xValue ,0 , 172 ,65)];
UIColor *buttonOutline = [[UIColor redColor] CGColor];
button.layer.borderColor = [buttonOutline CGColor];
button.layer.backgroundColor = [[UIColor clearColor] CGColor];
button.layer.borderWidth = 1.0;
button.layer.cornerRadius = 6.0;
[button.titleLabel setFont:[UIFont fontWithName:#"Helvetica" size:13.0]];
button.titleLabel.text = [ages objectAtIndex:x];
[button addTarget:self action:#selector(test:) forControlEvents:UIControlEventTouchUpInside];
[scrollView addSubview:button];
NSLog(#"Button Added");
xValue = button.frame.size.width + 40;
}
scrollView.contentSize = CGSizeMake(xValue, 65);
[self.view addSubview:scrollView];
}
- (void)test:(UIButton*)sender{
NSLog(#"Clicked %#", sender.titleLabel.text);
}
#end
If anyone sees anything wrong with this code, please point it out!
Thanks,
Arnav K.
I found four problems (there may be others) that stop this working correctly:
1) The for loop bound when setting up the ages array is incorrect.
2) The for loop bound when creating the buttons is incorrect.
3) You are setting the buttonOutline colour incorrectly.
4) xValue is being updated incorrectly.
Here is the viewDidLoad method after the changes have been made:
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray *ages = [[NSMutableArray alloc] init];
for (int i = 0; i < 10; i++) { // UPDATED
[ages addObject:[NSString stringWithFormat:#"%i", i]];
}
UIScrollView *scrollView= [[UIScrollView alloc]initWithFrame:self.view.frame];
scrollView.delegate= self;
self.automaticallyAdjustsScrollViewInsets= NO;
scrollView.backgroundColor= [UIColor clearColor];
scrollView.scrollEnabled= YES;
scrollView.userInteractionEnabled= YES;
[scrollView setShowsHorizontalScrollIndicator:NO];
[scrollView setShowsVerticalScrollIndicator:NO];
CGFloat xValue = 0;
for(int x=0; x < ages.count; x++){ // UPDATED
UIButton *button= [[UIButton alloc] initWithFrame:CGRectMake(xValue ,0 , 172 ,65)];
UIColor *buttonOutline = [UIColor redColor]; // UPDATED
button.layer.borderColor = [buttonOutline CGColor];
button.layer.backgroundColor = [[UIColor clearColor] CGColor];
button.layer.borderWidth = 1.0;
button.layer.cornerRadius = 6.0;
[button.titleLabel setFont:[UIFont fontWithName:#"Helvetica" size:13.0]];
button.titleLabel.text = [ages objectAtIndex:x];
[button addTarget:self action:#selector(test:) forControlEvents:UIControlEventTouchUpInside];
[scrollView addSubview:button];
NSLog(#"Button Added");
xValue += button.frame.size.width + 40; // UPDATED
}
scrollView.contentSize = CGSizeMake(xValue, 65);
[self.view addSubview:scrollView];
}
I have marked the four lines I changed with a UPDATED comment so you can compare them to the original.
EDIT
To change the text and text colour use the following:
[button setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[button setTitle:[ages objectAtIndex:x] forState:UIControlStateNormal];
and remove this:
button.titleLabel.text = [ages objectAtIndex:x];
You need to do this because you can set different text for the different states of the button and this is all handled automatically for you.

Constraint spacing UILabel in For Loop

I have a small problem and hope someone can help me solve it ... I searched the net and made some attempts, but I could not solve my problem.
I created a FOR loop that plays a specified number of labels obtained through an array, as you can see from the code that I posted below ...
Now my problem is how to insert constraint programmatically. I need that between a label and the other (horizontal) there is a specific space.
Example:
if I label 4 I would like these would take around the horizontal space is in the iPhone display SE both iPhone 7 Plus ..
So my question is how do I set a specific space between each label and pass in the FOR loop?
CGFloat padding = 0;
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:#"INFO UNIVERSITARIE",#"INFO GENERALI", #"TROVA SEDI", nil];
for (NSInteger i = 0; i < array.count; i ++) {
NSString *valueText = [array objectAtIndex:i];
UILabel *label = [[UILabel alloc] init];
label.frame = CGRectMake(padding *i, 0, 50, 30);
label.text = [NSString stringWithFormat:#"%#", valueText];
label.textColor = [UIColor whiteColor];
label.font = [UIFont fontWithName:#"HelveticaNeue" size:12];
[label sizeToFit];
[_baseView addSubview:label];
padding = label.frame.size.width;
label.translatesAutoresizingMaskIntoConstraints = NO;
}
Researching this, I remembered that the UIStackView is our new friend, designed specifically for this problem.
NSArray *array = #[ #"INFO UNIVERSITARIE",#"INFO GENERALI", #"TROVA SEDI" ];
NSMutableArray *labels = [NSMutableArray array];
for (NSString *string in array) {
UILabel *label = [[UILabel alloc] init];
label.text = string;
[labels addObject:label];
}
UIStackView *stackView = [[UIStackView alloc] initWithArrangedSubviews:labels];
stackView.axis = UILayoutConstraintAxisHorizontal;
stackView.spacing = 12.0;
stackView.frame = self.view.bounds;
[self.view addSubview:stackView];
Just learned about this myself, but I tried this code and it works nicely.

How to add text shadows to a UITextView?

I've been searching around to find an easy way to add shadows to the text of a UITextView, like you can do in a UILabel. I found this question where there was an answer that supposedly does this, however, it makes no sense why this should be the case.
Question: Adding shadows to the layer of the UITextView itself should not affect the text inside, rather it should shadow the entire object, right?
In my case, even adding the shadow to the layer of the textview is not having any effect (even after adding the QuartzCore headers).
i tried, and found that , you should set the UITextView's backgroundcolor to transparent,
so the shadow should work
UITextView *text = [[[UITextView alloc] initWithFrame:CGRectMake(0, 0, 150, 100)] autorelease];
text.layer.shadowColor = [[UIColor whiteColor] CGColor];
text.layer.shadowOffset = CGSizeMake(2.0f, 2.0f);
text.layer.shadowOpacity = 1.0f;
text.layer.shadowRadius = 1.0f;
text.textColor = [UIColor blackColor];
//here is important!!!!
text.backgroundColor = [UIColor clearColor];
text.text = #"test\nok!";
text.font = [UIFont systemFontOfSize:50];
[self.view addSubview:text];
#adali's answer will work, but its wrong. You shouldn't add the shadow to the UITextView itself in order to effect the visible views inside. As you can see, by applying the shadow to the UITextView the cursor will also have the shadow.
The approach that should be used is with NSAttributedString.
NSMutableAttributedString* attString = [[NSMutableAttributedString alloc] initWithString:textView.text];
NSRange range = NSMakeRange(0, [attString length]);
[attString addAttribute:NSFontAttributeName value:textView.font range:range];
[attString addAttribute:NSForegroundColorAttributeName value:textView.textColor range:range];
NSShadow* shadow = [[NSShadow alloc] init];
shadow.shadowColor = [UIColor whiteColor];
shadow.shadowOffset = CGSizeMake(0.0f, 1.0f);
[attString addAttribute:NSShadowAttributeName value:shadow range:range];
textView.attributedText = attString;
However textView.attributedText is for iOS6. If you must support lower versions, you could use the following approach.
CALayer *textLayer = (CALayer *)[textView.layer.sublayers objectAtIndex:0];
textLayer.shadowColor = [UIColor whiteColor].CGColor;
textLayer.shadowOffset = CGSizeMake(0.0f, 1.0f);
textLayer.shadowOpacity = 1.0f;
textLayer.shadowRadius = 0.0f;

Scroll to xib (pagecontrol)

i had a small question, i'm using this code to scroll from color to color:
NSArray *colors = [NSArray arrayWithObjects:[UIColor redColor], [UIColor greenColor], [UIColor blueColor], nil];
you can scroll from color to color, but is there a way to scroll to another xib file?
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *colors = [NSArray arrayWithObjects:[UIColor redColor], [UIColor greenColor], [UIColor blueColor], nil];
for (int i = 0; i < colors.count; i++) {
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
UIView *subview = [[UIView alloc] initWithFrame:frame];
subview.backgroundColor = [colors objectAtIndex:i];
[self.scrollView addSubview:subview];
[subview release];
}
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * colors.count, self.scrollView.frame.size.height);
}
This tutorial will help you out: http://www.iosdevnotes.com/2011/03/uiscrollview-paging/
(i think that you've use this tutorial)
but on the last line of the tutorial:
Update: In the comments, some people have asked about placing buttons
inside the scroll view, and also about setting up the scroll view
using Interface Builder. I’ve added some code that includes buttons
here, and a version using Interface Builder here.
So here is the link to move to xib files: https://github.com/cwalcott/UIScrollView-Paging/tree/buttons-ib
Good luck,
Nathan
Instead of preparing UIView's and adding them to a scrollview, you could indeed use [[NSBundle mainBundle] loadNibNamed... to load several nib (which are compiled xib) and add them to a scrollview, and then scroll them up and down, or back and forth.

Fit text in UILabel

Here is my code
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(10, 50, 300, 50)];
label.textAlignment = UITextAlignmentCenter;
label.backgroundColor = [UIColor clearColor];
label.textColor = [UIColor whiteColor];
label.textColor.font = [UIFont fontWithName:#"Verdana" size:30];
label.text = #"A very long string";
etc...
The problems is that the font is large and can't fit in the label. It just display "A very"
What to do so entire text to be displayed.
I have tried
label.lineBreakMode = UILineBreakModeWordWrap;
label.numberOfLines = 0;
But it doesn't work for me.
I want to do that programmatically.
//EDIT
CGRect frame = CGRectMake(10, 50, 300, 50);
NSString *labelString = #"Players.";
UILabel *howManyUsersLabel = [[UILabel alloc]initWithFrame:frame];
howManyUsersLabel.textAlignment = UITextAlignmentCenter;
howManyUsersLabel.backgroundColor = [UIColor clearColor];
howManyUsersLabel.textColor = [UIColor whiteColor];
howManyUsersLabel.adjustsFontSizeToFitWidth = NO;
howManyUsersLabel.numberOfLines = 0;
CGFloat fontSize = 30;
while (fontSize > 0.0)
{
CGSize size = [labelString sizeWithFont:[UIFont fontWithName:#"Verdana" size:fontSize] constrainedToSize:CGSizeMake(frame.size.width, 10000) lineBreakMode:UILineBreakModeWordWrap];
if (size.height <= frame.size.height) break;
fontSize -= 1.0;
NSLog(#"test");
}
howManyUsersLabel.font = [UIFont fontWithName:#"Verdana" size:fontSize];
I think you just need to add this:
label.adjustsFontSizeToFitWidth = YES;
label.minimumFontSize = 0;
Then the text will automatically resize to fit the label.
Note however that this will only really work if the label.numberOfLines = 1, so that the text is on a single line.
If you need the text to wrap onto multiple lines but still shrink to fit, the solution is more complex. To do this, you need to calculate the rendered size of the text and then reduce it in a loop, as follows:
NSString *theText = #"A long string";
CGRect labelRect = CGRectMake(10, 50, 300, 50);
label.adjustsFontSizeToFitWidth = NO;
label.numberOfLines = 0;
CGFloat fontSize = 30;
while (fontSize > 0.0)
{
CGSize size = [theText sizeWithFont:[UIFont fontWithName:#"Verdana" size:fontSize] constrainedToSize:CGSizeMake(labelRect.size.width, 10000) lineBreakMode:UILineBreakModeWordWrap];
if (size.height <= labelRect.size.height) break;
fontSize -= 1.0;
}
//set font size
label.font = [UIFont fontWithName:#"Verdana" size:fontSize];
This basically just reduces the font size until it fits the label.
UPDATE:
As of iOS7, multiline text will also shrink automatically when adjustsFontSizeToFitWidth = YES, so the second part of this answer is no longer needed (unless you still support iOS 6 and earlier).
Finally I got solution for text allignment issue in arabic language you just do like this:
label.text = #"هذا هو نص طويل جدا";
label.textAlignment = NSTextAlignmentNatural;
CGSize size = [labels sizeThatFits:CGSizeMake(_lblAddress.width, CGFLOAT_MAX)];
label.height = size.height;
[UILabel sizeToFit];
It will work for your problem.
Swift with iOS 9
let maxFontSize: CGFloat = 40
let minFontSize: CGFloat = 10
label.font = UIFont(name: label.font.fontName, size: maxFontSize)!
label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = minFontSize/maxFontSize
This doesn't increase the font size to fill the label. It just starts with the max size and decreases as necessary down to the minimum. This is also assuming that the number of lines is 1.
CGRect titleRect = CGRectMake(10, 50, 300, 50);
UILabel *textTitleView = [[UILabel alloc] initWithFrame:titleRect];
textTitleView.numberOfLines = 3 //for multiple lines;
textTitleView.lineBreakMode = UILineBreakModeWordWrap;
[UIFont fontWithName:#"Verdana" size:30];
textTitleView.text = #"your text";
Interface Builder lets you do this now.
In UILabel, under Autoshrink, select "Minimum Font Size" instead of "Fixed Font Size".
Set the Minimum Font Size to be something reasonable, like 8.
You can also check the checkmark "Tighten Letter Spacing".
Alternatively you can do it programmatically:
label.adjustsFontSizeToFitWidth = YES;
Everything seems to be broken in iOS 8 (probably iOS 7 too).
Solution:
-(UIFont*)fontForString:(NSString*)string toFitInRect:(CGRect)rect seedFont:(UIFont*)seedFont {
UIFont* returnFont = seedFont;
CGSize stringSize = [string sizeWithAttributes:#{NSFontAttributeName : seedFont}];
while(stringSize.width > rect.size.width){
returnFont = [UIFont systemFontOfSize:returnFont.pointSize -1];
stringSize = [string sizeWithAttributes:#{NSFontAttributeName : returnFont}];
}
return returnFont;
}
Make sure you don't try and use label.adjustsFontSizeToFitWidth = YES otherwise it'll get really confused and the new size won't work properly.