Programmatically Centering UIViews
I've seen a bunch of similar questions to this, but nothing seems to be completely what I'm looking for. Do forgive me if I have missed the solution answered in another question, though!
Right. I have a view. 160 pixels both tall and wide. I know that this view is going to be used as a subview, and I know that it always needs to be centered about both axis in whatever situation it's used.
If defining the view programmatically, how can I be sure that it is always perfectly centered, horizontally and vertically, relative to its superview?
So far, all I have is this simple code:
- (void)loadView {
self.view = [[UIView alloc] initWithFrame:CGRectMake(80, 150, 160, 160)];
self.view.backgroundColor = [UIColor greenColor];
self.view.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin);
[self.view release];
}
This does the centralization, 开发者_如何学Gobut only in the simplest of cases. Any insight is greatly appreciated.
EDIT 1:
With the addition of the following line of code:
self.view.center = self.view.superview.center;
The subview's center point becomes the (0,0) coordinate of the superview. Perhaps I haven't set up the superview correctly?
In addition to what @Jasarien and @Brad have said, don't forget that you can force auto-centering using the Autosizing springs and struts. Essentially (in Interface Builder) you click around until there are no Autosizing lines visible, like this:
alt text http://gallery.me.com/davedelong/100084/Screen-20shot-202010-03-26-20at-2010-49-18-20AM/web.jpg?ver=12696222220001
In code, you set the -[UIView autoresizingMask]
to:
Objective C :
(UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleTopMargin |
UIViewAutoresizingFlexibleBottomMargin)
Swift 3.x :
[.flexibleLeftMargin, .flexibleRightMargin, .flexibleTopMargin, .flexibleBottomMargin]
If you do these, then the view stays centered automatically.
EDIT #1
Answering your edit, you can't do:
self.view.center = self.view.superview.center;
Unless your view has been added as a subview of another view ([anotherView addSubview:self.view];
). My guess is that self.view.superview
is returning nil
, and so you're (luckily) getting {0,0}
as the return value when trying to invoke center
on nil
.
The proper place to center your view would probably be in the viewWillAppear:
method of the view controller. Once the view is about to appear, you know that it must have a superview (otherwise how else would it be about to appear?). You could safely set your view's center
there.
I'd say the simplest way to do this is to set the center of the view to be at the center of it's superview (which you can obtain from the superview's height and width attributes):
// Init as above and then...
// Get superview's CGSize
CGSize size = self.superview.frame.size;
[self.view setCenter:CGPointMake(size.width/2, size.height/2)];
I don't think you can do the simpler:
self.view.center = self.view.superview.center;
As the superview's center is defined in the superview's superview. Thus the superview could be centered about (0,0), but you wouldn't want to center your view at this point.
Quote from Apple docs:
The center is specified within the coordinate system of its superview
Assuming you are inside of a subclass of UIView, you could do this:
-(void) layoutSubviews {
self.center = self.superview.center;
}
Or, if as above, you are working inside of a ViewController, you could
- (void)loadView {
//...
self.view.center = self.view.superview.center;
}
Brad Smith beat me to the punch, with a slightly more elegant solution :D
Let me know if this isn't what you're looking for, but have you tried:
// when adding to a subview, try this, where myView is the view you need centered,
// and myMainView is the view you'll be adding it to as a subview
myView.center = myMainView.center;
[myMainView addSubview:myView];
I had the same issue. Each time I tried to access to self.view.superview or self.view.window on viewDidLoad they returned nil. In viewDidLoad (I guess it's the same for loadView) those pointer are not initialized yet. To solved this issue I can give you a trick:
- (void)viewDidLoad
{
[super viewDidLoad];
// both equal to nil
id lwindow = self.view.window;
id lparent = self.view.superview;
[self performSelector:@selector(myViewDidLoad) withObject:nil afterDelay:0.01];
}
- (void)myViewDidLoad
{
// both not equal to nil!
id lwindow = self.view.window;
id lparent = self.view.superview;
}
It's like self.view.parent and self.view.window are initialized after viewDidLoad and loadView.
精彩评论