How to update UILabel programmatically in iOS - ios

I am facing a problem with updating my labels.. it doesn't remove the old values so new values go on top of old ones.. any help with this will be appreciated..
timer = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(updateLabels)
userInfo:nil
repeats:YES];
-(void) updateLabels{
for (GraphView *graph in arr){
// retrieve the graph values
valLabel = [[UILabel alloc] initWithFrame:CGRectMake(i * 200, 0, 90, 100)];
valLabel.textColor = [UIColor whiteColor];
valLabel.backgroundColor = [UIColor clearColor];
valLabel.text = [NSString stringWithFormat:#"Value: %f", x];
i++;
}
}

If you set the text of your label you do not need to call setNeedsDisplay or clearContext etc.
In your code, I do not know what are your variables i and x?
The main problem is that you are creating and adding new labels on your view. When you call updateLabels method, may cause a Memory leak. Simply you have n times labels overlapped.
You need to remove the labels before you create and add new labels or you can reuse which you already have. To reuse your labels you need to save them to an array and update texts.
If you want to create new labels then you can do like this unless you have other labels in your view
-(void) updateLabels{
// remove all labels in your view
for (UIView *labelView in self.view.subviews) {
if ([labelView isKindOfClass:[UILabel class]]) {
[labelView removeFromSuperview];
}
for (GraphView *graph in arr){
// retrieve the graph values
valLabel = [[UILabel alloc] initWithFrame:CGRectMake(i * 200, 0, 90, 100)];
valLabel.textColor = [UIColor whiteColor];
valLabel.backgroundColor = [UIColor clearColor];
valLabel.text = [NSString stringWithFormat:#"Value: %f", x];
i++;
}
}
When you create new labels like this you need to add them to your view as subview
[self.view addSubview: valLabel];
if you have other labels in your view then you can save them in an array and remove just them

Your updateLabels method is actually creating new UILabel controls each time so they will simply appear "on top of" older ones. I'm guessing this is not what you want, although it's not perfectly clear so apologies if I've misunderstood what you're trying to do.
If I'm correct about that, create your UILabel controls just once maybe in your viewDidLoad or similar. Then just set their .text properties when your timer fires.

You need to call setNeedsDisplay so that the app knows it has changed and redraw it.
- (void)setNeedsDisplay

Set clearsContextBeforeDrawing property of your label to YES
you can set this from nib as well as code.
label.clearsContextBeforeDrawing = YES;

Related

Multiple NSTimer animation views

- (void)createCar
{
_car = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 40, 10)];
[_car setBackgroundColor:[UIColor redColor]];
[self addSubview:_car];
_myTimer = [NSTimer scheduledTimerWithTimeInterval:normalSpeedValue target:self selector:#selector(moveCar) userInfo:nil repeats:YES];
}
- (void)moveCar
{
static int move = 0;
move = move+1;
[_car setFrame:(CGRectMake(move, 0, 40, 10))];
}
This is how I create a view and animate it moving from left to right.
If I call the method "createCar" again, it will just create a new view but I won't animate. Why is that?
I want to be able to create more views and animate (moveCar).
The reason that additional calls to createCar creates motionless, but still visible cars, is because the callback on the timer, moveCar, only has reference to the most recently created car stored in the _car ivar.
The past created cars are still visible because the view they were added to still holds reference to them and consequently continues to draw them.
You can fix this by creating an NSMutableArray for your cars, adding them to it in createCar, and then looping over the array moving each car in the moveCar method.
Sample Code:
// ...
NSMutableArray<UIView *> *_cars; // Be sure to init this somewhere
// ...
// ...
timer = NSTimer.schedule ... // Schedule time in viewDidLoad, or somwhere
// ...
- (void)createCar
{
UIView *_car = [[UIView alloc] initWithFrame: CGRectMake(0, 0, 100, 100)];
[_car setBackgroundColor: [UIColor redColor]];
[self.view addSubview: _car];
[_cars addObject:_car];
}
- (void)moveCars
{
// go through each car
[_cars enumerateObjectsUsingBlock:^(UIView *car, NSUInteger i, BOOL *stop) {
// and set its frame.x + 1 relative to its old frame
[car setFrame: CGRectMake(car.frame.origin.x + 1, 0, 100, 100)];
}];
}
This is one simple way of doing it. But if you want flexibility like different speeds for different cars, it'll take a little reworking but not much.
Hope this helps!
Every time your move became 0 when method get called. declared it as instance variable and set it's initial value 0 (in your case) in createCar method. I think this you want. hope this will help :)

UITextField is cutting off the right side of text and not displaying the cursor at the correct position

This problem can be demonstrated by creating a new project in Xcode (I am using version 6.4) and using the following code:
#interface ViewController ()
#property (nonatomic, strong) UITextField * myTextField;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.myTextField = [[UITextField alloc] initWithFrame:CGRectMake(50, 50, self.view.frame.size.width-100, 50)];
self.myTextField.textAlignment = NSTextAlignmentRight;
[self.myTextField becomeFirstResponder];
self.myTextField.backgroundColor = [UIColor lightGrayColor]
self.myTextField.adjustsFontSizeToFitWidth = YES;
self.myTextField.font = [UIFont systemFontOfSize:40];
[self.view addSubview:self.myTextField];
}
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.myTextField.text = #"1.5241578750119E18";
}
When running this project in iOS Simulator (iPhone 5 or 5S), the cursor is initially displayed after the last "1", and the "8" is not visible until a new character is typed.
This appears to be a bug by Apple, but my question is: is there a workaround for now that will force the text to right-align and show the cursor in the correct position?
To clarify the question further, the issue occurs when the text is set programmatically. I expect to see this:
But instead I am seeing this (note that the entire number is not visible and the cursor is showing after the "1" instead of the last digit which is an "8"):
This is a bug, existing in iOS, since iOS 7. Issue can be reproduced in stock applications like Settings as well. It affects text fields only when NSTextAlignmentRight is used. The original bug ID logged into Radar for this issue is 14485694. You may use centre or left text alignments, to circumvent this problem.
I would also suggest to file a new bug report to Apple,
Try this
UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 20)];
self.myTextField.leftView = paddingView;
self.myTextField.leftViewMode = UITextFieldViewModeAlways;
it will add some space to the left side of your TextField so that your cursor starts at correct position.
Hope it helps.
If I change your code to this:
- (void)viewDidLoad {
[super viewDidLoad];
self.myTextField = [[UITextField alloc] initWithFrame:CGRectMake(5, 50, self.view.frame.size.width-10, 50)];
self.myTextField.textAlignment = NSTextAlignmentRight;
[self.myTextField becomeFirstResponder];
self.myTextField.backgroundColor = [UIColor lightGrayColor];
self.myTextField.adjustsFontSizeToFitWidth = YES;
self.myTextField.font = [UIFont systemFontOfSize:60];
[self.view addSubview:self.myTextField];
}
And start typing in those numbers, the cursor ends up along the right edge of the text field just as it's supposed to.
Even when I start the app with the default value in the text, I see the cursor along the right edge of the text field fine.
Listening to UITextFieldTextDidChangeNotification notification instead of UIControlEventEditingChanged will fix the issue.
I met the same issue, try add dummy code like this
(void)textFieldDidBeginEditing:(UITextField *)textField {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
textField.text = textField.text;
});
}

Coded UIStepper not displaying

After not finding an answer I have to again ask you all for help. I am creating a UIStepper programatically but it will not display. Labels, buttons, and switches are all displaying properly so I must be missing something related to the stepper.
Elsewhere in my code I declare and initialize UIView *v and NSMutableArray *steppers, and declare UIStepper *st. The code to create the stepper is:
st = [[UIStepper alloc] init];
st.frame = CGRectMake(xnear, ypos, 0, 0);
[st addTarget:self action:#selector(stepper1:) forControlEvents:UIControlEventValueChanged];
[st setMinimumValue:0];
[st setMaximumValue:99];
[st setWraps:NO];
[st setContinuous:NO];
[v addSubview:st];
[steppers addObject:st];
At runtime xnear = 100 and ypos = 250, so the stepper is within the display. A label immediately above, and a text field immediately below, are displaying. Other questions regarding the UIStepper state the width and height are ignored, so I used 0 for both. Is there anything obviously wrong with this code?
You are setting height and width of UIStepper as 0
st.frame = CGRectMake(xnear, ypos, 0, 0);
give some height and width
st.frame = CGRectMake(xnear, ypos,200, 100);
The answer is, quite frankly, embarrassing. A custom background color was set for the UIView and no color was set for the control. I was able to get the stepper to show up with the following line of code:
st.backgroundColor = [UIColor whiteColor];
Similarly, the UISegmentedControl *sc showed up when I added:
sc.backgroundColor = [UIColor whiteColor];
Thanks for the help and sorry to waste your time!

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

Programatically generated UILabel origin point incorrectly to (0.0) set on first load

I am trying to programatically generate two UILabels in my application for each UIImageView on my storyboard. The code runs and works correctly, however, on first load the two UILabels form in the (0.0) coordinate of the main view, as opposed to the UIImageView frame origin.x,origin.y. I can't understand why this is happening.
If I then click on a different tab and return to the page, the labels generate in the correct location.
Why is this? How can I get it to initially generate the labels in the correct location?
-(void) viewWillAppear:(BOOL)animated
{
//removed unneccessary code above...
int i = 0;
for (UIImageView *plantScreen in self.view.subviews)
{
if ([plantScreen isMemberOfClass:[Plant class]])
{
#try
{
//the label which will hold the name
UILabel *plantName = [[UILabel alloc] initWithFrame:CGRectMake((plantScreen.frame.origin.x), (plantScreen.frame.origin.y+ plantScreen.frame.size.height), 160, 30.0)];
plantName.numberOfLines = 1;
plantName.minimumScaleFactor = .5;
plantName.adjustsFontSizeToFitWidth = YES;
[plantName setTextAlignment:NSTextAlignmentCenter];
[plantName setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:plantName];
plantName.hidden = false;
[self.view bringSubviewToFront:plantName];
//create the label which will hold the quantity
UILabel *quantity = [[UILabel alloc] initWithFrame:CGRectMake((plantScreen.frame.origin.x), (plantScreen.frame.origin.y+ plantScreen.frame.size.height + 20), 160, 30.0)];
[quantity setTextAlignment:NSTextAlignmentCenter];
[quantity setBackgroundColor:[UIColor clearColor]];
quantity.text = [NSString stringWithFormat:#"%d",plant.quantity];
[self.view addSubview:quantity];
quantity.hidden = false;
[self.view bringSubviewToFront:quantity];
i++;
}
#catch (NSException *exception)
{
NSLog(#"An exception occured: %#", [exception reason]);
}
#finally
{
}
}
}
}
Frame of the UIImageView depends on the image being drawn and its contentMode property. You can try setting the contentMode to UIViewContentModeScaleAspectFill to see if it forces to keep its assigned frame.
First things first, you're missing a call to [super viewWillAppear:animated]. You need to give the superclass (including the UIViewController base class) a chance to "do its magic".
Never forget about giving the parent class a chance to do its magic, unless you know really really well what you're doing.
Second, UI creation should be done in -loadView, not in viewWillAppear:.
Try these two things first.
Alright. Now I'm curious about how you moved things to -loadView. Did you add [super loadView];?
In fact, now that I think about it, moving to -loadView is wrong in this case; you obviously instantiate some views through a nib. UIViewController's implementation of -loadView typically just loads the nib file. Once that's done, UIViewController's -loadView calls -viewDidLoad.
So when you're not creating all UI programmatically but are instead allowing UIViewController to load it from nib, you actually probably want to move code into -viewDidLoad. (See template generated by Xcode when you tell it to create a new UIViewController subclass.)
Moving on, let's consider what the frame depends on. It depends on some view class you called Plant.
Please don't call it that way; it's confusing. Call it PlantView, so a casual reader of your code is aware of what the class is supposed to do. Similarly, you might want to call the variables plantView instead of plantScreen, and plantNameLabel instead of plantName. plantScreen implies a variable containing UIScreen, and plantName implies an NSString more than it implies a UILabel. Same applies to quantity; call this variable quantityLabel.
Next, let's consider what the variables are depending on -- their origin's x and y do not change based on the counter, variable i. Perhaps you meant to write:
UILabel *plantName = [[UILabel alloc] initWithFrame:CGRectMake((plantScreen.frame.origin.x), (plantScreen.frame.origin.y+ plantScreen.frame.size.height * i), 160, 30.0)];
and later on:
UILabel *quantity = [[UILabel alloc] initWithFrame:CGRectMake((plantScreen.frame.origin.x), (plantScreen.frame.origin.y+ plantScreen.frame.size.height*i + 20), 160, 30.0)];
Next, avoid exceptions and exception handling. Ensure that the exception does not occur via other forms of checking; Apple highly recommends you fix exceptions while writing the application and not handle them when they run:
Important: You should reserve the use of exceptions for programming or
unexpected runtime errors such as out-of-bounds collection access,
attempts to mutate immutable objects, sending an invalid message, and
losing the connection to the window server. You usually take care of
these sorts of errors with exceptions when an application is being
created rather than at runtime.
Next, a small stylistic remark (not very important): you're mixing calling setters via properties and calling setters directly. Nothing wrong (they end up doing exactly the same), but stylistically not very nice.
Next, unless you're using ARC (automatic reference counting), don't forget to release the views once they're added as subviews.
Next, plantScreen (which I named plantView below) can have type set to Plant (which I named PlantView below) when declared inside the loop.
Last but highly important and extremely easy to miss: you call the function isMemberOfClass: instead of isKindOfClass:.
Reworked version of your code (untested):
-(void)viewDidLoad
{
[super viewDidLoad];
int i = 0;
for (PlantView *plantView in self.view.subviews)
{
if ([plantView isKindOfClass:[PlantView class]])
{
//the label which will hold the name
CGRect plantNameLabelFrame = CGRectMake((plantScreenView.frame.origin.x),
(plantScreenView.frame.origin.y + plantScreen.frame.size.height*i),
160,
30.0);
UILabel *plantNameLabel = [[UILabel alloc] initWithFrame: plantNameLabelFrame];
plantNameLabel.numberOfLines = 1;
plantNameLabel.minimumScaleFactor = .5;
plantNameLabel.adjustsFontSizeToFitWidth = YES;
plantNameLabel.textAlignment = NSTextAlignmentCenter;
plantNameLabel.backgroundColor:[UIColor clearColor];
[self.view addSubview:plantNameLabel];
[plantNameLabel release];
//create the label which will hold the quantity
CGRect quantityLabelFrame = CGRectMake((plantScreenView.frame.origin.x),
(plantScreenView.frame.origin.y + plantScreen.frame.size.height*i + 20),
160,
30.0);
UILabel *quantityLabel = [[UILabel alloc] initWithFrame: quantityLabelFrame];
quantityLabel.textAlignment = NSTextAlignmentCenter;
quantityLabel.backgroundColor = [UIColor clearColor];
quantityLabel.text = [NSString stringWithFormat:#"%d", plant.quantity]; // NB: what's "plant"?
[self.view addSubview:quantityLabel];
i++;
}
}
}
I've also removed .hidden = false (which should actually read .hidden = NO; this is Objective-C, and not C++), and bringSubviewToFront: (it's already in front, having just been added by addSubview:).

Resources