Updating A UIView in customView field of UIBarButtonItem - ios

I am keeping a score of a game in the navigation bar.
I am trying to update the UILabel in UIBarButtonItem's customView.
After I call setText on UILabel, it does not get updated.
I tried to change its color just to test, that also does not work.
I tried to update the UILabel by calling setNeedsDisplay
I tried to update the customView in UIBarButtonItem by calling setNeedsDisplay.
Non of that actually updates the view.
I debugged and the code executes and prints the correct value on console when it gets to the line where I NSLog.
I also tried to update the whole view of navController by calling. (Current code does that below)
What is the right way to update/refresh the customView field of UIBarButtonItem
UIBarButtonItem* backUIButton =[view.navigationItem.rightBarButtonItems objectAtIndex:1];// I have 2 items in rightBarButtonList
UIView* settingFrame =backUIButton.customView;
for (UIView *i in settingFrame.subviews){
if([i isKindOfClass:[UILabel class]]){
UILabel *newLbl = (UILabel *)i;
if(newLbl.tag == 1){
/// Write your code
NSString *inStr = [NSString stringWithFormat:#"%ld", [Utility getCoins] ];
NSLog(#"data : %#",inStr);
[newLbl setTextColor:[UIColor redColor]];
[newLbl setText:inStr];
[view.navigationController.view setNeedsDisplay];
}
}
}
Thanks

I will just keep a property of the label
For example
I keep a property
#property (weak,nonatomic)UILabel * numlabel;
Here I create the custom bar item
UIView * customView = [[UIView alloc] initWithFrame:CGRectMake(0, 0,80,40)];
UILabel * label = [[UILabel alloc] init];
label.text = #"1";
label.frame = CGRectMake(0,0,80,40);
self.numlabel = label;
[customView addSubview:label];
UIBarButtonItem * item = [[UIBarButtonItem alloc] initWithCustomView:customView];
self.navigationItem.leftBarButtonItem = item;
Then When I need to change
self.numlabel.text = #"2";
I have test with my XCode,it works well

#interface HomeViewController ()
{
UILabel *label;//Globally declare the label to make changes
}
- (void)viewDidLoad
{
[super viewDidLoad];
label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 100, 30)];
label.text = #"First";
UIBarButtonItem *barButton = [[UIBarButtonItem alloc]initWithCustomView:label];//set label as barButtonItem
self.navigationItem.rightBarButtonItem = barButton;
}
here, i updated the label with a buttonAction
- (IBAction)buttonAction:(id)sender
{
label.text = #"second";//successfully updated the label
}

Related

IOS/Objective-C: Lazy load UILabel

I am creating a label programatically. Unfortunately, I've discovered that every time I update the label, I am creating a new instance. Is there a way to check if a UILabel already exists before you create it?
This is my current code to create label:
UILabel *percentLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, height, 280, 20)];
If I condition it on following, I get error that it does not recognize label:
for (id percentLabel in self.view.subviews) {
if (![percentLabel isKindOfClass:[UILabel class]]) {
UILabel *percentLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, height, 280, 20)];
}
percentLabel.textAlignment = NSTextAlignmentCenter;
Thanks for any suggestions.
There are many ways to check the object existence. In your example the if statement will create a label on every single iteration of the for cycle. A fixed version of that code will look like this:
UILabel *percentLabel = nil;
for (id subview in self.view.subviews) {
if ([subview isKindOfClass:[UILabel class]]) {
percentLabel = (UILabel *)subview;
break;
}
}
if (!percentLabel) {
// Label creation code here
}
However I would suggest you to store that label as a property in your view controller and initialize it lazily as it shown below:
...
#property (weak, nonatomic) UILabel *percentLabel;
...
- (UILabel *)percentLabel {
if (!_percentLabel) {
UILabel *percentLabel = /* initialization code here */;
// Add percent label as a subview to your view
_percentLabel = percentLabel;
}
return _percentLabel;
}
Note that I'm storing the property with a weak reference, because your view will actually own that label and keep a strong reference via it's subviews property.
It looks to me like you are looping over your subviews (some of which might not actually be labels) and you are trying to change the text alignment.
There are better ways to keep track of a label instance then looping over the subviews every time, such as setting a class property like:
UILabel *labelToChange;
in your interface decleration in your .h file.
Then in your implementation simply access the label using
labelToChange.textAlignment = NSTextAlignmentCenter;
Just make sure you only [UILabel alloc] init once to initialise an instance of UILabel
It would be easier to set a unique tag to your UILabel that way you do not need to check the class. Remember that there are even UILabel in UITableView, UINavigationBar, and so, and you don't want to mess with those.
So, what you should do is create 2 separate methods: one to create label and be called in viewDidLoad ONCE, and another is to update the label.
Create method:
-(void)createLabels {
UILabel *percentLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, height, 280, 20)];
percentLabel.tag = 1111; // a unique tag
[self.view addSubview:percentLabel];
}
Update method:
-(void)updateLabelWithText:(NSString*)newText {
UILabel *yourLabel = (UILabel*)[self.view viewWithTag:1111];
yourLabel.text = newText;
}
you can give percentLabel a unique tag value.
then you can use viewWithTag to get percentLabel, like
UILabel *percentLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, height, 280, 20)];
percentLabel.tag = 100;
[self.view addSubview:percentLabel];
//In another method
UILabel *percenLabel = [self.view viewWithTag:100];
if (percentLabel == nil) {
percentLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, height, 280, 20)];
percentLabel.tag = 100;
percentLabel.textAlignment = NSTextAlignmentCenter;
[self.view addSubview:percentLabel];
}
else {
percentLabel.textAlignment = NSTextAlignmentCenter;
}

Accessing UILabel created on run time

I have created UILabel (lblCount) and UIButton (btnAdd) on a UIButton (Add Item Button)'s action method. The new UILabel and UIButton is added to scrollview. The UILabel (lblCount) shows count of UIButton (btnAdd) tapped. Here, addBtnClickCount is an integer which counts the number of click.
UILabel * lblCount = [[UILabel alloc] initWithFrame:CGRectMake( 50, 100*addBtnClickCount, 25, 25)];
lblCount.text = [NSString stringWithFormat:#"%d",count];
lblCount.tag = addBtnClickCount;
lblCount.textColor = [UIColor whiteColor];
lblCount.textAlignment = NSTextAlignmentCenter;
[self.scrollView addSubview:lblCount];
addBtnClickCount = addBtnClickCount+1;
There will be multiple label (lblCount) and button (btnAdd) when user taps Add Item Button. I want to access particular label for particular add button and display the count.
You have already set tag on your label. Create a mutable array labelArray and add label to it. To access the particular label do following code on add button's action.
-(void)addItem:(UIButton*)button{
UILabel* lblShowCount = [_labelArray objectAtIndex:[button tag]];
lblShowCount.text = [NSString stringWithFormat:#"%d", [lblShowCount.text integerValue]+1];
}
Here i understand that #Hem Poudyal, know's that with help of viewWithTag.he will get output. but don't know how to achieved that. so i am describing over here.
Step 1: Here i am adding UILabel and UIButton to self.view instead of UIScrollView. i hope you can convert it as UIScrollView. here i applied some relation between UILabel tag and UIButton tag. that you can see in below code.
for (int i=0; i<10; i++) {
UILabel * lblCount = [[UILabel alloc] initWithFrame:CGRectMake( 50, (i*50)+((i+1)*5), 100, 50)];
lblCount.text = [NSString stringWithFormat:#"%d",0];
lblCount.tag = [[NSString stringWithFormat:#"%d%d",i,i] integerValue];
lblCount.backgroundColor = [UIColor yellowColor];
lblCount.textAlignment = NSTextAlignmentCenter;
[self.view addSubview:lblCount];
UIButton* btnTemp = [UIButton buttonWithType:UIButtonTypeCustom];
btnTemp.tag = i;
btnTemp.backgroundColor = [UIColor redColor];
[btnTemp addTarget:self action:#selector(btnTempClick:) forControlEvents:UIControlEventTouchUpInside];
btnTemp.frame = CGRectMake( 150, (i*50)+((i+1)*5), 100, 50);
[btnTemp setTitle:[NSString stringWithFormat:#"Button : %d",i] forState:UIControlStateNormal];
[self.view addSubview:btnTemp];
}
Step 2: In UIButton selector method, Do the following things.
-(IBAction)btnTempClick:(id)sender{
UIButton* btnInner = sender;
NSInteger lblTagbaseOnButtonTag = [[NSString stringWithFormat:#"%ld%ld",btnInner.tag,btnInner.tag] integerValue];
UILabel* lblReceived = (UILabel*)[self.view viewWithTag:lblTagbaseOnButtonTag];
lblReceived.text = [NSString stringWithFormat:#"%ld",[lblReceived.text integerValue]+1];
}
And Output is :
You should have an array that you add the labels and buttons too (this could be one array containing a dictionary or custom class or multiple arrays). Now, when a button is tapped you can find where it is in the array and get the corresponding label to update.
The cheat way is to set the tag of the buttons and labels so you can find one from the other using viewWithTag:.
You need to set unique tag value while creating the labels and buttons and by using viewWithTag: you can access the respective ui container.

iOS Calc X position to place elements on a View

I want to add a Label and an Image in titleView of my NavigationItem. I am adding UILabel and UIImageView to a UIView and setting it as titleView of the navigation Item. Things are being added, but I am not able to calculate the length of label and place image next to it.
My code is :-
// Title Name + Image
UIView *titView = [[UIView alloc] initWithFrame:self.navigationItem.titleView.bounds];
self.navigationItem.titleView = titView;
UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(-10, -20, 150, 30)];
title.text = #"Bunny ";
[title setTextColor:[UIColor orangeColor]];
[titView addSubview:title];
float x2 = 30; //+ title.bounds.size.width;
UIImageView *img = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"return" ]];
img.frame = CGRectMake(x2, -20, img.bounds.size.width, 30);
[titView addSubview:img];
I am looking for some way to calc the width text and set accordingly the width of the label. Right now I have set the width of the label as 150. And secondly, calc the x position to place the image just next to the label.
Tried many ways, but nothing works as expected. How can I achieve this ? Can you he give some guidelines such that regardless of length of text of label, things works as expected and UIView gets placed in the center of navigation item.
Any help is highly appreciated. Thanks.
You can call
[title sizeToFit];
after setting its properties and it will size itself to match the contained string.
Set the imageViews x origin to
CGRectGetMaxX(title.frame) + desiredSpacing;
And it could help to subclass UIView to achieve the final results by overwriting layoutSubviews and placing your views there, since the titleView's frame can be adjusted by the navigationBar...basically like this:
#implementation TitleView{
UILabel *_titleLabel;
UIImageView *_img;
}
- (id)initWithTitle:(NSString *)title andImage:(UIImage *)image
{
self = [super init];
if (self) {
_titleLabel = [[UILabel alloc] init];
_titleLabel.text = title;
[_titleLabel setTextColor:[UIColor orangeColor]];
[_titleLabel sizeToFit];
[self addSubview:_titleLabel];
_img = [[UIImageView alloc] initWithImage:image];
[self addSubview:_img];
}
return self;
}
- (void)layoutSubviews{
CGFloat spacingBetweenTextAndImage = 0;
CGFloat width = CGRectGetWidth(_titleLabel.frame)+CGRectGetWidth(_img.frame)+spacingBetweenTextAndImage;
CGFloat x = (CGRectGetWidth(self.bounds)-width)/2;
_titleLabel.frame = CGRectMake(x, (CGRectGetHeight(self.bounds)-CGRectGetHeight(_titleLabel.bounds))/2, CGRectGetWidth(_titleLabel.bounds), CGRectGetHeight(_titleLabel.bounds));
x+=CGRectGetWidth(_titleLabel.bounds)+spacingBetweenTextAndImage;
_img.frame = CGRectMake(x, (CGRectGetHeight(self.bounds)-CGRectGetHeight(_img.bounds))/2, CGRectGetWidth(_img.bounds), CGRectGetHeight(_img.bounds));
}
#end
use in your viewController:
UIView *titleView = [[TitleView alloc] initWithTitle:#"Bunny" andImage:[UIImage imageNamed:#"return" ]];
self.navigationItem.titleView = titleView;

Why UILabel in UINavigation is not centered

I use custom back btn in navigation controller:
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc]
initWithTitle:NSLocalizedString(#"Back", nil)
style:UIBarButtonItemStylePlain
target:nil
action:nil];
//and add custom label in this:
heightNav = self.navigationController.navigationBar.frame.size.height;
widthNav = self.navigationController.navigationBar.frame.size.width;
self.aCNavLabel = [[ACNavLabel alloc] initWithFrame:CGRectMake(0, 0, widthNav, heightNav)];
self.aCNavLabel.text = NSLocalizedString(#"Settings", nil);
//
UIView *titleNavView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, widthNav, heightNav)];
self.navigationItem.titleView = titleNavView;
[self.navigationItem.titleView addSubview:self.aCNavLabel];
but label is not centered.
Please tell me where I made a mistake?
and custom label aCNavLabel:
#implementation ACNavLabel
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
self.textColor = [UIColor blackColor];
self.font = FONT_OP_STD(22.0f);
// self.text = title;
self.textAlignment = NSTextAlignmentCenter;
}
return self;
}
I change some rules for this
self.navigationItem.titleView = self.aCNavLabel;
and and there was something incredible
this is first viewController and
and next what is this????
self.navigationController.navigationBar setTitleTextAttributes:(NSDictionary *)
This method will be Ok
you can customer the navigationBar title about the font,the color,the textAlign and other properties;
self.aCNavLabel = [[ACNavLabel alloc] initWithFrame:CGRectMake(0, 0, widthNav, heightNav)];
self.aCNavLabel.text = NSLocalizedString(#"Settings", nil);
self.aCNavLabel.textAlignment = NSTextAlignmentCenter; // SET THIS
You need to set the text alignment to center like:
aCNavLabel.textAlignment = NSTextAlignmentCenter;
Refer the UILabel textAlignment property for more options.
or as #NANNAV suggested use:
self.navigationItem.titleView = self.aCNavLabel;
aCNavLabel.textAlignment = NSTextAlignmentCenter;
try it.
Create category for UINavigationBar and programmatically adjust the position of your title label. set ACNavLabel view as titleview.
UINavigationBar+MyNavigationBar.h
#interface UINavigationBar (MyNavigationBar)
#end
UINavigationBar+MyNavigationBar.m
#implementation UINavigationBar (MYNavigationBar)
- (void)layoutSubviews {
for (UIView *view in self.subviews) {
if ([view isKindOfClass:[ACNavLabel class]]) {
view.center = CGPointMake(self.center.x, self.center.y);
}
}
}
#end

iOS Bounds of UIView in ViewDidLoad

I wanted to use the bounds of a UIView to create a UILabel and add it to that UIView inside the viewDidLoad method, however, I have found that the bounds of UIView is still null inside viewDidLoad. But when I look at a demo app, the bounds of its UIView is already initialised in viewDidLoad.
In the interface I have
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIView *promotionView;
#end
And I am trying to do
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *container = [[UIView alloc] initWithFrame:self.promotionView.bounds];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, container.bounds.size.height-100, 320, 20)];
label.text = #"Promotion Title";
[container addSubview:label];
[self.promotionView addSubview: container];
}
but it doesn't work because the bounds of promotionView is null.
You can do it like this in viewDidAppear:
-(void)viewDidAppear:(BOOL)animated {
static int first = 1;
if (first) {
UIView *container = [[UIView alloc] initWithFrame:self.promotionView.bounds];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, container.bounds.size.height-100, 320, 20)];
label.text = #"Promotion Title";
[container addSubview:label];
[self.promotionView addSubview: container];
first = 0;
}
}

Resources