Center row of Buttons in UIScrollView - objective-c

I am adding buttons in a UIScrollView dynamically, but some views only have two buttons and some have 10. I want to center the buttons in the scroll view so It doesn't look like I built them from the left to right. I've tried several tricks from SO and nothing seems to work. setting the content offset was my first approach, but doesn't have the effect I want.
Here is the code I am using:
- (void)addButton:(UIButton *)button {
CGFloat contentWidth = 0.0f;
CGRect buttonFrame = button.frame;
if ([_scrollView.subviews count] == 0) {
buttonFrame.origin.x = self.contentIndicatorWidth + kButtonSeperator;
contentWidth = self.contentIndicatorWidth + buttonFrame.size.width + self.contentIndicatorWidth;
} else {
contentWidth = _scrollView.contentSize.width;
UIButton *lastButton = [_scrollView.subviews lastObject];
buttonFrame.origin.x = lastButton.frame.origin.x + lastButton.frame.size.width + kButtonSeperator;
contentWidth += buttonFrame.size.width + kButtonSeperator;
}
button.frame = buttonFrame;
[_scrollView addSubview:button];
_scrollView.contentSize = CGSizeMake(contentWidth *kContentMultiplicityFactor, _scrollView.frame.size.height);
[_buttons setValue:button forKey:button.titleLabel.text];
totalWidth = contentWidth;
// [_scrollView scrollRectToVisible:[self getButtonAtIndex:0].frame animated:YES];
}

After you add the buttons call this method:
- (void)centerButtons:(NSArray*)buttons {
CGSize scrollViewSize = _scrollView.bounds.size;
// Measure the total width taken by the buttons
CGFloat width = 0;
for (UIButton* b in buttons)
width += b.bounds.size.width + kButtonSeparator;
if (width > kButtonSeparator)
width -= kButtonSeparator;
// If the buttons width is shorter than the visible bounds, adjust origin
CGFloat origin = 0;
if (width < scrollViewSize.width)
origin = (scrollViewSize.width - width) / 2.f;
// Place buttons
CGFloat x = origin;
CGFloat y = 0;
for (UIButton* b in buttons) {
b.center = CGPointMake(x + b.bounds.size.width/2.f, y + b.bounds.size.height/2.f);
x += b.bounds.size.width + kButtonSeparator;
}
_scrollView.contentSize = CGSizeMake(MAX(scrollViewSize.width, width), scrollViewSize.height);
}

In the end, this isn't a very hard problem. I guess you add these buttons on the fly.
You have a scrollview called ScrollView and you have already put in content size.
So you have 10 buttons of different widths :
int btnCount = 10;
int totalWidth = 0;
int spacing = 5;
NSMUtableArray *buttons = [[NSMutableArray alloc] init];
for (int i=0; i<btnCount-1; i++) {
UIButton *b = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[b setTitle:#"some title" forState:UIControlStateNormal];
[b sizeToFit];
CGRect frame = b.frame;
totalWidth += b.frame.size.width;
[buttons addObject:b];
}
totalWidth += (btnCount * spacing);
UIView *btnView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, totalWidth, 40)];
int priorButtonX = 0;
for (UIButton *b in buttons) {
CGRect frame = b.frame;
frame.origin.x = priorButtonX;
b.frame = frame;
priorButtonX = frame.origin.x + spacing;
[btnView addSubview:b];
}
int scrollSizeWidth = scrollView.contentSize.width;
int placeX = (scrollSizeWidth /2) - (btnView.frame.size.width /2)
CGRect btnViewFrame = btnView.frame;
btnViewFrame.origin.x = placeX;
bbtnView.frame = btnViewFrame;
[scrollView addSubView:btnView];
You might want to do something with Y placement, but that one is very simple. This code can be written in fewer lines, and use fewer variables, but this is done to make it easier to read.

Related

Place UIImageViews in row

I am looping through a array and adding UIImageViews, the array has a have different count depending on somethings. So the amount of UIImageViews varies. What I need to do is line them up in a row in the center of the view. I know the code that I need to use its the calculations that I am having an issue with.
for (int i = 0; i < [_lettersArray count]; i++){
UIImage* imageContainer = [UIImage imageNamed:#"container.png"];
UIImageView *containerView = [[UIImageView alloc] initWithImage:imageContainer];
containerView.frame = CGRectMake(???,120,imageContainer.size.width,imageContainer.size.height);
[self.view addSubview:containerView];
}
[self _layoutViews:self.imageViews inView:self.view];
- (void) _layoutViews:(NSArray *)views inView:(UIView *)contentView
{
NSInteger overallWidth = 0;
for ( UIView *view in views ) {
overallWidth += view.frame.size.width;
}
CGSize contentSize = contentView.frame.size;
CGFloat startOffset = (contentSize.width - overallWidth)/2.0;
CGFloat offset = startOffset;
for ( UIView *view in views ) {
CGRect frame = view.frame;
frame.origin.x = offset;
frame.origin.y = (contentSize.height/2.0) - (frame.size.height/2.0);
view.frame = frame;
offset += view.frame.size.width;
}
}
For your example code it would be something like this:
CGFloat count = [_lettersArray count];
NSMutableArray *imageViews = [[NSMutableArray alloc] initWithCapacity:count];
for (int i = 0; i < [_lettersArray count]; i++) {
UIImage *imageContainer = [UIImage imageNamed:#"container.png"];
UIImageView *containerView = [[UIImageView alloc] initWithImage:imageContainer];
containerView.frame = CGRectMake(0,120,imageContainer.size.width,imageContainer.size.height);
[imageViews addObject:containerView];
[self.view addSubview:containerView];
}
[self _horizontalCenterViews:imageViews inView:self.view];
return YES;
}
- (void) _horizontalCenterViews:(NSArray *)views inView:(UIView *)contentView
{
NSInteger overallWidth = 0;
for ( UIView *view in views ) {
overallWidth += view.frame.size.width;
}
CGSize contentSize = contentView.frame.size;
CGFloat startOffset = (contentSize.width - overallWidth)/2.0;
CGFloat offset = startOffset;
for ( UIView *view in views ) {
CGRect frame = view.frame;
frame.origin.x = offset;
view.frame = frame;
offset += view.frame.size.width;
}
}

space between images in thumbnail for ipad

I create Thumbnail photo with scrollview for ipad, here is the code:
// load all the images from bundle and add them to the scroll view
NSUInteger i;
for (i = 1; i <= kNumImages; i++)
{
NSString *imageName = [NSString stringWithFormat:#"image%d.jpg", i];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
}
- (void)layoutScrollImages
{
UIImageView *view = nil;
NSArray *subviews = [scrollView1 subviews];
// reposition all image subviews in a horizontal serial fashion
CGFloat curXLoc = 0;
for (view in subviews)
{
if ([view isKindOfClass:[UIImageView class]] && view.tag > 0)
{
CGRect frame = view.frame;
frame.origin = CGPointMake(curXLoc, 0);
view.frame = frame;
curXLoc += (kScrollObjWidth);
}
}
}
rightnow I have all images in UIScrollView that they are next to each other, I want to have some space between each images like this picture
would you please give me some hint that how can I add space between these images?
Thanks in Advance!
Try this:
curXLoc += (kScrollObjWidth) + kDifferenceBetweenImages;
and define kDifferenceBeteweenIMages accordingly.
Use UICollectionView instead. Much easier to achieve what you want and will work better too.
It even has a property for the space between each cell.
Try this one :
CGRect frame = view.frame;
frame.origin = CGPointMake(curXLoc, 0);
frame.size.height = //put height;
frame.size.width = //put width;
frame.origin.y = //put y;
view.frame = frame;
curXLoc += (kScrollObjWidth) + 15;

UIScrollView paging tagging

I've created a UIScrollView with paging containing several images, with 1 image per "page", and i was wondering if there were any way to distinguish the images from each other?
Fx. when the first image is showing, I would have a button to set a UILabel to '1' and when the second image is showing, the same button would set the same UILabel to '2'.
Here's my code:
pictures = [NSArray arrayWithObjects: [UIImage imageNamed:#"AND.png"], [UIImage imageNamed:#"ALB.png"], nil];
for (int i = 0; i < pictures.count; i++) {
CGRect frame;
frame.origin.x = 135 + (self.scrollViewQuiz.frame.size.width * i);
frame.origin.y = 40;
frame.size = CGSizeMake(50, 50);
UIImageView *subview = [[UIImageView alloc] initWithFrame:frame];
subview.image = [pictures objectAtIndex:i];
[self.scrollViewQuiz addSubview:subview];
}
self.scrollViewQuiz.contentSize = CGSizeMake(self.scrollViewQuiz.frame.size.width * pictures.count, self.scrollViewQuiz.frame.size.height);
It sounds like you just want to compute the "page number" that the scroll view is currently displaying. You can try something like this as your button's action:
- (IBAction)buttonWasTapped:(id)sender {
UIScrollView *scrollView = self.scrollViewQuiz;
int pageNumber = (int)roundf(scrollView.contentOffset.x / scrollView.bounds.size.width);
self.label.text = [NSString stringWithFormat:#"%d", pageNumber];
}
You could implement the following scrollview delegate method:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
In it you would examine the scrollview's contentOffset and set the label accordingly.
Try these two.. these should work.. hope this helps..
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat xOffset = scrollView.contentOffset.x;
int currentPage = floor(xOffset / scrollView.bounds.size.width);
[itsLabel setText:[NSString stringWithFormat:#"%i", currentPage]];
}
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
CGFloat xOffset = scrollView.contentOffset.x;
int currentPage = floor(xOffset / scrollView.bounds.size.width);
[itsLabel setText:[NSString stringWithFormat:#"%i", currentPage]];
}

Scroll View adding views on top of each other

I can add several scrollviews with its background colours changed and it works fine. So basically for every view you have different background colours. However when I try to add separate views for each of these, it adds it right on top of the other and I don't know why.
UIViewController *view1 = [self.storyboard instantiateViewControllerWithIdentifier:#"View1"];
UIViewController *view2 = [self.storyboard instantiateViewControllerWithIdentifier:#"View2"];
UIViewController *view3 = [self.storyboard instantiateViewControllerWithIdentifier:#"View3"];
for (NSInteger i=0; i<ScrollViewControllerNumberOfPages; i++) {
CGFloat yOrigin = i * self.view.frame.size.height;
CGRect subViewFrame = CGRectMake(yOrigin, 0, pageHeight, pageWidth);
NSLog(#"Printing Width and Height %f %f",pageWidth,pageHeight);
UIView *subView = [[UIView alloc] initWithFrame:subViewFrame];
// Pick a random colour for the view
CGFloat randomRed = ((CGFloat)(arc4random() % 1000))/1000;
CGFloat randomGreen = ((CGFloat)(arc4random() % 1000))/1000;
CGFloat randomBlue = ((CGFloat)(arc4random() % 1000))/1000;
subView.backgroundColor = [UIColor colorWithRed:randomRed green:randomGreen blue:randomBlue alpha:1];
NSLog(#"printin i %i", i);
if (i == 0)
subView = view1.view;
else if (i == 1)
subView = view2.view;
[self.scrollView addSubview:subView];
}
This is kind of a shot in the dark because your code would need some serious rethinking.
What you're doing is you allocate a subview, you modify it's frame and background and then completely disregard this and set it to a view of previously instantiated viewcontoller.
This should work (in a way):
UIViewController *view1 = [self.storyboard instantiateViewControllerWithIdentifier:#"View1"];
UIViewController *view2 = [self.storyboard instantiateViewControllerWithIdentifier:#"View2"];
UIViewController *view3 = [self.storyboard instantiateViewControllerWithIdentifier:#"View3"];
for (NSInteger i=0; i<ScrollViewControllerNumberOfPages; i++) {
CGFloat yOrigin = i * self.view.frame.size.height;
CGRect subViewFrame = CGRectMake(yOrigin, 0, pageHeight, pageWidth);
NSLog(#"Printing Width and Height %f %f",pageWidth,pageHeight);
UIView *subView;
if (i == 0)
subView = view1.view;
else if (i == 1)
subView = view2.view;
subView.frame = subViewFrame;
// Pick a random colour for the view
CGFloat randomRed = ((CGFloat)(arc4random() % 1000))/1000;
CGFloat randomGreen = ((CGFloat)(arc4random() % 1000))/1000;
CGFloat randomBlue = ((CGFloat)(arc4random() % 1000))/1000;
subView.backgroundColor = [UIColor colorWithRed:randomRed green:randomGreen blue:randomBlue alpha:1];
NSLog(#"printin i %d", i);
[self.scrollView addSubview:subView];
}
It might look a bit better if you do it like:
for (NSInteger i=0; i<ScrollViewControllerNumberOfPages; i++) {
CGFloat yOrigin = i * self.view.frame.size.height;
CGRect subViewFrame = CGRectMake(yOrigin, 0, pageHeight, pageWidth);
NSLog(#"Printing Width and Height %f %f",pageWidth,pageHeight);
UIViewController *subViewCont = [self.storyboard instantiateViewControllerWithIdentifier:[NSString stringWithFormat:#"View%d",i+1]];
UIView *subView = subViewCont.view;
subView.frame = subViewFrame;
// Pick a random colour for the view
CGFloat randomRed = ((CGFloat)(arc4random() % 1000))/1000;
CGFloat randomGreen = ((CGFloat)(arc4random() % 1000))/1000;
CGFloat randomBlue = ((CGFloat)(arc4random() % 1000))/1000;
subView.backgroundColor = [UIColor colorWithRed:randomRed green:randomGreen blue:randomBlue alpha:1];
NSLog(#"printin i %d", i);
[self.scrollView addSubview:subView];
}

Make a Views with Array

I want to create views programmatically, Matrix: 10X10 = 100 views . I've created IB but it has to be programmed with Xcode. How can i do this?
For one view create this, for 10X10 views I don't know. How can i do all views;
UIView *tempView1 = [[UIView alloc] initWithFrame:CGRectMake(0, 660, 60, 60)];
[self.view addSubview:tempView1];
rd = 0;
gr = 0.5;
bl =0;
tempView1.backgroundColor = [UIColor colorWithRed:rd green:gr blue:bl alpha:1.0];
This should do the trick for you:
for (int i = 0; i < amountOfViewsHorizontally; i++)
{
for (int j = 0; j < amountOfViewsVertically; j++)
{
UIView *someView = [[UIView alloc] initWithFrame:CGRectMake((i*widthOfView), (j*heightOfView), widthOfView, heightOfView)];
rd = 0;
gr = 0.5;
bl =0;
someView.backgroundColor = [UIColor colorWithRed:rd green:gr blue:bl alpha:1.0];
UILabel *someLabel = [[UILabel alloc] init];
someLabel.frame = CGRectMake(0,0,50,20); //this will add a label in all the upperleft corners (point(0,0)) of every view with width 50 and height 20.
[someView addSubView:someLabel];
//[someViewArray addObject:someView]; //add view to an array
[self.view addSubview:someView];
}
}
You might want to put them into some sort of array so you can access them at some later point.
If you want components like UILabel to be added to those views. You will have to use the intern coordinate system of those views.
For an example of more detailed layout, row, height dynamically, check out my article here. It shows how you can not only dynamically layout boxes according to size and screen size but also how dynamic reordering works.
See the article for more details but the key approach is...
- (void) layoutBoxesWithRowCount:(NSInteger)rowCount {
double xPos = kBoxSpacer;
double yPos = kBoxSpacer;
int boxCount = 0;
for(LOBox *box in boxes) {
CGRect frame = [box frame];
frame.origin.x = xPos;
frame.origin.y = yPos;
[box setFrame:frame];
xPos += kBoxDimension + kBoxSpacer;
boxCount++;
if(boxCount == rowCount) {
boxCount = 0;
xPos = kBoxSpacer;
yPos += kBoxDimension + kBoxSpacer;
}
}
}
Full write-up here.