Dyamic frame calculation for UIImages in UITableViewCell - ios

I am putting few icons on UITableViewCell. The number of icons can vary from 1 to 6. Icons should not have fixed X position and instead they should be dynamically placed considering the cell space. So if there are 3 icons they should look placed centric to the cell. Also, the icon spacing should also vary. For instance when it is 6 icons all of them will be placed with less margins in between and when there are 3 then margin will be more and so will be the X position.
Please suggest some quick way to calculate this frame. I am running the app both on iOS 6 and iOS 7.
This is what I have tried by far but this does not seems to work well with icon count variation. Also, in between space is not dynamic with this.
int maxIconTypes = 6;
CGFloat innerPadding = ([self isIOS7]) ? 15.0f : 9.0f;
CGRect adjustedBoundsIOS6 = [self bounds];
CGFloat adjustedWidth = ([self isIOS7]) ? self.bounds.size.width : adjustedBoundsIOS6.size.width;
CGFloat xOrigin = innerPadding;
CGFloat iconViewSize = 25.0f;
CGFloat ySpacer = (self.bounds.size.height - iconSize) / 2;
CGFloat xSpacer = ((adjustedWidth - (innerPadding * 2)) - (maxRequestTypes * iconViewSize)) / (maxIconTypes - 1);
for (NSString *icon in iconList) {
UIImageView *anIconView = [[UIImageView alloc] initWithImage:[UIImage icon]];
if (anIconView.image) {
anIconView.frame = CGRectMake(xOrigin + originPadding, ySpacer, anIconView.image.size.width, anIconView.image.size.height);
[self.contentView addSubview:anIconView];
xOrigin += anIconView.frame.size.width + xSpacer;
}
}

However many items you have, the number of spaces is the same if you want equal spacing with half spacing at the start and end:
half width full width half
half width full width full width half
So, you just need to know the full width available and the combined width of the items. A simple multiply (to get the combined width of the items) and subtract (from the full width available) gives you the remaining width for the 'spacers'. Divide by the number of items to get the xSpacer, set the initial xOrigin to xSpacer * 0.5

Here is an example of what Wain is explaining:
//Im doing this in a UIView rather than in a UITableViewCell but idea is the same
int cellWidth = CGRectGetWidth(self.view.bounds);
//num of icons
int iconCount = 6;
//size of icon
int iconSize = 25;
//The max padding we can have
float maxPadding = (cellWidth - (iconSize * iconCount)) / iconCount;
//Our offset
float xOrigin = maxPadding / 2;
//Loooop
for (int i = 0; i < iconCount; i++) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(xOrigin, self.view.center.y, iconSize, iconSize)];
xOrigin += (iconSize + maxPadding);
label.backgroundColor = [UIColor blueColor];
[self.view addSubview:label];
}

Related

How to Resize button animations programmatically

I am new to Objective-C. I created an animation that move 3 buttons upwards. These buttons contain images. However, when this button animation occurs it resizes the button images and makes them HUGE. I tried to correct the code below to resize the button images, but I still get HUGE buttons. Can someone please help me? It should be Width:78 Height:76. I tried replacing width and height but it still doesn't work. Note: Just correct the code, I don't need a completely different answer.
-(IBAction)Search:(id)sender {
CGFloat screenWidth = self.view.bounds.size.width;
CGFloat screenHeight = self.view.bounds.size.height;
CGFloat normalizedX = (124 / 320); // You calculate these 'normalized' numbers, possibly from a designer's spec.
// it's the percent the amount should be over, as number from 0-1.
// This number is based on screen width of 320 having x 124 pt.
CGFloat startingX = normalizedX * screenWidth;
CGFloat startingY = (475 / 200) * screenHeight;
CGFloat width = (42 / 40) * screenWidth;
CGFloat height = (30 / 30) * screenHeight;
CGRect startingRect = CGRectMake(startingX, startingY, width, height);
self.button.frame = startingRect;
self.buttonTwo.frame = startingRect;
self.buttonThree.frame = startingRect;
// animate
[UIView animateWithDuration:0.75 animations:^{
CGFloat firstX = (13 / 770) * screenWidth;
CGFloat lowerY = (403 / 370) * screenHeight;
self.button.frame = CGRectMake(firstX, lowerY, width, height);
CGFloat secondX = (124 / 424) * screenWidth;
CGFloat upperY = (347 / 447) * screenHeight;
self.buttonTwo.frame = CGRectMake(secondX, upperY, width, height);
CGFloat thirdX = (232 / 680) * screenWidth;
self.buttonThree.frame = CGRectMake(thirdX, lowerY, width, height);
}];
}
Looks to me like your height and width math is wrong.
(42/40) * screenWidth will simplify to (1) * screenWidth, or the full width of the screen (The expression 42/40 will be done using integer math, resulting in 1.0. If it used floating point, you'd get 1.05 * screenWidth, which would make the images even bigger.)
You have a similar problem with your height calculation. You are setting the button to be the full height of the screen, and slightly wider.

IOS Autolayout- Multiple images in one horizontal line of subview programmatically

I created a tableview header and added a subview to it.
I am trying to center multiple avatar images(fixed width and height) in a single line of this ui subview.
Max number of images=max(predefined).
Number of images that I would like to fit is n.
When 5 is max number of image,
n=1:
[......................image 1........................... ]
n=2:
[.................image 1.....image2...............]
n=3
[.........image 1.....image2....image3.........]
n=4
[...image 1....image2....image3......image4...]
n=5
[.imag 1....imag2....imag3....imag4....imag5.]
That is the placement should be centred with equal spacings.
How can I achieve this programatically?
I can do this by story board, by placing max images in a row, keeping equal leading and trailing spaces,
and when n=1, i will hide 1,2,4 and 5
while when n=2, i will hide 1,2,5
If you can target a Deployment Target of iOS 9 and up, use UIStackView. It's designed to handle this scenario.
If you can't do that yet, the following algorithm will work. It doesn't use constraints.
CGFloat tableWidth = ...; // This may change if you allow rotation.
CGFloat spacer = ...; // Amount of space between images goes here.
CGFloat imageWidth = images.count > 0 ? [[images[0] size] width] : 0.0;
CGFloat imageHeight = images.count > 0 ? [[images[0] size] height] : 0.0;
CGFloat totalWidth = images.count * imageWidth + (images.count - 1) * spacer;
CGFloat leftEdge = (tableWidth / 2.0) - (totalWidth / 2.0);
for (int i = 0; i < images.count; i++) {
UIImageView *iv = ...; // Create and configure with image[i].
CGRect frame = CGMakeRect(0, 0, imageWidth, imageHeight);
frame.origin.x = leftEdge + (i * imageWidth + i * spacer);
iv.frame = frame;
}

iOS8 UIView width 320

There is the question: I set a custom view named ZHLockView. I put it in the storyboard and I set the constraints. But I can't get the correct width in - (id)initWithCoder:(NSCoder *)aDecoder, it is always 320, what should I do to get the correct width?
Last I know in the - (void)layoutSubviews, I can get the right width, but it will going twice. Is there a better idea?
See, you're getting width 320 because your view is of that size on storyboard.
If the width of the view is equal to superview, which is indeed again equal to width of device, you can use following code to get width of view at anytime and dont need to worry about where to write.
Swift :-
CGFloat width = CGRectGetWidth(UIScreen.mainScreen.bounds);
CGFloat height = CGRectGetHeight(UIScreen.mainScreen.bounds);
Objective-C :-
CGFloat width = CGRectGetWidth([[UIScreen mainScreen] bounds]);
CGFloat height = CGRectGetHeight([[UIScreen mainScreen] bounds]);
Hope you understood and it helps you.. :)
the code is here
objc
#define KScreenWidth [UIScreen mainScreen].bounds.size.width
CGFloat height = 0;
CGFloat margin = (KScreenWidth - columnCount * btnW) / (columnCount + 1);
for (int i = 0; i < btnCount; i++) {
int row = i / columnCount;
int column = i % columnCount;
CGFloat btnX = margin + column * (btnW + margin);
CGFloat btnY = row * (btnW + margin);
height = btnH + btnY;
ZHButtonView *button = [[ZHButtonView alloc] initWithFrame:CGRectMake(btnX, btnY, btnW, btnH)];
button.userInteractionEnabled = NO;
button.currentIndex = i;
[button setBackgroundImage:[UIImage imageNamed:#"gesture_node_normal"] forState:UIControlStateNormal];
[button setBackgroundImage:[UIImage imageNamed:#"gesture_node_highlighted"] forState:UIControlStateSelected];
[self addSubview:button];
}
The view will be load with the value in the xib at the first start, next when the autolayout engine makes the first pass, it will be set to a new value according to the constraints set.
Why would you need to know the size? Autolayout is made to do not care about it.
-layoutSubviews, -viewWillLayout, -viewDidLayout are called when the layout engine needs a update, that could means Different times before displaying your view.

Labels for UISlider values and centering text

I have a slider and would like to display text labels for some of the values on the slider.
I would like numbers to be centered on top of values. Labels are of fixed width - predefined. So I think all I need to do is calculate space width in between labels and keep incrementing x position when positioning each label. The problem that I am seeing though is there more labels there are the more each label slides to the right. I know this because the value set is always in the center of the slider in my test cases. Text is centered within label. Please see pictures on the first picture labels are almost correctly centered. The way to see what I mean is looking at the last label in both pictures. I almost think that it is the border of the label perhaps but I do not set the border either. I am not sure what I could be doing wrong in terms of math, but must be missing something. Also, it seems like the fir label maybe more than 1/2 label width of to the left of slider start position.
EDIT This is because the frame X starting position DOES not match the x starting position of the slider. See pic. Now I just need to figure out how to calculate the offset. The red line is drawn at slider.frame.origin.x. You can see that slider is off by a few points. The ball should be in the center at 3.125 - 25 .. but it is slightly of.
The way space between labels is calculated:
float xPosition = sliderFrame.origin.x;
//Slider adjusted width
float sliderWidth = sliderFrame.size.width - xPosition;
float spacedApart = (sliderWidth - (LABEL_WIDTH * numberofticks)) / (float) (numberofticks);
Each label is displayed at:
CGRect mpkLabelFrame = CGRectMake(xPosition - LABEL_WIDTH/2, (yPosition - spaceBetweenLabelsAndSlider), LABEL_WIDTH, LABEL_HEIGHT)+3; //need to increase by 3 to make it work better
//display label do other things
xPosition += (LABEL_WIDTH + spacedApart);
You don't need to take into account the sliders x coordinate to figure out the spacing. In fact, since they are distributed equally you don't need the label size as well.
CGFloat labelSpacing = sliderFrame.size.width/(numberOfTicks-1);
xPosition = sliderFrame.origin.x;
Set the label's frames:
CGRect mpkLabelFrame = CGRectMake(xPosition - LABEL_WIDTH/2, (yPosition - spaceBetweenLabelsAndSlider), LABEL_WIDTH, LABEL_HEIGHT);
xPosition += labelSpacing;
EDIT: code for testing the approach in an viewController:
- (void)viewDidLoad{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(40, 100, 240, 10)];
[self.view addSubview:slider];
int numberOfTicks = 7;
CGFloat labelSpacing = slider.frame.size.width/(numberOfTicks-1);
CGFloat xPosition = slider.frame.origin.x;
CGFloat labelWidth = 10;
CGFloat yPosition = CGRectGetMinY(slider.frame)-20;
for (int i=0;i<numberOfTicks;i++){
CGRect labelFrame = CGRectMake(xPosition - labelWidth/2, (yPosition), labelWidth, 20);
UILabel *label = [[UILabel alloc] initWithFrame:labelFrame];
label.backgroundColor = [UIColor redColor];
label.adjustsFontSizeToFitWidth = YES;
label.text = [NSString stringWithFormat:#"%i",i];
[self.view addSubview:label];
xPosition += labelSpacing;
}
}

Adding multiple items to UIScrollView, but can't scroll?

I'm writing a UI for iOS and I need to create a scrolling view of note-type widgets. I'm experimenting with creating a scrollview and adding some UIView objects to it, but for some reason, I can't scroll, am I doing something wrong? Here's what I'm doing:
[_testScrollView setBackgroundColor:[UIColor purpleColor]];
NSUInteger size = 100;
float height = _testScrollView.frame.size.height/10;
float width = _testScrollView.frame.size.width;
float currTop = 0;
CGSize fooSize = CGSizeMake(_testScrollView.frame.size.width, _testScrollView.frame.size.height);
[_testScrollView setContentSize:fooSize];
for (NSUInteger i = 0; i < size; i++)
{
double red = ((double)arc4random() / ARC4RANDOM_MAX);
double green = ((double)arc4random() / ARC4RANDOM_MAX);
double blue = ((double)arc4random() / ARC4RANDOM_MAX);
CGRect currFrame = CGRectMake(0, currTop, width, height);
UIView* testView = [[UIView alloc] initWithFrame:currFrame];
[testView setBackgroundColor:[UIColor colorWithRed:red green:green blue:blue alpha:1.0]];
[_testScrollView addSubview:testView];
currTop += height;
}
I would've expected to scroll through the scrollview and be able to go through all of the 100 UIViews added. What am I missing?
you need to set the content size for your scroll view to the height of all the uiviews. use
setContentSize:cgSizeMake(_testScrollView.frame.size.width,size*height)
after the for loop
Just print(Log screen) your height of contentsize in scrollview.there you can see the scrollview height...you need to add heights of all subviews to get height of contentsize for scrollview...

Resources