一个想法是,与其用标签替换自定义视图,不如给它们一个“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;
}