簡體   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