Objective-c: Multiplying an object - iphone

This is a beginner's question about the fundamentals of objective programming (at least I think so..):
I have an UIView and would like to add several buttons to this UIView programatically. How many buttons there are depends on the user input.
Every button has four characteristics:
Its number (e.g. button number one, two, three etc.)
Its title (e.g. click this, click here, click me etc.)
Its position and size (i.e. a CGRect - size stays the same, only y-position needs to change)
Its colour (e.g. red, green, blue etc.)
Now I thought I can create a button by creating a method, but I am not entirely sure if this is a very sound method. I have the feeling that I should have created an object. Any help of how I should go about this would be very much appreciated. Here is my attempt - which is full of mistakes (for instance, I wasn't sure of how to create button1, button2 etc. -- hence the button[bNumber] thing):
-(void) createIndexButtonWithNumber:(NSString *)bNumber withTitle:(NSString *)bTitle atPosition:(NSInteger *)bPosition withColour:(NSInteger *)bColour {
CGRect buttonFrame = CGRectMake(0,bPosition,25,25);
UIButton* button[bNumber] = [[[UIButton alloc] initWithFrame:buttonFrame] autorelease];
UIButton.text = bTitle;
if (bColour == 1) {UIButton.color = [UIColor colorWithRed:0.751 green:0.742 blue:0.715 alpha:1.000];};
[indexView addSubview:button[bNumber]];
// to do: if button[bNumber] pressed {do something};
}
Then, I would like to 'multiply' the object three times by calling:
for (temp = 0; temp < 2; temp++) {
[self createIndexButtonWithNumber:temp withTitle:[#"Test%i", temp] atPosition:10 withColour:1];}
I'm sure this is all a bit problematic, wrong and clumsy, so I'd be very grateful for any suggestions of how to tackle this.

Here's a simple example that I wrote that creates 5 buttons vertically in a row. The only thing extra in there is the tag, which is used to later reference the button if you need to.
I would suggest reading some more object orientated program examples as well.
float buttonPadding = 20;
float buttonWidth = 80;
float buttonHeight = 40;
for (int k=0;k<5;k++)
{
UIButton* btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btn.tag = 1000 + k;
btn.frame = CGRectMake(0, k*(buttonPadding+buttonHeight), buttonWidth, buttonHeight);
[btn setTitle:[NSString stringWithFormat:#"Button %i", k+1] forState:UIControlStateNormal];
[self.view addSubview:btn];
}

I'd like to reference to UIButton Class Reference
You should create buttons only with buttonWithType: method.
Second, there is no button color. You can set a color for title with setTitleColor:forState: method.
There are just syntax mistakes in your code (UIButton.text, etc). You cant do such a call. UIButton is a class.
Your calling createIndexButtonWithNumber... within for will place buttons in the same place — atPosition input parameter has no change.
NSInteger variable is not a pointer — * is not needed.
...
In the end of struggling we have smth like that:
-(void)createIndexButtonWithNumber:(NSInteger)bNumber //(sorry for that, some troubles with code formatting)
withTitle:(NSString *)bTitle
atPosition:(NSInteger)bPosition
withColour:(NSInteger)bColour {
CGRect buttonFrame = CGRectMake(0,bPosition,25,25);
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = buttonFrame;
button.tag = bNumber;
[button setTitle: [NSString stringWithFormat:#"Button %i", bNumber]
forState:UIControlStateNormal];
if (bColour == 1) {
[button setTitleColor:[UIColor colorWithRed:0.751 green:0.742 blue:0.715 alpha:1.000]
forState:UIControlStateNormal];
};
// you should pass to #selector a description like 'indexAction:' but NOT any calls like '[self indexAction:button]'
[button addTarget:self
action:#selector(indexAction:)
forControlEvents:UIControlEventTouchUpInside];
[indexView addSubview:button];
}
And for call:
for (int temp = 0; temp < 2; temp++) {
[self createIndexButtonWithNumber:temp withTitle:[#"Test%i", temp] atPosition:30 * temp withColour:1];
}
UPDATE: Selector method
-(void)indexAction:(id)sender {
NSLog(#"Button with tag %d is pressed", ((UIButton *)sender).tag);
}

Related

UIScrollView distribute UIButtons Horizontally

I have a UIScrollView that will expand depending on how many buttons it is due to display. It will always round up to the nearest 320 multiple.
So, if the UIScrollView will receive 3 buttons it will be 320px horizontal, if it received 6 then 640px, 9 is 960.
What I need to do is distribute the UIButtons across this UIScrollView evenly.. However I can't seem to figure out how to do this.
My UIButtons measure 80 pixels horizontally.
Could somebody help me get my head round this?
Update/Clarification: I have no problem setting the UIScrollView's width. This has been done. I am looking for info on how to distribute the 'UIButtons' within the 'UIScrollView'..
[theScrollView setContentSize:CGSizeMake(320/640/960, theScrollView.frame.size.height)];
//considering a margin of 10 pts on either edges and a additional 10 pts on each side of button
Add the buttons like below:
for(int i=0; i< buttonCount;i++){
CGRect buttonFrame = CGRectMake( 10 + i*(80+10+10) +10 , buttonY, 80, buttonHeight );
UIButton *button = [UIButton buttonWithType:<type>];
button.frame = buttonFrame;
}
//To set the scrollable area
[scrollView setContentSize:CGSizeMake( 10 + buttonCount*(80+10+10) +10, 0 )];
//left margin + buttonCount x (buttonWidth + leftButtonMargin+rightButtonMargin) + right margin
This should give you an almost evenly distributed buttons according to the number of buttons.
First take all the buttons in an array..lets say buttonsArray
int spacing = 10; // Adjust according to you requirement
int buttonWidth = 100; // Adjust according to you requirement
int buttonHeight = 100; // Adjust according to you requirement
int count = 0;
for (UIButton *thisButton in buttonsArray) {
[thisButton setFrame:CGRectMake(spacing*(count+1)+count*buttonWidth, 20, buttonWidth, buttonHeight)];
count++;
}
[theScrollView setContentSize:CGSizeMake([[buttonsArray lastObject]frame].origin.x+[[buttonsArray lastObject]frame].size.width+spacing, 0)];
Hope this will help you. I have tested it..working fine...
You can use like this:Use MyScrollView.pagingEnabled=YES.
int PageNum=0;
if(TotalButtons%3 >0)
{
pageNum=TotalButtons/3;
pageNum++;
}
else{
PageNum=TotalButtons/3;
}
[MyScrollView setContentSize:CGSizeMake(320*pageNum, MyScrollView.frame.size.height)];
Add Buttons according to the width and spacing you want on the scrollview.
Edit:
int x=56;
int y=60;
for(int i=1;i<= 60;i++)
{
UIButton *button=[UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame=CGRectMake(x, y, 200, 120);
button.tag=i;
// [button setTitle:[NSString stringWithFormat:#"Video-%d",i+1] forState:UIControlStateNormal];
[button setBackgroundImage:[UIImage imageNamed:#"220x200.png"] forState:UIControlStateNormal];
[button addTarget:self action:#selector(ButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[VideoStoreScroll addSubview:button];
if(i%6==0)
{
count++;
x=(count-1)*VideoStoreScroll.frame.size.width+56;
y=50;
}
else
{
if(i%3==0)
{
x=(count-1)*VideoStoreScroll.frame.size.width+56;
y=y+190;
}
else
{
x=x+256;
}
}
}
VideoStoreScroll.contentSize=CGSizeMake(x-56, 480);
VideoStoreScroll.contentOffset=CGPointMake(0, 0);
Here I am using six buttons horizontally on scroll per page.You can work for three following this.

Proper Way for Create Dynamic UIButton in ScrollView?

I am new to iOS Development.
I have a navigation based Application, In my application I created dynamic buttons by using a for loop.
I have two UITextFields (row and column) in FirstViewController. When user enters a value of row and column then click on OK Button the values of row and column passes to anOtherViewController. In anOtherViewController I have to put a logic to create All Buttons based on row and column value.
MyLogical Code:
for (int i = 1 ; i <= rows; i++)
{
for (int j = 1 ; j <= columns ; j++)
{
NSString *btnTitle = [NSString stringWithFormat:#"%d",buttonCount];
self.btnCount = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.btnCount.tag = [btnTitle intValue];
[self.btnCount setTitle: btnTitle forState: UIControlStateNormal];
[self.btnCount addTarget:self action:#selector(btnCountPressed:) forControlEvents:UIControlEventTouchUpInside];
self.btnCount.frame = CGRectMake(162+changedX, 60+changedY, 43, 43);
[self.scrollView addSubview:self.btnCount];
[self.listOfbtnCount addObject:btnTitle];
changedY = changedY + 50;
buttonCount = buttonCount + 1;
}
changedX = changedX + 55;
if (i == rows)
widthScView = changedX;
if (heightScView == 0)
heightScView = changedY;
changedY = 5;
}
My ScreenShot:
It works fine, but my problem is that if I enter values of row and column more then 40 (about) then my app takes more time to create the dynamic button. The issue is only related to the time required to create the button.
Is there any way to create a button faster? and I also need to know is if my code is bad for memory management? please help me on this issues.
For Information : I Have no errors generated, I have issue of only time consuming process of creation of Buttons.
Thank in Advance.
You should use UICollectionView for this.
UICollectionView works a lot like UITableView in that it'll manage the cells that are displayed on screen, including scrolling, and it'll ask its data source for new cells as it needs them. You can also recycle cells, so you'll only need to create about enough to display, plus a few extra. This should really improve performance, especially when scrolling.
Apple has some sample code using UICollectionView here, and watching Introducing Collection Views in the 2012 WWDC Videos will get you off to a good start.
my problem is that If i enter values of row and column more then 40
Forty rows of forty columns would give you 1600 buttons, most of which don't need to exist most of the time. By managing which cells are needed on screen for you, UICollectionView will reduce that to around eighty (judging by your screen shot). You should see much, much better performance this way.
UICollectionView will also simplify positioning the buttons once you've configured the collection view (which you can do in code or in Interface Builder), you won't need any code of your own for calculating the positions of the buttons.
just implement you logic here with your requirement..
int imageIndex = 0;
int yOffset = 4;//set offset which you want...
while (imageIndex < rows)
{
int yPos = 7 + yOffset * 30; // set distance in height between two raws
for(int i = 0; i < columns; ++i)
{
CGRect rect = CGRectMake((0 + i * 80), yPos, 80, 31);**// here set frame of every button with different x and y postion// here width of button is 80 and height is 31**
if (imageIndex < rows) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = rect;
button.tag = imageIndex;
[button addTarget:self
action:#selector(btnTemp_Clicked:)
forControlEvents:UIControlEventTouchDown];
[button setTitle:[NSString stringWithFormat:#"%d",imageIndex] forState:UIControlStateNormal];
[button.titleLabel setFont:[UIFont fontWithName:#"Helvetica-Bold" size:12]];
// [button.titleLabel setTextColor:[UIColor blueColor]];
[button setTitleColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"circle03.jpg"]] forState:UIControlStateNormal ];
[button setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted ];
[button setNeedsDisplay];
[yourScrollView addSubview:button];
}
++imageIndex;
}
++yOffset;
}
See the screen which i got output..
Try this method
-(void)ScrollViewSetting {
scrollview.scrollEnabled=YES;
scrollview.userInteractionEnabled=YES;
TotalStyleX=25;
TotalStyleY=18;
int count=0;
int px=0;
int py=0;
for (int i=1; i<=TotalStyleX; i++) {
px=0;
for (int j=1; j<=TotalStyleY; j++) {
count++;
UIButton *btn1=[[UIButton alloc] init];
btn1.tag = count;
btn1.frame=CGRectMake(px+10, py+10, 300, 380); //you can set your height and width your x and y position
[scrollview addSubview:btn1];
px=px+320;
}
py=py+400;
}
[scrollview setContentSize:CGSizeMake(px, py)];
}

Identifying the Position of a UIButton

I've created 5 buttons dynamically, as follows:
float xpos=0,ypos=0;
for (int i = 0; i < 5; i++)
{
but = [UIButton buttonWithType:UIButtonTypeCustom];
[but setTag:i];
[but setImage:[UIImage imageNamed:#"btfrnt.png"] forState:UIControlStateNormal];
[but setFrame:CGRectMake(xpos, ypos, 40, 40)];
xpos+=80;
[but addTarget:self action:#selector(checkboxButton:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:but];
}
In Click event of any of the button, I want to find the position of the button which I have clicked....
-(void)checkboxButton:(UIButton*)sender
{
NSLog(#"%d",xpos);
}
But, it displays only the xpos of the last button...Is there any way to identify it by means of its tag?
try this :
-(void)checkboxButton:(UIButton*)sender
{
NSLog(#"%f %f",sender.frame.origin.x,sender.frame.origin.y);
}
I take it xPos is a global variable - of course it contains the value of the last button, that's the value it was set to last.
For the button position you don't need to store anything in a global variable - just get it from the sender object that is delivered to you in the click event handler - it is a UIButton pointer, and the UIButton object has a frame structure with origin.x and origin.y, as well as a size.width and size.height, by the way.
You may try this...
-(void)checkboxButton:(UIButton*)sender {
UIButton *button = (UIButton *)sender;
CGRect rect = button.frame; //You may use sender.frame directly
NSLog(#"X: %d", rect.origin.x);
NSLog(#"Y: %d", rect.origin.y);
NSLog(#"Width: %f", rect.size.width);
NSLog(#"Height: %f", rect.size.height);
}

Dynamic UIButtons with vertical spacing on a UIScrollView

I need to space UIButtons out on a UIScrollView. The code I have works, however depending on the amount of dataItems I have, the spacing is not even.
Snippet in Question
CGRectMake(10, ((120 / (count + 1)) * (i + 1) * 3) ,300,50)
Specifically
((120 / (count + 1)) * (i + 1) * 3)
Working code
int count = [dataItems count]; /* not a specific value, can grow */
for (int i = 0; i < count; i++) {
UIButton* aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[aButton setTag:i];
[aButton setFrame: CGRectMake(10,((120 / (count + 1)) * (i + 1) * 3) ,300,50) ];
[aButton setTitle:[[dataItems objectAtIndex:i] objectForKey:#"Feed"] forState:UIControlStateNormal];
[aButton addTarget:self action:#selector(viewCategories:) forControlEvents:UIControlEventTouchUpInside];
[scroller addSubview:aButton];
}
Screenshot
The example on the right should look like the example on the left as far as spacing goes. The UIButtons are sitting on a UIScrollView, so the UIScrollView's contentSize should also grow if there are more dataItems so the buttons can scroll offscreen if there are say, 30+ dataItems.
sounds like you need a set size and padding...
int count = [dataItems count];
CGFloat staticX = 10; // Static X for all buttons.
CGFloat staticWidth = 300; // Static Width for all Buttons.
CGFloat staticHeight = 50; // Static Height for all buttons.
CGFloat staticPadding = 10; // Padding to add between each button.
for (int i = 0; i < count; i++) {
UIButton* aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[aButton setTag:i];
//Calculate with the Static values.
//I added one set of padding for the top. then multiplied padding plus height for the count.
// 10 + 0 for the first
// 10 + 60 for the second.
// 10 + 120 for the third. and so on.
[aButton setFrame: CGRectMake(10,(staticPadding + (i * (staticHeight + staticPadding)) ,staticWidth,staticHeight) ];
[aButton setTitle:[[dataItems objectAtIndex:i] objectForKey:#"Feed"] forState:UIControlStateNormal];
[aButton addTarget:self action:#selector(viewCategories:) forControlEvents:UIControlEventTouchUpInside];
[scroller addSubview:aButton];
}
however if you are trying to get buttons to do this sort of behavior. I am inclined to agree with the rest.. You can make a custom cell with a button in it.
Then you can load that button cell when the table asks for a button.
And you have the table tie to your [dataItems count] for the total of the items.
then your only calculation is to set the cell height when you initially set the dataItems count. making sure not to make them too short. and the table will handle the rest.
I agree with Gurpartap, but if your dead set on this, I'd do it a bit differently. Even if you understand the math in that setFrame statement now, will you or someone else understand it later. I sure don't looking at it quick. Why not do something like:
CGRect frm = CGRectMake(10,10,300,50);
for (int i = 0; i < count; i++) {
UIButton* aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[aButton setFrame: frm];
frm.origin.y = frm.origin.y + aButton.frame.size.height + 10;
etc, etc
You should really use a UITableView instead. It does the scroll view, cell laying out, etc. all by itself. You just specify the cell contents.

Dynamic Button Layout without hard coding positions

I would like to implement a view (it will actually be going into the footer of a UITableView) that implements 1-3 buttons. I would like the layout of these buttons (and the size of the buttons themselves) to change depending on which ones are showing. An example of almost the exact behavior I would want is at the bottom of the Info screen in the Contacts application when you are looking at a specific contact ("Add to Favorites" disappears when it is clicked, and the other buttons expand to take up the available space in a nice animation).
As I'm running through the different layout scenarios, I'm hard coding all these values and I just think... "this is NOT the way I'm supposed to be doing this."
It even APPEARS that Interface Builder has some features that may do this for me in the ruler tab, but I'll be darned if I can figure out how they work (if they work) on the phone.
Does anyone have any suggestions, or a tutorial online that I could look at to point me in the right direction?
Thanks much.
You could take a look at
Stanford cs193p classes
I think there is a demo in one of the lessons/example where they programaticaly set the autoresize of the buttons and some other where they animate the view.
you can also make the view set dynamically the width of each of its subview to (ownWidth/numberofSubView),the same for the positon of each elements.
[edit] like that ? it's not "dynamic" yet, but you've got the idea
you can increase/decrease numberOfbuttons when "adding/removing" a button then reset the new frame of all the subviews
- (void)loadView
{
UIView *view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
view.backgroundColor = [UIColor lightGrayColor];
view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
int numberOfbuttons = 2;
CGFloat buttonsLegth = (-20+view.bounds.size.width)/numberOfbuttons-20;
for(int i=0;i<numberOfbuttons;i++){
CGRect buttonFrame = CGRectMake(0, 0, buttonsLegth, 37);
buttonFrame.origin.x = (buttonFrame.size.width+20)*i + 20.0;
buttonFrame.origin.y = 20.0;
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; // Autoreleased
button.frame = buttonFrame;
[button setTitle:#"Done" forState:UIControlStateNormal];
[view addSubview:button];
}
self.view = view;
[view release];
}
hi remove all buttons in view and add again using this method...
you have to pass number of buttons and a UIView in which you want to add these buttons
-(void)addButtons:(int)numberOfButtons ToView:(UIView *)containerView;
{
CGRect containerRect = containerView.frame;
CGFloat padding = 5.0;
CGFloat width = (containerRect.size.width - (padding*numberOfButtons+1))/numberOfButtons;
for (int i = 1; i<=numberOfButtons; i++)
{
UIButton * btn = [[[UIButton alloc] initWithFrame:CGRectMake(i*padding+width, 0, width, containerRect.size.height)]autorelease];
//set Button Properties like Target,backColor,Title,,,,etc MUST SET TAG TO ACCESS THEM IN CLICK METHOD IF YOU ARE USING SAME SELECTOR FOR ALL BUTTONS.
[containerView addSubview:btn];
}
}
Try this and have fun......