How to center a grouped table view both vertically and horizontally on iOS? - objective-c

I've been looking for a way to center a table view both vertically and horizontally but I can't seem to figure out if this is better done / possible using interface builder alone. If not what method should I override to set this in objective-c itself?
Also will this use the vertical screen size of the device so it actually centers the grouped table view on both legacy iPhone devices and the new iPhone 5?
Thank you in advance

This is what I use to get the proper centered frame. Note that the view needs to have proper springs and struts so it resizes when phone calls come in, etc:
+ (CGRect)centeredFrameForSize:(CGSize)size inRect:(CGRect)rect
{
CGRect frame;
frame.origin.x = rintf((rect.size.width - size.width)/2) + rect.origin.x;
frame.origin.y = rintf((rect.size.height - size.height)/2) + rect.origin.y;
// if(frame.origin.x < 0) frame.origin.x = 0;
// if(frame.origin.y < 0) frame.origin.y = 0;
frame.size = size;
return frame;
}

Related

Change UIView layout programmatically for iPhone 5

I am trying to change the layout of my UIView programmatically, and not by using Auto Layout, as I am trying to deploy this app for iOS 4 and up. I basically set my view up with the screen height at 455(iPhone 5)(I know the actual screen size is 568 points, but I have a tab bar on the bottom so I am assuming the size shown in IB has taken that into account). I recorded the origin of all of my buttons and labels relative to the longer screen size and programmatically changed them to how I preferred them. The problem is, some of the buttons and labels are going off the screen now, so I think I have to perform some kind of conversion to keep them in bounds, but I am not sure what. See the pictures attached below:
Image before my initMethod is called to change button and label origins
Image after my initMethod is called to change the origin
View properties in XCode for the old screen size
This is how I want the view to Look. I moved the buttons around and recorded the origin of each.
Picture of my init method in viewWillAppear. Notice how the frame of the label is zero.
Here is the code I used:
-(void)initView
{
CGRect screenBounds = [[UIScreen mainScreen] bounds];
if (screenBounds.size.height == 480) {
//iphone 4,4s
//done
}else if(screenBounds.size.height == 568) {
//iphone 5
CGRect frame;
//Static Professor label
frame = [staticProfessorLabel frame];
frame.origin.x = 48;
frame.origin.y = 218;
[staticProfessorLabel setFrame:frame];
//Professor Label
frame = [professorLabel frame];
frame.origin.x = 192;
frame.origin.y = 218;
[professorLabel setFrame:frame];
//show button
frame = [showProfessorButton frame];
frame.origin.x = 67;
frame.origin.y = 258;
[showProfessorButton setFrame:frame];
//clear proff button
frame = [clearProfessor frame];
frame.origin.x = 240;
frame.origin.y = 258;
//note label
frame = [bottomNote frame];
frame.origin.x = 160;
frame.origin.y = 310;
[bottomNote setFrame:frame];
//search button
frame = [searchButton frame];
frame.origin.x = 158;
frame.origin.y = 424;
[searchButton setFrame:frame];
//spinner
frame = [actIndicator frame];
frame.origin.x = 266;
frame.origin.y = 424;
[actIndicator setFrame:frame];
}
}
Also, I am calling this in the viewDidAppear method because when I call it in viewDidLoad, none of the buttons and labels give me a valid frame(I am guessing they are not initialized yet).
Your Xcode screenshots show that your storyboard contains constraints, so we can tell that your storyboard has autolayout turned on. If you want to set the view frames directly in code, you have to turn off autolayout.
Take a look at my answer here if you need help turning off autolayout on your storyboard.
Your hard-coded coordinates are simply wrong. Just double-check your values.
For example, bottomNote starts at x 160, which is clearly too far to the right.

ConvertRect accounting for UIScrollView zoom and contentOffset

I've been trying to get the converted CGRect of a UIView within a UIScrollView. It works fine if I'm not zoomed, but once I zoom, the new CGRect shifts. Here is the code that's gotten me close:
CGFloat zoomScale = (scrollView.zoomScale);
CGRect newRect = [self.view convertRect:widgetView.frame fromView:scrollView];
CGPoint newPoint = [self.view convertPoint:widgetView.center fromView:scrollView];
// Increase the size of the CGRect by multiplying by the zoomScale
CGSize newSize = CGSizeMake(newRect.size.width * zoomScale, newRect.size.height * zoomScale);
// Subtract the offset of the UIScrollView for proper positioning
CGPoint newCenter = CGPointMake(newPoint.x - scrollView.contentOffset.x, newPoint.y - scrollView.contentOffset.y);
// Create rect with the proper width/height (x and y set by center)
newRect = CGRectMake(0, 0, newSize.width, newSize.height);
[self.view addSubview:widgetView];
widgetView.frame = newRect;
widgetView.center = newCenter;
I'm fairly certain that my issue lies in the zoomScale - I should probably be modifying the x and y coordinates based on the zoomScale value. Everything I have tried thus far has been unsuccessful, though.
I received the following answer from user Brian2012 on the iOS dev forums:
What I did:
Created a UIScrollView that covers the view controller's main view.
Put a desktop view (a standard UIView) in the scroll view. The origin of the desktop is at 0,0 and the size is bigger than the scroll view so I could scroll around without having to zoom first.
Put some widget views (UIImageView) into the desktop view at various locations.
Set the contentSize of the scroll view to the size of the desktop view.
Implemented viewForZoomingInScrollView to return the desktop view as the view to scroll.
Put NSLogs in scrollViewDidZoom to print out the frame of the desktop view and one of the widget views.
What I found out:
The widget frame never changes from the initial value that I set. So for example, if a widget started at position 108, 108 with a size of 64x64, then the frame is always reported as 108,108,64,64 regardless of zooming or scrolling.
The desktop frame origin never changes. I put the origin of the desktop at 0,0 in the scroll view, and the origin is always reported as 0,0 regardless of zooming or scrolling.
The only thing that changes is the desktop view's frame size, and the size is just the original size multiplied by the scroll view's zoomScale.
Conclusion:
To figure out the location of a widget relative to the coordinate system of the view controller's main view, you need to do the math yourself. The convertRect method doesn't do anything useful in this case. Here's some code to try
- (CGRect)computePositionForWidget:(UIView *)widgetView fromView:(UIScrollView *)scrollView
{
CGRect frame;
float scale;
scale = scrollView.zoomScale;
// compute the widget size based on the zoom scale
frame.size.width = widgetView.frame.size.width * scale;
frame.size.height = widgetView.frame.size.height * scale;
// compute the widget position based on the zoom scale and contentOffset
frame.origin.x = widgetView.frame.origin.x * scale - scrollView.contentOffset.x + scrollView.frame.origin.x;
frame.origin.y = widgetView.frame.origin.y * scale - scrollView.contentOffset.y + scrollView.frame.origin.y;
// return the widget coordinates in the coordinate system of the view that contains the scroll view
return( frame );
}
I have also similar kind of issue, i fixed it by a different trick. i catch the zoom scale in a temporary variable, and set scrollView's zoom scale to minimum(1.0) and then calculate my frame using convertRect() and set the original zoom scale again
CGFloat actualZoomScal = self.baseVideoView.zoomScale;
CGPoint actualOffset = self.baseVideoView.contentOffset;
self.baseVideoView.zoomScale = 1.0;
CGRect iFrame = [[RGLayout layout] rectToPixels:[self recordingIndicatorFrame]];
self.recordIndicator = [[RiscoRecordingIndicatorView alloc] initWithFrame:[self convertRect:iFrame fromView:self.previewView]];
[self addSubview:self.recordIndicator] ;
[self bringSubviewToFront:self.recordIndicator] ;
self.baseVideoView.zoomScale = actualZoomScal;
self.baseVideoView.contentOffset = actualOffset;

UIScrollView moves image to the top left corner when zooming in

Looking at this question: Prevent UIScrollView from moving contents to top-left, i'm having the exact issue.
I'm using this tutorial: http://cocoadevblog.heroku.com/iphone-tutorial-uiimage-with-zooming-tapping-rotation
Back to the similar question, if i disable the UIScrollViewPanGestureRecognizer, i'm not able to pan the zoomed image anymore.
I have a UIImageView within a UIScrollView, and i want to be able to zoom and pan the image as well.
How can i do tho disable the contents moving to the top left corner when zooming in?
Seems i solved tweaking my UiScrollView Autosizing and Origin in the Size inspector \ Attributes inspector. I unchecked Paging Enabled and the magic happened.
Just in case anyone else comes here and none of the other answers seem to work ( which was my case ), what did the trick for me was setting the contentSize of the scrollView. Just set it to the size whatever subview you are zooming in on and it should work.
Make a subclass of UIScrollView, and add this method to it:
- (void)layoutSubviews {
[super layoutSubviews];
// center the image as it becomes smaller than the size of the screen
CGSize boundsSize = self.bounds.size;
//get the subView that is being zoomed
UIView *subView = [self.delegate viewForZoomingInScrollView:self];
if(subView)
{
CGRect frameToCenter = subView.frame;
// center horizontally
if (frameToCenter.size.width < boundsSize.width)
frameToCenter.origin.x = (boundsSize.width - frameToCenter.size.width) / 2;
else
frameToCenter.origin.x = 0;
// center vertically
if (frameToCenter.size.height < boundsSize.height)
frameToCenter.origin.y = (boundsSize.height - frameToCenter.size.height) / 2;
else
frameToCenter.origin.y = 0;
subView.frame = frameToCenter;
}
else
NSLog(#"No subView set for zooming in delegate");
}
If I understand you right, you want to allowing scrolling only when theImageView is zoomed in, then a scrollView.zoomScale > 1. For my app requirement I am using this.
Add UIScrollView's delegate method as follows and check.
- (void)scrollViewDidScroll:(UIScrollView *)aScrollView
{
CGFloat offsetY = 0;
if (aScrollView.zoomScale > 1)
offsetY = aScrollView.contentOffset.y;
[aScrollView setContentOffset: CGPointMake(aScrollView.contentOffset.x, offsetY)];
}

How do you change the width of a UITableView?

I'm new to iPhone development, coming from a web application development background and I'm working on my first project. I chose to create a Navigation based project, since after reading it seemed to be the easiest way to get what I'm after. How do you change the width of the UITableView? Eventually, I'd like to have a top bar, UITableView, and bottom bar be 304px wide. I've tried the following in my RootViewController's viewDidLoad method, but I'm doing it wrong:
CGRect tableViewFrame = self.tableView.frame;
tableViewFrame.size.width = 200;
self.tableView.frame = tableViewFrame;
Thanks for any help in advance.
If you want to change the width of the tableViewCell.. go to cellForRowAtIndexPath, and assign it there.
You could also do -
CGFloat tableBorderLeft = 1;
CGFloat tableBorderRight = 1;
CGRect tableRect = self.view.frame;
tableRect.origin.x += tableBorderLeft; // make the table begin a few pixels right from its origin
tableRect.size.width -= tableBorderLeft + tableBorderRight; // reduce the width of the table
tableView.frame = tableRect;
For changing the size of header
-(CGFloat)tableView:(UITableView*)tableView heightForHeaderInSection:(NSInteger)section
{
return 150.0; //Give a value
}
For changing size of footer
-(CGFloat)tableView:(UITableView*)tableView heightForFooterInSection:(NSInteger)section
{
return 150.0;//Give a value
}

Core Animation and Transformation like zoomRectToVisible

I'm trying to get an effect like the zoomRectToVisible-method of UIScrollview.
But my method should be able to center the particular rect in the layer while zooming and it should be able to re-adjust after the device orientation changed.
I'm trying to write a software like the marvel-comic app and need a view that presents each panel in a page.
For my implementation I'm using CALayer and Core Animation to get the desired effect with CATransform3D-transformations. My problem is, I'm not able to get the zoomed rect/panel centered.
the structure of my implementation looks like this: I have a subclass of UIScrollview with a UIView added as subview. The UIView contains the image/page in it's CALayer.contents and I use core animations to get the zooming and centering effect. The zoom effect on each panel works correcty but the centering is off. I'm not able to compute the correct translate-transformation for centering.
My code for the implementation of the effect is like this:
- (void) zoomToRect:(CGRect)rect animated:(BOOL)animated {
CGSize scrollViewSize = self.bounds.size;
// get the current panel boundingbox
CGRect panelboundingBox = CGPathGetBoundingBox([comicPage panelAtIndex:currentPanel]);
// compute zoomfactor depending on the longer dimension of the panelboundingBox size
CGFloat zoomFactor = (panelboundingBox.size.height > panelboundingBox.size.width) ? scrollViewSize.height/panelboundingBox.size.height : scrollViewSize.width/panelboundingBox.size.width;
CGFloat translateX = scrollViewSize.width/2 - (panelboundingBox.origin.x/2 + panelboundingBox.size.width/2);
CGFloat translateY = scrollViewSize.height/2 - (panelboundingBox.size.height/2 - panelboundingBox.origin.y);
// move anchorPoint to panelboundingBox center
CGPoint anchor = CGPointMake(1/contentViewLayer.bounds.size.width * (panelboundingBox.origin.x + panelboundingBox.size.width/2), 1/contentViewLayer.bounds.size.height * (contentViewLayer.bounds.size.height - (panelboundingBox.origin.y + panelboundingBox.size.height/2)));
// create the nessesary transformations
CATransform3D translateMatrix = CATransform3DMakeTranslation(translateX, -translateY, 1);
CATransform3D scaleMatrix = CATransform3DMakeScale(zoomFactor, zoomFactor, 1);
// create respective core animation for transformation
CABasicAnimation *zoomAnimation = [CABasicAnimation animationWithKeyPath:#"transform"];
zoomAnimation.fromValue = (id) [NSValue valueWithCATransform3D:contentViewLayer.transform];
zoomAnimation.toValue = (id) [NSValue valueWithCATransform3D:CATransform3DConcat(scaleMatrix, translateMatrix)];
zoomAnimation.removedOnCompletion = YES;
zoomAnimation.duration = duration;
// create respective core animation for anchorpoint movement
CABasicAnimation *anchorAnimatione = [CABasicAnimation animationWithKeyPath:#"anchorPoint"];
anchorAnimatione.fromValue = (id)[NSValue valueWithCGPoint:contentViewLayer.anchorPoint];
anchorAnimatione.toValue = (id) [NSValue valueWithCGPoint:anchor];
anchorAnimatione.removedOnCompletion = YES;
anchorAnimatione.duration = duration;
// put them into an animation group
CAAnimationGroup *group = [CAAnimationGroup animation];
group.animations = [NSArray arrayWithObjects:zoomAnimation, anchorAnimatione, nil] ;
/////////////
NSLog(#"scrollViewBounds (w = %f, h = %f)", self.frame.size.width, self.frame.size.height);
NSLog(#"panelBounds (x = %f, y = %f, w = %f, h = %f)", panelboundingBox.origin.x, panelboundingBox.origin.y, panelboundingBox.size.width, panelboundingBox.size.height);
NSLog(#"zoomfactor: %f", zoomFactor);
NSLog(#"translateX: %f, translateY: %f", translateX, translateY);
NSLog(#"anchorPoint (x = %f, y = %f)", anchor.x, anchor.y);
/////////////
// add animation group to layer
[contentViewLayer addAnimation:group forKey:#"zoomAnimation"];
// trigger respective animations
contentViewLayer.anchorPoint = anchor;
contentViewLayer.transform = CATransform3DConcat(scaleMatrix, translateMatrix);
}
So the view requires the following points:
it should be able to zoom and center a rect/panel of the layer/view depending on the current device orientation. (zoomRectToVisible of UIScrollview does not center the rect)
if nessesary (either device orientation changed or panel requires rotation) the zoomed panel/rect should be able to rotate
the duration of the animation is depending on user preference. (I don't know whether I can change the default animation duration of zoomRectToVisible of UIScrollView ?)
Those points are the reason why I overwrite the zoomRectToVisible-method of UIScrollView.
So I have to know how I can correctly compute the translation parameters for the transformation.
I hope someone can guide me to get the correct parameters.
Just skimmed over your code and this line is probably not being calculated as you think:
CGPoint anchor = CGPointMake(1/contentViewLayer.bounds.size.width * (panelboundingBox.origin.x + panelboundingBox.size.width/2), 1/contentViewLayer.bounds.size.height * (contentViewLayer.bounds.size.height - (panelboundingBox.origin.y + panelboundingBox.size.height/2)));
You're likely to get 0 because of the 1/ at the start. C will do your multiplication before this division, resulting in values <1 - probably not what you're after. See this
You might find it more useful to breakdown your calculation so you know it's working in the right order (just use some temporary variables) - believe me it will help enormously in making your code easier to read (and debug) later. Or you could just use more brackets...
Hope this helps.