这是我设置一些UIView
和子视图的几个问题中的第一个。我有一个UIView
在运行时动态定位在屏幕上。 UIView
(主)包含另一个UIView
(子),其中包含UIImageView
和UILabel
。以下是我对此安排的要求:
UIView
必须在主人UIView
中居中。 UILabel
中的文字可能很长或很短,带图片和文字的儿童UIView
仍必须保持居中。willRotateToInterfaceOrientation.
中的任何框架/定位代码我想通过一些autoresizingMask
设置来处理所有这些IB如果可能的话,也许有点强制调整代码大小。这是Interface Builder中的控件排列(以红色突出显示):
使用Interface Builder,autoresizingMask
属性已设置如此,用于描述的控件
UIView
(主):灵活的上边距,灵活的左边距,灵活的右边距,灵活的宽度UIView
(儿童):灵活的上边距,灵活的下边距,灵活的左边距,灵活的右边距,灵活的宽度,灵活的高度。 (所有模式,除无)UIImageView
:灵活的右边距UILabel
:灵活的右边距在纵向模式下,在运行时以编程方式添加视图(带图像和文本的红色条):
主人UIView
的背景是浅红色的图像。儿童UIView
的背景略暗于此,UILabel
的背景更暗。我对它们进行着色,以便在应用程序响应轮换时我可以看到它们的边界。
我很清楚:
这是在以纵向方式添加后再旋转到横向模式后的视图:
从这里我可以看到:
这是我现在所处位置的代码。我从viewDidLoad调用方法showNoDataStatusView
:
// Assuming
#define kStatusViewHeight 20
- (void)showNoDataStatusView {
if (!self.noDataStatusView.superview) {
self.noDataStatusView.frame = CGRectMake(self.mapView.frame.origin.x,
self.mapView.frame.origin.y,
self.mapView.frame.size.width,
kStatusViewHeight);
self.noDataStatusView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"bgRedStatus.png"]];
// Position the label view in the center
self.noDataStatusLabelView.center = CGPointMake(self.noDataStatusView.frame.size.width/2,
self.noDataStatusView.frame.size.height/2);
// Test different text
self.noDataStatusLabel.text = @"Testing, 123.";
// Size to fit label
[self.noDataStatusLabel sizeToFit];
// Test the status label view resizing
[self.noDataStatusLabelView resizeToFitSubviews];
// Add view as subview
[self.view addSubview:self.noDataStatusView];
}
}
请注意以下事项:
resizeToFitSubviews
是我在UIView上的一个类别,一旦我发现即使你打电话给sizeToFit
,UIView也不会自动调整大小以适应他们的子视图。 This question和this question解释了这个问题。请参阅下面的类别代码。UIView resizeToFitSubviews类别实现方法:
-(void)resizeToFitSubviews
{
float width = 0;
float height = 0;
// Loop through subviews to determine max height/width
for (UIView *v in [self subviews]) {
float fw = v.frame.origin.x + v.frame.size.width;
float fh = v.frame.origin.y + v.frame.size.height;
width = MAX(fw, width);
height = MAX(fh, height);
}
[self setFrame:CGRectMake(self.frame.origin.x, self.frame.origin.y, width, height)];
}
我想知道的是,为什么UIView
(子)在将超级视图添加到视图层次结构后没有正确居中。它看起来好像有适当的宽度,但不知何故保留了它在I.B.中的框架。当标签显示“此地图范围内没有数据。”
我还想知道为什么它不会在设备旋转后居中,以及我在这里采取的方法是否明智。也许这会导致我遇到的其他问题。任何UIView布局帮助都将非常感激。
谢谢!
答案 0 :(得分:1)
如果您能够定位iOS 6,您可以使用新的自动布局功能,使这更容易管理 - 我一直在阅读Ray Wenderlich的great tutorial,这似乎是完美的解决方案你看到的问题。
答案 1 :(得分:1)
这里的问题是我的UIView
(主人)在设备旋转时没有自动布局它的子视图,而用于定位图像和内部UIView
的“弹簧和支柱”布局方法是效率低下。我通过做两件事解决了这个问题。
UIView
(子)实例,只留下UIView
(主),并且只留下UILabel
和UIImageView
。UIView
的{{1}}子类,并在其中实现了StatusView
方法。在其构造函数中,我添加了layoutSubviews
和UIImageView
并动态定位它们。 UILabel
首先根据文字的大小定位,然后将UILabel
放在其左侧并垂直居中。而已。在UIImageView
中,我确保为新框架调整元素的位置。此外,由于我需要在某些情况下交换背景,消息和可能的图像,因此使用自定义类是有意义的。这里/那里可能存在内存问题,但是当我使用分析工具运行时,我会解决它们。
最后,我不完全确定这段代码是否坚如磐石,但确实有效。我不知道我的init方法中是否需要布局代码。在将视图添加为子视图后,似乎很快就会调用布局子视图。
这是我的班级标题:
layoutSubviews
......和实施:
#import <UIKit/UIKit.h>
typedef enum {
StatusViewRecordCountType = 0,
StatusViewReachedMaxRecordCountType = 1,
StatusViewZoomInType = 2,
StatusViewConnectionLostType = 3,
StatusViewConnectionFoundType = 4,
StatusViewNoDataFoundType = 5,
StatusViewGeographyIntersectionsType = 6,
StatusViewRetreivingRecordsType = 7
} StatusViewType;
@interface StatusView : UIView
@property (strong, nonatomic) NSString *statusMessage;
@property (nonatomic) StatusViewType statusViewType;
- (id)initWithFrame:(CGRect)frame message:(NSString*)message type:(StatusViewType)type;
@end
然后在我的视图控制器中我可以这样做:
#import "StatusView.h"
#define kConstrainSizeWidthOffset 10
#define kImageBufferWidth 15
@interface StatusView ()
@property (nonatomic, strong) UILabel *statusMessageLabel;
@property (nonatomic, strong) UIFont *statusMessageFont;
@property (nonatomic, strong) UIImage *statusImage;
@property (nonatomic, strong) UIImageView *statusImageView;
@end
@implementation StatusView
@synthesize statusMessageLabel = _statusMessageLabel;
@synthesize statusMessageFont = _statusMessageFont;
@synthesize statusImageView = _statusImageView;
@synthesize statusMessage = _statusMessage;
@synthesize statusViewType = _statusViewType;
@synthesize statusImage = _statusImage;
- (id)initWithFrame:(CGRect)frame message:(NSString *)message type:(StatusViewType)type {
self = [super initWithFrame:frame];
if (self) {
if (message != nil) {
_statusMessage = message;
_statusMessageFont = [UIFont fontWithName:@"Avenir-Roman" size:15.0];
CGSize constrainSize = CGSizeMake(self.frame.size.width - kImageBufferWidth - kConstrainSizeWidthOffset, self.frame.size.height);
// Find the size appropriate for this message
CGSize messageSize = [_statusMessage sizeWithFont:_statusMessageFont constrainedToSize:constrainSize];
// Create label and position at center of status view
CGRect labelFrame = CGRectMake(self.frame.origin.x,
self.frame.origin.y,
messageSize.width,
messageSize.height);
_statusMessageLabel = [[UILabel alloc] initWithFrame:labelFrame];
_statusMessageLabel.backgroundColor = [UIColor clearColor];
_statusMessageLabel.textColor = [UIColor whiteColor];
_statusMessageLabel.font = _statusMessageFont;
// Set shadow and color
_statusMessageLabel.shadowOffset = CGSizeMake(0, 1);
_statusMessageLabel.shadowColor = [UIColor blackColor];
// Center the label
CGPoint centerPoint = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2);
_statusMessageLabel.center = centerPoint;
// Gets rid of fuzziness
_statusMessageLabel.frame = CGRectIntegral(_statusMessageLabel.frame);
// Flex both the width and height as well as left and right margins
_statusMessageLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
// Set label text
_statusMessageLabel.text = _statusMessage;
[self addSubview:_statusMessageLabel];
}
self.statusViewType = type;
if (_statusImage != nil) {
// Create image view
_statusImageView = [[UIImageView alloc] initWithImage:_statusImage];
// Vertically center the image
CGPoint centerPoint = CGPointMake(_statusMessageLabel.frame.origin.x - kImageBufferWidth,
self.frame.size.height / 2);
_statusImageView.center = centerPoint;
[self addSubview:_statusImageView];
}
}
return self;
}
- (void)layoutSubviews {
CGSize constrainSize = CGSizeMake(self.frame.size.width - kImageBufferWidth - kConstrainSizeWidthOffset, self.frame.size.height);
// Find the size appropriate for this message
CGSize messageSize = [_statusMessage sizeWithFont:_statusMessageFont constrainedToSize:constrainSize];
// Create label and position at center of status view
CGRect labelFrame = CGRectMake(self.frame.origin.x,
self.frame.origin.y,
messageSize.width,
messageSize.height);
_statusMessageLabel.frame = labelFrame;
// Center the label
CGPoint centerPoint = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2);
_statusMessageLabel.center = centerPoint;
// Gets rid of fuzziness
_statusMessageLabel.frame = CGRectIntegral(_statusMessageLabel.frame);
if (_statusImageView != nil) {
// Vertically center the image
CGPoint centerPoint = CGPointMake(_statusMessageLabel.frame.origin.x - kImageBufferWidth,
self.frame.size.height / 2);
_statusImageView.center = centerPoint;
}
}
#pragma mark - Custom setters
- (void)setStatusMessage:(NSString *)message {
if (_statusMessage == message) return;
_statusMessage = message;
_statusMessageLabel.text = _statusMessage;
// Force layout of subviews
[self setNeedsLayout];
[self layoutIfNeeded];
}
- (void)setStatusViewType:(StatusViewType)statusViewType {
_statusViewType = statusViewType;
UIColor *bgColor = nil;
switch (_statusViewType) {
// Changes background and image based on type
}
self.backgroundColor = bgColor;
if (_statusImageView != nil) {
_statusImageView.image = _statusImage;
}
}
@end
......稍后我可以通过这样做来改变它:
CGRect statusFrame = CGRectMake(self.mapView.frame.origin.x,
self.mapView.frame.origin.y,
self.mapView.frame.size.width,
kStatusViewHeight);
self.staticStatusView = [[StatusView alloc] initWithFrame:statusFrame message:@"600 records found :)" type:StatusViewRecordCountType];
self.staticStatusView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
[self.view addSubview:self.staticStatusView];
现在我有了一个可重用的类而不是12个UIView实例,它们在我的NIB周围浮动,具有各种设置和属性。