How do I keep images in programmatrically-created UIButtons from being scaled? - uibutton

I'm creating a series of UIButtons from an NSArray of UIImages with the following:
#define BUTTONWIDTH 66
for (int i = 0; i < [imgArray count]; i++){
toolTile = [UIButton buttonWithType:UIButtonTypeRoundedRect];
buttonRect = CGRectMake((BUTTONWIDTH*i)+i, 0, BUTTONWIDTH, BUTTONWIDTH);
toolTile.frame = buttonRect;
toolTile.tag = i;
[toolTile addTarget:self action:#selector(toolTileClick:) forControlEvents:UIControlEventTouchUpInside];
toolTile.imageView.contentMode = UIViewContentModeCenter;
[toolTile setBackgroundImage:[imgArray objectAtIndex:i] forState:UIControlStateNormal];
[[self view] addSubview:toolTile];
}
Unfortunately, the images are being scaled (blown up) to fill the 66x66 tile. I want them to be centered at 1:1 in the tile- supposedly toolTile.imageView.contentMode = UIViewContentModeCenter should do that. I've tried moving this line before,after the setBackgroundImage: -no luck. What am I missing?

The culprit was using setBackgroundImage:forState:[UIControlState] instead of setImge:forState:[UIControlState].
SetBackgroundImage apparently always scales, SetImage: honors the imageView.contentMode.

Related

Objective-C: how can i change the alpha of uiimages created by a for loop

I used a for loop to create several images and sliders on a scroller, how can I change the alpha of the images by changing the value of sliders? here is my code
I've tried to declare the uiimages outside the function loadImages, but I dont think this is a good idea.
I know how to do it without using for loop, but if I want to use for loop, how can I let the function know which uiimage it should operate on. Cause all the uiimages created in the for loop are not public objects I think.
-(void)loadImages
{
for (int i = 0; i < 10; i++){
//show drawing position in the output
NSLog(#"x:%i, y:%i",xInc, yInc);
//text label on the slider button
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(78 + xInc, 55+yInc, 200, 20)];
Person *thisPerson = [arrayOfPerson objectAtIndex:i];
NSString *namePerson = thisPerson.name;
[label setText:[NSString stringWithFormat:#"%#",namePerson]];
[label setTextColor:[UIColor whiteColor]];
[label setBackgroundColor:[UIColor clearColor]];
label.textAlignment = NSTextAlignmentCenter;
//front office background image of slider
NSString *frontimageName = [NSString stringWithFormat:#"frontofficeBUTTON.png"];
UIImageView *frontimgView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:frontimageName]];
frontimgView.frame = CGRectMake(xInc, 10 + yInc, 332, 70);
[frontimgView setTag:i];
//back office background image of slider
NSString *backimageName = [NSString stringWithFormat:#"backofficeBUTTON.png"];
UIImageView *backimgView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:backimageName]];
backimgView.frame = CGRectMake(xInc, 10 + yInc, 332, 70);
[backimgView setTag:i];
//slider
UISlider *slider=[[UISlider alloc] initWithFrame:CGRectMake(5+ xInc, 25+yInc, 322, 40)];
//give a id tag to the slider
[slider setTag:i];
//set a action to the slider
[slider addTarget:self action:#selector(UnlocklinkSlider:) forControlEvents:UIControlEventTouchUpInside];
//define the appearance of the slider
UIImage *stetchLeftTrack= [[UIImage imageNamed:#"Nothing.png"]
stretchableImageWithLeftCapWidth:30.0 topCapHeight:0.0];
UIImage *stetchRightTrack= [[UIImage imageNamed:#"Nothing.png"]
stretchableImageWithLeftCapWidth:30.0 topCapHeight:0.0];
[slider setThumbImage: [UIImage imageNamed:#"rightBUTTON.png"] forState:UIControlStateNormal];
[slider setMinimumTrackImage:stetchLeftTrack forState:UIControlStateNormal];
[slider setMaximumTrackImage:stetchRightTrack forState:UIControlStateNormal];
yInc = yInc + 80;
[_scrollView addSubview:backimgView];
[_scrollView addSubview:frontimgView];
[_scrollView addSubview:label];
[_scrollView addSubview:slider];
}
[_scrollView setContentSize:CGSizeMake(320, scrollLength)];
}
- (void)UnlocklinkSlider:(UISlider*)slider
{...}
Your slider should have a target and action added for UIControlEventValueChanged so that the image updates in sync (though it will work on touch up too). When you get the callback, use the slider tag to find the image view with the matching tag. Then set the image view alpha to slider.value.
To find the image view, you could loop over the subviews of the scroll view and check the tags of the subviews. You will want to change the tags from your current code as you have lots of things with the same tags.
A better option is to store references to the image views in an array property on your controller, then use the slider tag as the index in that array.

Scroll to center of UIScrollview clicked UIButton added programmatically EDITED

I have a scrollview of scrollview of UIbuttons build like this:
-(void) loadCompeticionSlide{
float x=0;
for (int i = 0; i < [categoriasArray count]; i++) {
NSDictionary *categoria = [categoriasArray objectAtIndex:i];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
NSString *titleString = [categoria valueForKey:#"competicion"]; // get button title
btn.titleLabel.font = [UIFont boldSystemFontOfSize:11.0];
CGSize fontSize = [titleString sizeWithFont:[UIFont systemFontOfSize:11.0]];
CGRect currentFrame = btn.frame;
CGRect buttonFrame = CGRectMake(x, currentFrame.origin.y, fontSize.width + 22.0, fontSize.height + 12.0);
[btn setFrame:buttonFrame];
x = x + fontSize.width + 35.0;
[btn setTitle:titleString forState: UIControlStateNormal];
int idc = [[categoria valueForKey:#"idc"]intValue];
[btn addTarget:self action:#selector(cambiarCompeticion:) forControlEvents:UIControlEventTouchUpInside];
[btn setTag:idc];
[self.competicionSlide addSubview:btn];
}
//[competicionSlide setBackgroundColor:[UIColor whiteColor]];
competicionSlide.contentSize = CGSizeMake(350,35);
competicionSlide.layer.cornerRadius = 11;
competicionSlide.layer.masksToBounds = YES;
}
Then, in the added selector cambiarCompeticion:, I got the button clicked, here I need to use scrollRectToVisible: to get the clicked UIButton scrolled to the center of the UIScrollview that contains it, but I don't know how to do it.
This is the selector method triggered by button selection where I understand scrollRectToVisible: has to be called:
-(void)cambiarCompeticion:(UIButton*)boton{
int idCompeticion;
idCompeticion = boton.tag;
switch (idCompeticion) {
case 1:
[self tablaLigaRegular];
break;
case 5:
[self tablaCoparey];
break;
case 10:
[self tablaPlayOff];
break;
}
}
here are the details in images, in first image blue arrow indicates previous state of the partial hidden left button and the move to do to the middle of scroll view once it is clicked:
many thanks
Your boton parameter (from the cambiarCompeticion: selector) has everything you need. Just call like this (assuming that "competicionSlide" is an UIScrollView) :
[self.competicionSlide scrollRectToVisible:boton.frame];
Good luck !

UIScrollView and Autoration issues

I'm trying to understand an issue I'm having with an iOS Universal app. I have a UIScrollView which I want the page of to take up the full dimension of the device and adjust itself when rotating.
In my viewDidLoad method, I'm testing with:
NSArray *colors = [NSArray arrayWithObjects:[UIColor orangeColor], [UIColor cyanColor], [UIColor redColor], [UIColor greenColor], [UIColor blueColor], nil];
for (int i = 0; i < colors.count; i++) {
CGRect frame;
frame.origin.x = _scrollView.bounds.size.width * i;
frame.origin.y = 0;
frame.size = _scrollView.bounds.size;
UIView *subview = [[UIView alloc] initWithFrame:frame];
subview.backgroundColor = [colors objectAtIndex:i];
[_scrollView addSubview:subview];
}
_scrollView.contentSize = CGSizeMake(_scrollView.bounds.size.width * colors.count, _scrollView.bounds.size.height);
then I added in the didRotateFromInterfaceOrientation method:
_scrollView.contentSize = CGSizeMake(_scrollView.bounds.size.width * colors.count, _scrollView.bounds.size.height);
for (int i= 0; i< colors.count; i++)
{
CGRect frame;
frame.origin.x = _scrollView.bounds.size.width * i;
frame.origin.y = 0;
frame.size = _scrollView.bounds.size;
UIView *subview= [[_scrollView subviews] objectAtIndex:i];
subview.frame= frame;
}
This seems to work, but I seem to have some clipping on the main view while the device is rotating.
Here's a screenshot of what happens when rotating:
I thought this happened because I changed the size after it was rotated, but I tried to handle it in the willRotateToInterfaceOrientation method, but it gave the wrong result...
Am I handling this incorrectly?
What would be the correct approach?
TIA!
S.
Am I handling this incorrectly?
You should put the code that changes the bounds in willRotateToInterfaceOrientation, but do so in an animation block (using [UIView animateWithDuration:0.4 animations:...])_so that the transition will be smooth rather than immediate.
An extra note is that inside willRotateToInterfaceOrientation, the parent view will not yet have been resized, so you cannot depend on it's bounds to calculate the final position of the views, rather you must do so manually.

Showing buttons on the screen using a for-loop with Objective-C

I have a database full of words, and each word contains information. My job is to show the words on screen using buttons, and without using interface builder. I figured I could do this with a for loop, like this:
for (int i=0; i <=20; i++) {
UIButton *word= [UIButton buttonWithType:UIButtonTypeRoundedRect];
[word setTitle:#"Test" forState:UIControlStateNormal];
[word setFrame:CGRectMake(0, 0, 100, 40)];
[self.view addSubview:word];
}
this is all done in the viewDidLoad section. But when I run the program, only one button is showed, so how can I make it show all the 20 buttons?
Thanks on forehand,
Nicholas
It may be useful.
for (int i=0; i <=20; i++)
{
UIButton *word= [UIButton buttonWithType:UIButtonTypeRoundedRect];
[word setTitle:#"Test" forState:UIControlStateNormal];
[word setFrame:CGRectMake(0, (i+1)*100, 100, 40)];
[self.view addSubview:word];
}
You should dynamically change the frame of the buttons added. The following code places the views horizontally.
float _width = 100;
float _x = i * _width;
[word setFrame:CGRectMake(_x, 100, _width, 40)];
Every time Button Frame is Similar .. so only 1 button is showe ..
Try like this
[word setFrame:CGRectMake(0+i*110, 0+i*50, 100, 40)];
or set frame as per your need
What you are doing here is adding all the 100 btns on the same frame. Instead of this, if you want to show all the 100 btns on the screen, you'll have to use two for loops.
for example, if you wanna show four btns in a single row then you should use,
for(i = 0 ; i < 20 (i.e. no of elements in a single column) ; i++ )
{
for(j = 0; j < 4 (i.e. no of elements in a single row) ; j++)
{
UIButton *word= [UIButton buttonWithType:UIButtonTypeRoundedRect];
[word setTitle:#"Test" forState:UIControlStateNormal];
[word setFrame:CGRectMake(j*40, i*100, 100, 40)];
[self.view addSubview:word];
}
}

Multiple Lines in UIButton

Hi I have problem for set multiple lines to my Button which is declared like that:
button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.titleLabel.font = [UIFont systemFontOfSize: 12];
button.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
button.titleLabel.numberOfLines = 0;
button.titleLabel.shadowOffset = CGSizeMake (1.0, 0.0);
[button addTarget:self
action:#selector(myButtonClick)
forControlEvents:UIControlEventTouchDown];
button.frame = CGRectMake(0.0, 100.0, 317.0, 100.0);
[button setTitle:string forState:UIControlStateNormal];
button.titleLabel.font = [UIFont systemFontOfSize: 12];
button.titleLabel.text = #"ahoj";
NSMutableString *ObratString = [[NSMutableString alloc] initWithString:button.titleLabel.text];
[ObratString appendString:#"\n"];
[ObratString appendString:#"caw"];
[ObratString appendString:#"\n"];
[ObratString appendString:#"helllo"];
button.titleLabel.text = ObratString;
[ObratString release];
[self.view addSubview:button];
But in the end I just see the first line.
Is there any way to make it work?
The UIButton displays it's text with a contained UILabel. The default for the contained label is to display one line of text only. This label is accessible through the titleLabel property, and anything you can do to a normal label can be done to it.
For example making it multi-lines broken by words:
ObjC:
myButton.titleLabel.numberOfLines = 0; // Dynamic number of lines
myButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
Swift:
myButton.titleLabel?.numberOfLines = 0; // Dynamic number of lines
myButton.titleLabel?.lineBreakMode = .byWordWrapping;
Swift version for the checked response:
myButton.titleLabel?.numberOfLines = 0
myButton.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping