[英]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.