Ios 居中和大小在运行时和方向更改期间调整子视图

Ios 居中和大小在运行时和方向更改期间调整子视图,ios,uiview,subviews,sizetofit,Ios,Uiview,Subviews,Sizetofit,这是我在设置一些UIViews和子视图时遇到的几个问题中的第一个。我有一个ui视图,它在运行时动态定位在屏幕上。该UIView(主视图)包含另一个UIView(子视图),它封装了UIImageView和UILabel。以下是我对这种安排的要求: 当设备旋转时,子视图必须保持在主视图的中心位置 ui标签中的文本可以很长也可以很短,带有图像和文本的子视图必须仍然居中 我希望避免将UIView子类化以处理此场景,我还希望避免在willRotateToInterfaceOrientation中使用任何帧

这是我在设置一些
UIView
s和子视图时遇到的几个问题中的第一个。我有一个
ui视图
,它在运行时动态定位在屏幕上。该
UIView
(主视图)包含另一个
UIView
(子视图),它封装了
UIImageView
UILabel
。以下是我对这种安排的要求:

  • 当设备旋转时,子视图必须保持在主视图的中心位置
  • ui标签
    中的文本可以很长也可以很短,带有图像和文本的子视图必须仍然居中
  • 我希望避免将UIView子类化以处理此场景,我还希望避免在willRotateToInterfaceOrientation中使用任何帧/定位代码。我希望使用I.B.中的一些
    AutoResizingTask
    设置来处理所有这些,如果可能的话,还可以使用一些强制调整大小的代码
  • 这是Interface Builder中控件的排列(以红色突出显示):

    使用Interface Builder,对于所描述的控件,
    autoresizingMask
    属性已按此方式设置

    • ui视图
      (主视图):灵活的上页边距、灵活的左页边距、灵活的右页边距、灵活的宽度
    • ui视图
      (子项):灵活的上边距、灵活的下边距、灵活的左边距、灵活的右边距、灵活的宽度、灵活的高度。(所有模式,无模式除外)
    • UIImageView
      :灵活的右页边距
    • ui标签
      :灵活的右页边距
    这是在运行时以编程方式在纵向模式下添加后的视图(带有图像和文本的红色条):

    主视图的背景是浅红色图像。子视图
    UIView
    的背景比该视图略暗,而
    UILabel
    的背景更暗。我给它们上色,以便在应用程序响应旋转时看到它们的边界

    我很清楚:

    • 它不是居中的,而是
    • 将文本从I.B中的默认值从“此映射范围中没有数据”更改为“Test1123”后,标签将正确收缩
    这是在纵向模式下添加并旋转到横向模式后的视图:

    从这里我可以看到:

    • 它仍然没有居中,并且可能在旋转之前处于其原始帧原点
    • UIView(子视图)已扩展,以在不应填充的情况下填充更多屏幕
    • UIView(主视图)已正确扩展以填充屏幕宽度
    这就是我现在所处位置的密码。我从viewDidLoad调用方法
    ShowNodeDataStatusView

    // 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不会自动调整大小以适应其子视图时放置在UIView上的一个类别,即使您调用
      sizeToFit
      ,并解释了这个问题。请参见下面的类别代码
    • 我曾考虑过创建一个UIView子类来处理所有这些逻辑,但这似乎有些过分。在I.B.安排这个应该很简单吧
    • 我已尝试设置书中的每个调整大小掩码设置,以及调整标签和视图的调整顺序以及主视图作为子视图添加的点。我每次都得到奇怪的结果,似乎什么都不起作用
    UIView ResizetofitsubView类别实现方法:

    -(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
    (子视图)的superview添加到视图层次结构后没有正确居中。它看起来像是得到了正确的宽度,但不知何故保留了它在I.B.中的框架,当标签读到“此地图范围中没有数据”时

    我还想知道为什么在设备旋转后它没有居中,以及我在这里采用的方法是否明智。也许这是我遇到的其他问题的原因。如有任何UIView布局帮助,将不胜感激


    谢谢

    如果你能够瞄准iOS 6,你可以使用新的自动布局功能使其更易于管理-我一直在阅读Ray Wenderlich的一篇文章,它似乎非常适合解决你看到的问题。

    这里的问题是我的
    UIView
    (master)设备旋转时不会自动布局其子视图,用于定位图像和内部的“弹簧和支柱”布局方法效率低下。我通过做两件事解决了这个问题

  • 我去掉了内部的
    UIView
    (子)实例,只剩下
    UIView
    (主)和内部的
    UILabel
    UIImageView
  • 然后,我创建了一个名为
    StatusView
    UIView
    子类,并在其中实现了
    layoutSubviews
    方法。在其构造函数中,我添加了一个
    UIImageView
    UILabel
    并动态定位它们。首先根据文本的大小定位
    ui标签
    ,然后将
    ui图像视图
    放置在标签的左侧并垂直居中。就这样。在
    layoutSubviews
    中,我确保为新帧调整元素的位置
  • 此外,由于我需要在某些情况下交换背景、消息和图像,因此使用自定义类是有意义的。这里/那里可能存在内存问题,但我将在使用分析工具完成此操作时解决这些问题

    最后,我不能完全确定这段代码是否坚如磐石,但它确实有效。我也不知道我的init方法中是否需要布局代码。布局子视图似乎很快就会被调用
    #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];
    
    self.staticStatusView.statusMessage = @"No data was found here";
    self.staticStatusView.statusViewType = StatusViewNoDataFoundType;