Dynamically create UIButton based on response from server - ios

I need to implement a view that require me to create a buttons based on the response from the server.
Example response:
{
...
"enable_button_1" = 1;
"enable_button_2" = 1;
"enable_button_3" = 1;
...
}
Currently, I try to create the buttons manually using Interface Builder. And each of them are embedded in UIView and put on top of each other. Like so:
They are hidden by default. So, whenever on or more buttons enabled, I will check using if conditions and then unhide the view.
eg. only one button enabled
eg. two button enabled
But the thing is by doing so, I would probably miss a few use case and this seems like a bad practices. Is there any way that I could create it dynamically instead of creating multiple buttons in UIViews in Interface Builder?

You can always create buttons programatically and add them to your view. You'd have to calculate the width of the button-frame so that they always fit the view 100%.
For example somehow like this:
//Here you'd have to calculate the correct position of the button you want to add
CGRect frame = CGRectMake(0, 0, self.buttonView.frame.size.width, self.buttonView.frame.size.height);
UIButton *button = [[UIButton alloc] initWithFrame:frame];
[button setTitle:#"myButton" forState:UIControlStateNormal];
[self.buttonView addSubview:button];

Related

UIButton center position doesn't update with rotation

I have a program that dynamically generates UIButtons in the center of
the screen with push of another button.
The buttons are not updating the x-coordinates when I rotate the device.
Here is my code for creating buttons:
- (IBAction)createButton:(UIButton *)sender {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setBackgroundColor:[UIColor redColor]];
[button addTarget:self action:#selector(doSomething:) forControlEvents:UIControlEventTouchUpInside];
button.frame = CGRectMake(self.xCoord,self.yOffset,100.0,120.0);
[self.view addSubview:button];
_yOffset = _yOffset+130;
}
The XCoord and self.yOffset were set in viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
self.yOffset = 109;
self.xCoord = self.view.bounds.size.width/2-50;
}
The coordinates of the button in your code are fixed once they've been added to the view. If you want to update the frame of the buttons when the screen rotates, you'll need to trigger the repositioning of the buttons when the screen rotates.
AutoLayout in a storyboard makes this easier (if you just want a button to appear then you can add it in a storyboard and change its hidden property from NO to YES when the other button is pressed -- this won't be helpful if you want to add an arbitrary number of buttons, although you could have a hidden placeholder view that you use as a positioning reference)
If you want to keep the buttons x-position, you need to add Auto Layout constraints. There are a couple ways to do this programmatically. You can use the NSLayoutConstraint object directly or use Auto Layout's Visual Format Language. For more info, see Apple's documentation.

Automatic view id's like in android

I need to write some gui for IOS, yet i am so used to the automatic view id's that android has, that i am at a loss when it comes to identifying views without putting explicit tags in the interface builder
is there some way to automatically identify iOS views from interface builder or otherwise ?
maybe a library that does that ?
Thats why you have IBOutlets. Create an IBOutlet for your views, like so IBOutlet UIView *view1; etc etc then in link the IBOutlet to your view in Interface Builder. Now you can progammatically use the view1 variable which will modify your view associated to that IBOutlet in interface builder\
UPDATE
Progammatically create all your views like so:
for(int i = 0; i < 20; i++){
//set your x and y coordinates with some awesome maths, maybe you want to create a grid, so update the x coordinate accordingly
UIView *view = [UIView alloc] initWithFrame:CGRectMake(whateverframe)];
UITapGestureRecognizer *singleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(viewTapped:)];
[imageView addGestureRecognizer:singleTapGesture];
[singleTapGesture release]; //remove line if you have an ARC project
view.tag = i; //this is just for you since you like to handle your views with id tags
}
Then your one method that will handle the taps for all your code
- (void) viewTapped:(UIGestureRecognizer*)recognizer
{
UIView *viewTapped = recognizer.view; // This is the view associated with gesture recognizer.
int id = viewTapped.tag; //heres the tag id do whatever you like
//do something with either that view variable which will return the view that was tapped
//maybe you wanted to change the color of it or something or change the contents of it
//or you can do something with the id tag of that view.
//or maybe you just want to handle it with if else statements like so
//if(viewTapped.tag == 1) //do this
//elseif(viewTapped.tag == 2) // etc etc
}
Set Tag for each and every view using property setTag and retrieve the corresponding view using – viewWithTag:. [abaseView subViews] returns an array of subviews. Filter the subviews using Class and Tag.

How to create and add UIButton with multiline label from code using autolayout?

There's are a lot of links how to size a label, however there's a lack of info how to resize UIButton according to its label size. Currently, I have screen view set with autolayout (all the system constraints are added from IB) and everything works fine, but need to add dynamic content at the bottom of the screen. I need to create and add random number of buttons with random length titles. So, here's code fragment for creating and adding the buttons:
// Loop
UIButton *myButton = [UIButton new];
UIButton.frame = CGRectMake(0, previousButtonOriginY, self.view.bounds.size.width, 20);
myButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
myButton.titleLabel.textAlignment = NSTextAlignmentLeft;
myButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
[myButton setTitle:#"very long title..." forState:UIControlStateNormal];
myButton.titleLabel.numberOfLines = 0;
[self.footerView addSubview:myButton];
The problem is the frame height of the button stays 20px but the label string is shown on three lines and so overlaps with the other button title. If I add [myButton sizeToFit] then button width is resized to fit all the text into one line and so the title goes beyond the screen.
If I add [myButton sizeThatFits:CGSizeMake(320, 100)] then resize is not working at all. I know sizeToFit should not be called at all because it's not the part of autolayout, however need suggestions on that how easily to make button fit its label to screen 320 width.
I feel I need to add system constraints from code, but haven't done that before, so not sure how it should look like. I probably need a ton of constraints to be added from code in order to get this simple thing working :)
Instead of using Autolayout, you could just use a collection view which better options for you to lay out elements such as buttons.
It is better able to handle layouts under rotation as well.
Or you can use this code, it worked for me...
For example, substitute your desired padding values here:
UIButton* myButton = [[UIButton alloc] init];
// setup some autolayout constraints here
myButton.titleEdgeInsets = UIEdgeInsetsMake(-desiredBottomPadding,
-desiredRightPadding,
-desiredTopPadding,
-desiredLeftPadding);
Combined with the right autolayout constraints, you end up with an auto-resizing button which contains an image and text!
For this kind of customizations you'll need to create a subclass of UIButton. In the subclass you can add a customized label which benefits your needs. You can also override to setTitle:forState method to automatically update your customized label.

Add custom UIView programmatically created inside XIB UIView

I've created a UIView programmatically that embeds several UIControls (UIButtons, UISwitchs and UILabels mainly). I set in the -(id)initWithFrame: of this class the background color.
I have created a message to add the UIControls in the view in order to put inside of my custom view. It's something like that:
-(void) CreateGuiObjects
{
UIView *container = self;
//create uiswitch
mOnOffSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(10, 20, 0, 0)];
mOnOffSwitch.translatesAutoresizingMaskIntoConstraints = NO; //used for constraint testing
//add parent view (self)
[container addSubview: mOnOffSwitch];
/*
other stuff like above
*/
}
then in my view controller there is an event handler for an external button; the action is to add the above custom view in an empty UIView created with Storyboard Interface Builder in Xcode.
the code is like the following:
-(void)CreateButton
{
MyCustomView *view = [MyCustomView alloc] initWithFrame:CGRectMake(20,20,300,200)];
[self.view addSubview: view];
//now call my create method
[view CreateGuiObjects];
}
now, the problem is that it draws the controls, but it seems to position them in a different place...i set the frame origin for the container view in (20,20) and then put the switch in (10,20) where this point is relative to the custom view origin. Instead of that position the view seem to be far away from that position and the second problem is that the background color (gray) set in the initWithFrame is totally ignored.
If i remove every call to addSubview inside the CreateGuiObjects, it draws the empty view with the correct background color and in the correct position.
Edit:
if remove `mOnOffSwitch.translatesAutoresizingMaskIntoConstraints = NO; it works fine...but if i put again it doesn't work. Need to understand deeply the meaning of this property.
Could someone can help me? i think it is a silly question but i'm new to iOS development :(
thanks in advice
Method translatesAutoresizingMaskIntoConstraints = YES means that the UIView is using Auto Layout.
The fundamental building block in Auto Layout is the constraint.
Constraints express rules for the layout of elements in your
interface; for example, you can create a constraint that specifies an
element’s width, or its horizontal distance from another element. You
add and remove constraints, or change the properties of constraints,
to affect the layout of your interface.
When calculating the runtime positions of elements in a user
interface, the Auto Layout system considers all constraints at the
same time, and sets positions in such a way that best satisfies all of
the constraints.
read more about Auto Layout Concepts
If you don't know how to use Auto Layout I would recommend you to turn it off.

How to use the same [Storyboard] view for multiple tabs, and just change little things about it depending on the tab selected? (iOS)

I know this question is worded kind of strangely, but let me explain what I'm trying to do:
Let's say that I have an app with 2 tabs, each with their own view. Both views are almost exactly the same, except one contains a button or two that the other one doesn't, and vice versa.
I already made one view in Storyboard mode, now I want to change just a little tiny bit about it and reuse the same view for the other tab.
I don't want to do a deep copy, because if I change one, then I would have to change the other, and that might cause some inconsistency between the two.
So how should I go about using the same generic view for multiple tabs, and just change little things about it depending on which tab I am in?
Should I add the universal content in storyboard view, and then programmatically add the particular tab-exclusive content? If I did this, I would need a way to detect what tab is selected, right? Is there a way to do that?
Thank you for any suggestions!
You don't need a Storyboard for that. Sure you can drag a view in there and assign it to a specific class and program all stuff in that, but if you really need only one view in there the storyboard is useless. You should deal with subviews programmatically if you want to change something. This is very good and you have great features like animationWithDuration:
For checking which Tab in your UITabBarController is selected you can use self.tabBarController.selectedIndex and compare it with the given Index of the Tab which is selected.
EDIT:
If we assume you have a green Button on Tab with index 0, and the same Button should slide a little bit above and a red Button should appear where green Button when Tab with index 1 is tapped.
UIButton *greenButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 320, 100, 20)];
greenButton.backgroundColor = [UIColor greenColor];
[self.view addSubview:greenButton];
UIButton *redButton = [[UIButton alloc] initWithFrame:CGRectMake(0, greenButton.frame.origin.y, 100, 20)];
greenButton.backgroundColor = [UIColor redColor];
if (self.tabBarController.selectedIndex == 1) {
[UIView animateWithDuration:1.0 animations:^{
greenButton.frame = CGRectMake(0, 300, 100, 20);
} completion:^(BOOL finished) {
[self.view addSubview:redButton];
}];
}
First you create the two buttons and add the green one to the view. (The first view is at index 0). Then you check if the selectedIndex is 1 and animate the Buttons around.

Resources