繁体   English   中英

以编程方式将由Interface Builder安排的自定义UIView替换为UILabels

[英]Replace custom UIViews arranged by Interface Builder with UILabels programmatically

使用Interface Builder ,我建立了一个很长的ScrollView充满了自定义UIViews ,定期UIViewsStackViewsUILabelsUIButtons等。

对于某些自定义UIView,如果它们没有任何数据,那么我想用显示“ No Data Available ”的UILabel替换它们,并且我希望能够设置边距并使该UILabel的文本居中。

鉴于所有视图都是使用interface builder?排列的,因此在ViewController以编程方式进行此操作的最佳/最简便方法是什么interface builder?

谢谢您的帮助!

一个想法是,不要用标签替换自定义视图,而是给它们提供“ noData”模式,在这种模式下,如果没有数据,它们将显示正确的内容...

// CustomView.h

@interface CustomView : UIView
@property(assign,nonatomic) BOOL noData;
@end

// CustomView.m

@interface CustomView ()
@property(weak,nonatomic) UILabel *noDataLabel;
@end

- (void)setNoData:(BOOL)noData {
    _noData = noData;
    self.noDataLabel.alpha = (noData)? 1.0 : 0.0;
}

- (UILabel *)noDataLabel {
    if (!_noDataLabel) {
        UILabel *noDataLabel = [[UILabel alloc] initWithFrame:self.bounds];
        noDataLabel.backgroundColor = self.backgroundColor;
        noDataLabel.textAlignment = NSTextAlignmentCenter;
        noDataLabel.text = @"NO DATA";
        // configure font, etc.
        [self addSubview:noDataLabel];
        _noDataLabel = noDataLabel;
    }
    return _noDataLabel;
}

编辑

如果要将自定义视图视为不可触摸 ,则可以在包含它们的视图控制器中处理其状态,但这有点尴尬,因为我们需要解决将noData标签与子视图关联的问题。 这样的事情可以工作...

// in the view controller that contains the views that should be covered with labels
@interface ViewController ()
@property(weak,nonatomic) NSMutableArray *noDataViews;
@end

// initialize noDataViews early, like in viewDidLoad
_noDataViews = [@[] mutableCopy];

数组noDataViews可以包含字典。 词典将包含具有noData的视图(这可以是第三方自定义视图的实例),以及打算覆盖该视图的UILabel。

- (void)setView:(UIView *)view hasNoData:(BOOL)noData {
    // find the dictionary corresponding to view
    NSDictionary *dictionary;
    for (NSDictionary *d in self.noDataViews) {
        if (d[@"view"] == view) {
            dictionary = d;
            break;
        }
    }
    // if it doesn't exist, insert it
    if (!dictionary) {
        UILabel *label = [self labelToCover:view];
        dictionary = @{ @"view":view, @"label":label };
        [self.noDataViews addObject:dictionary];
    }
    // get the label
    UILabel *label = dictionary[@"label"];
    label.alpha = (noData)? 1.0 : 0.0;
}

// create a label that will cover the passed view, add it as a subview and return it
- (UILabel *)labelToCover:(UIView *)view {
    UILabel *noDataLabel = [[UILabel alloc] initWithFrame:view.frame];
    noDataLabel.backgroundColor = view.backgroundColor;
    noDataLabel.textAlignment = NSTextAlignmentCenter;
    noDataLabel.text = @"NO DATA";
    // configure font, etc.
    [self.view addSubview:noDataLabel];
    return noDataLabel;
}

根据视图将状态更改为noData状态的频率,您可能希望清除字典,删除那些标签的alpha == 0.0的字典。

- (void)releaseNoDataViews {
    NSMutableArray *removeThese = [@[] mutableCopy];
    // work out which ones to remove
    for (NSDictionary *d in self.noDataViews) {
        UILabel *label = d[@"label"];
        if (label.alpha == 0.0) {
            [removeThese addObject:d];
        }
    }
    for (NSDictionary *d in removeThese) {
        UILabel *label = d[@"label"];
        [label removeFromSuperview];
        [self.noDataViews removeObject:d];
    }
}

这有点冗长,因为通过不使用自定义视图,我们将逻辑更改为在视图控制器中改变它们的外观(覆盖它们)。

最好不要使用自定义视图,最好是将它们包装在一个包含视图中,该视图可以完成添加noData状态的附加工作。

例如,说CustomView来自第三方。 创建一个名为CustomViewWrapper的类,该类包含CustomView作为子级,并添加上面概述的noData行为。 代替在IB中绘制CustomView,而绘制CustomViewWrappers。

// CustomViewWrapper.h

@class CustomView;

@interface CustomViewWrapper : UIView
@property(assign,nonatomic) BOOL noData;
@end

// CustomViewWrapper.m

#import "CustomView.h"

@interface CustomViewWrapper ()
@property(weak,nonatomic) CustomView *customView;
@property(weak,nonatomic) UILabel *noDataLabel;
@end

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecorder];
    if (self) {
        CustomView *customView = [[CustomView alloc] init];
        [self addSubView:customView];
        _customView = customView;
    }
    return self;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    self.customView.frame = self.bounds;
}

- (void)setNoData:(BOOL)noData {
    _noData = noData;
    self.noDataLabel.alpha = (noData)? 1.0 : 0.0;
}

- (UILabel *)noDataLabel {
    if (!_noDataLabel) {
        UILabel *noDataLabel = [[UILabel alloc] initWithFrame:self.bounds];
        noDataLabel.backgroundColor = self.backgroundColor;
        noDataLabel.textAlignment = NSTextAlignmentCenter;
        noDataLabel.text = @"NO DATA";
        // configure font, etc.
        [self addSubview:noDataLabel];
        _noDataLabel = noDataLabel;
    }
    return _noDataLabel;
}

您可以通过在要覆盖的视图上添加一个带有一些简单约束的UILabel来实现此目的,而不是在视图内部添加一个UILabel(如果要确保您不会弄乱那些不是您想要的控件)。

我设置了一个简单的测试应用程序,以展示此方法的工作原理 在显示一些控件的图像之前

它具有一个带有一些图像的堆栈视图,一个文本视图以及一个触发样本的按钮。

在代码中确定没有要显示的数据并且想要显示占位符时,您应该能够将此方法应用于视图,但是在我的示例中,我设置了一个IBOutletCollection,它同时具有堆栈视图和文本视图,并在按下按钮时在两个视图上都运行此视图。

后图显示占位符而不是控件

您所需要做的就是为此方法提供占位符文本和要替换的视图

/// This method will hide a view and put a placeholder label in that view's superview, centered in the target view's frame.
- (void)showPlaceholderText:(NSString *)placeholder forView:(UIView *)view
{
    // Build the placeholder with the same frame as the target view
    UILabel *placeholderLabel = [[UILabel alloc] initWithFrame:view.frame];
    placeholderLabel.textAlignment = NSTextAlignmentCenter;
    placeholderLabel.text = placeholder;
    placeholderLabel.translatesAutoresizingMaskIntoConstraints = NO;

    // Hide the target view
    view.hidden = YES;

    // Put our placeholder into the superview, overtop the target view
    [view.superview addSubview:placeholderLabel];

    // Set up some constraints to ensure the placeholder label stays positioned correctly
    [view.superview addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:placeholderLabel attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]];
    [view.superview addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:placeholderLabel attribute:NSLayoutAttributeRight multiplier:1.0f constant:0.0f]];
    [view.superview addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:placeholderLabel attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]];
    [view.superview addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:placeholderLabel attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f]];
}

添加到占位符的约束应通过旋转或视图中的任何其他布局活动来使其正确定位。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM