簡體   English   中英

在 Objective-C 中使用 UIStackView 擴展 UITableViewCell

[英]Extending UITableViewCell with UIStackView in Objective-C

我有自己的跨平台小部件布局系統,用於大多數事情,所以我以前從未使用過布局約束,所以這是我第一次深入研究它。 我的代碼在 Objective-C 而不是 Swift 中,我發現的所有示例都在 Swift 中。 默認情況下,我的 UITableView 只會顯示圖標和文本。 但是,它具有額外的“列”圖標和文本,這些圖標和文本將位於 MacOS 或其他桌面平台上的各個列中。 我有一個切換按鈕,可以讓這些附加信息顯示在水平或垂直 UIStackView 中。 因此,如果切換,我想將 UIStackView 添加到放置在 textLabel 下的 UITableViewCell 中,將 UITableViewCell 擴展為 UIStackView 所需的任何大小。 我的想法是我可以通過添加 3 個將 UIStackView、contentView 和 textLabel 連接在一起的約束來做到這一點。 這沒有產生預期的結果。 前兩個約束正確 position UIStackView 下面的 textLabel 但沒有展開 UITableViewCell。 添加第三個(底部)約束來擴展單元格,而是將 UIStackView 完全從單元格中剪掉。 有人可以指出我做錯了什么嗎?

NSLayoutConstraint *constraint;

stack = [[[UIStackView alloc] init] retain];
[stack setTranslatesAutoresizingMaskIntoConstraints:NO];
[stack setSpacing:5.0];
[[self contentView] addSubview:stack];

/* Leading */
constraint = [NSLayoutConstraint constraintWithItem:stack attribute:NSLayoutAttributeLeft
                                          relatedBy:NSLayoutRelationEqual toItem:[self contentView]
                                          attribute:NSLayoutAttributeLeft multiplier: 1.0 constant:0.0];
[[self contentView] addConstraint:constraint];

/* Top */
constraint = [NSLayoutConstraint constraintWithItem:stack attribute:NSLayoutAttributeTop
                                          relatedBy:NSLayoutRelationEqual toItem:[self textLabel]
                                          attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0];
[[self contentView] addConstraint:constraint];

/* Bottom */
constraint = [NSLayoutConstraint constraintWithItem:[self contentView] attribute:NSLayoutAttributeBottom
                                          relatedBy:NSLayoutRelationEqual toItem:stack
                                          attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0];
[[self contentView] addConstraint:constraint];

通過使用“現代”約束語法,您可以節省大量輸入,並使代碼更具可讀性。

例如,如果我們創建了 label 和堆棧視圖,並將它們添加到單元格的內容視圖中:

    // let's use the default margins
    UILayoutGuide *g = self.contentView.layoutMarginsGuide;

    [NSLayoutConstraint activateConstraints:@[

        // constrain label Top/Leading/Trailing to content margins guide
        [label.topAnchor constraintEqualToAnchor:g.topAnchor constant:0.0],
        [label.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:0.0],
        [label.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:0.0],
        //  no Height, because we'll use the label's intrinsic size

        // constrain stack view Top to label bottom plus 8-points
        [stack.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:8.0],
        // Leading/Trailing/Bottom to content margins guide
        [stack.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:0.0],
        [stack.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:0.0],
        [stack.bottomAnchor constraintEqualToAnchor:g.bottomAnchor constant:0.0],
        //  no Height, because we'll use the arranged subviews heights

    ]];

所以,我們可以這樣寫一個單元格 class :

StackTableViewCell.h

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN
@interface StackTableViewCell : UITableViewCell
@end
NS_ASSUME_NONNULL_END

StackTableViewCell.m

#import "StackTableViewCell.h"

@interface StackTableViewCell()
{
    UIStackView *stack;
    UILabel *label;
}
@end

@implementation StackTableViewCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self commonInit];
    }
    return self;
}
- (instancetype)init
{
    self = [super init];
    if (self) {
        [self commonInit];
    }
    return self;
}
- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self commonInit];
    }
    return self;
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self) {
        [self commonInit];
    }
    return self;
}

- (void)commonInit {

    // create a label
    label = [UILabel new];
    [label setBackgroundColor:UIColor.greenColor];
    [label setNumberOfLines:0];

    // create a vertical stack view
    stack = [UIStackView new];
    [stack setAxis:UILayoutConstraintAxisVertical];
    [stack setSpacing:5.0];

    // add label and stack view to content view
    [label setTranslatesAutoresizingMaskIntoConstraints:NO];
    [stack setTranslatesAutoresizingMaskIntoConstraints:NO];
    [[self contentView] addSubview:label];
    [[self contentView] addSubview:stack];

    // let's use the default margins
    UILayoutGuide *g = self.contentView.layoutMarginsGuide;

    [NSLayoutConstraint activateConstraints:@[

        // constrain label Top/Leading/Trailing to content margins guide
        [label.topAnchor constraintEqualToAnchor:g.topAnchor constant:0.0],
        [label.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:0.0],
        [label.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:0.0],
        //  no Height, because we'll use the label's intrinsic size

        // constrain stack view Top to label bottom plus 8-points
        [stack.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:8.0],
        // Leading/Trailing/Bottom to content margins guide
        [stack.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:0.0],
        [stack.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:0.0],
        [stack.bottomAnchor constraintEqualToAnchor:g.bottomAnchor constant:0.0],
        //  no Height, because we'll use the arranged subviews heights

    ]];

    // let's give the stack view a border so we can see its frame
    stack.layer.borderColor = UIColor.redColor.CGColor;
    stack.layer.borderWidth = 1.0;

}

@end

連同基本的 controller...

StackTableViewController.h

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN
@interface StackTableViewController : UITableViewController
@end
NS_ASSUME_NONNULL_END

StackTableViewController.m

#import "StackTableViewController.h"
#import "StackTableViewCell.h"

@interface StackTableViewController ()

@end

@implementation StackTableViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [self.tableView registerClass:StackTableViewCell.class forCellReuseIdentifier:@"c"];
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 30;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    StackTableViewCell *cell = (StackTableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"c" forIndexPath:indexPath];

    // Configure the cell...
    return cell;
}

@end

此時,因為我們沒有給單元格提供任何數據——標簽和堆棧視圖在為空時沒有固有高度——它看起來像這樣:

在此處輸入圖像描述

所以,讓我們添加一個fillData方法:

StackTableViewCell.h

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN
@interface StackTableViewCell : UITableViewCell
// add this line
- (void)fillData:(NSInteger)n;
@end
NS_ASSUME_NONNULL_END

StackTableViewCell.m

// add this method
- (void)fillData:(NSInteger)n {

    label.text = [NSString stringWithFormat:@"Cell %ld", (long)n];
    
    // cells are reused, so first clear any existing labels in the stack view
    //  this is inefficient, but we're just demonstrating the cell sizing
    for (UIView *v in stack.arrangedSubviews) {
        [v removeFromSuperview];
    }
    
    // now add n number of labels
    for (int i = 0; i < n; i++) {
        UILabel *v = [UILabel new];
        v.text = [NSString stringWithFormat:@"Stack Label %ld", (long)i];
        v.backgroundColor = UIColor.yellowColor;
        [stack addArrangedSubview:v];
    }
    
}

並修改 controller 以設置一些單元格數據:

StackTableViewController.m

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    StackTableViewCell *cell = (StackTableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"c" forIndexPath:indexPath];

    // Configure the cell...
    [cell fillData:(indexPath.row % 4) + 1];
    
    return cell;
}

現在 output 看起來像這樣:

在此處輸入圖像描述

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM