UITableViewCell 附件视图相互影响?

UITableViewCell accessory views affecting each other?

提问人:tajmahal 提问时间:1/18/2023 更新时间:1/18/2023 访问量:61

问:

我有一个非常奇怪的问题,一个人的附件视图似乎会影响另一个附件视图的框架。UITableViewCellUITableViewCell

当我运行该应用程序时,它起初看起来像这样(滑块和 +/- 按钮包含在一个普通的文本中,该文本被设置为表格视图单元格的附件视图。UIView

enter image description here

但是,在重新加载表格视图后,滑块的大小会调整为如下所示(现在它太宽了,到达“+”按钮下方。

enter image description here

这似乎只有在我将作为附件视图添加到表视图的最后一行时才会发生!?我绝对不明白一行的附件视图如何能够影响(通过自动调整大小?)另一行附件视图的子视图的宽度。UISwitch

我相信当我上次在应用程序中使用这种代码时,这个故障并不存在。那是大约两到三年前的事了,MacOS 10.14 上的 Xcode 11.3.1 部署目标是 iOS 8。现在我在 macOS 12.6.2 上使用 Xcode 14.2,部署目标为 iOS 13。

我试图缩小错误范围,以获得一个合理的最小示例,但它仍然有些冗长,所以很抱歉。

我在 Xcode 中创建了一个新的 iOS 应用程序并扔掉了故事板。我的代码如下所示:

// AppDelegate.h

#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>
{
    UIWindow *window;
}

@end
// AppDelegate.m

#import "AppDelegate.h"
#import "TableViewController.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    
    TableViewController *tableViewController = [[TableViewController alloc] initWithStyle:UITableViewStyleInsetGrouped];
    
    UINavigationController *navController =
        [[UINavigationController alloc] initWithRootViewController:tableViewController];
    
    [window setRootViewController:navController];
    [window makeKeyAndVisible];
    
    return YES;
}

@end
// TableViewController.h

#import <UIKit/UIKit.h>

@interface TableViewController : UITableViewController
{
    UIView *sliderContainerView;
}

@end
// TableViewController.m

#import "TableViewController.h"

static NSString *const kDefaultCell = @"DefaultCell";

@implementation TableViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    [[self navigationItem] setTitle:@"Title"];
    
    UIBarButtonItem *reloadButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"reloadData" style:UIBarButtonItemStylePlain target:self action:@selector(reloadAction:)];
    [[self navigationItem] setRightBarButtonItem:reloadButtonItem];
    
    // create the slider container view
    CGRect frame = CGRectMake(0, 0, 150, 7); // actual width is not important, will get updated before display
    sliderContainerView = [[UIView alloc] initWithFrame:frame];
    
    UIFont *buttonFont = [UIFont systemFontOfSize:40 weight:UIFontWeightThin];
    
    // create the minus button
    frame = CGRectMake(0, -29, 0, 0);
    UIButton *minusButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [minusButton setFrame:frame];
    [minusButton setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin];
    [minusButton setTitle:@"–" forState:UIControlStateNormal];
    [[minusButton titleLabel] setFont:buttonFont];
    [minusButton sizeToFit];
    [sliderContainerView addSubview:minusButton];
    
    // create the slider
    frame = CGRectMake(34, 0, 82, 7);
    UISlider *slider = [[UISlider alloc] initWithFrame:frame];
    [slider setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
    slider.backgroundColor = [UIColor clearColor];
    slider.minimumValue = 1;
    slider.maximumValue = 10;
    [sliderContainerView addSubview:slider];
    
    // create the plus button
    frame = CGRectMake(120, -29, 0, 0);
    UIButton *plusButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [plusButton setFrame:frame];
    [plusButton setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin];
    [plusButton setTitle:@"+" forState:UIControlStateNormal];
    [[plusButton titleLabel] setFont:buttonFont];
    [plusButton sizeToFit];
    [sliderContainerView addSubview:plusButton];
}

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    
    [self updateLengthViewWidth];
}

- (void)updateLengthViewWidth
{
    UITableView *tableView = [self tableView];
    int lengthViewWidth = [[UIScreen mainScreen] bounds].size.width - [tableView layoutMargins].left - [tableView layoutMargins].right - 128;
    
    CGRect frame = [sliderContainerView frame];
    frame.size.width = lengthViewWidth;
    [sliderContainerView setFrame:frame];
}

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kDefaultCell];
    
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kDefaultCell];
        
        [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
    }
    
    if ([indexPath row] == 0) {
        [[cell textLabel] setText:@"foo"];
        [cell setAccessoryView:sliderContainerView];
    } else if ([indexPath row] == 1) {
        [[cell textLabel] setText:@"bar"];
        [cell setAccessoryView:nil];
    } else if ([indexPath row] == 2) {
        [[cell textLabel] setText:@"baz"];
        [cell setAccessoryView:nil];
    } else if ([indexPath row] == 3) {
        [[cell textLabel] setText:@"baz"];
        [cell setAccessoryView:[[UISwitch alloc] init]];
    }
    
    return cell;
}

- (IBAction)reloadAction:(id)sender
{
    [[self tableView] reloadData];
}

@end

知道这里发生了什么,以及如何解决它吗?

iOS Objective-C UITableView UIKit的

评论

1赞 HangarRash 1/18/2023
我建议创建一个包含滑块和两个按钮的自定义视图类,并将其全部设置为使用约束。如果你到了获得屏幕尺寸的地步,那么你就做错了。约束要好得多。顺便说一句,你似乎正在用 15 年前的风格编写你的 Objective-C 代码。是时候开始使用现代语法了。简单多了。
0赞 tajmahal 1/18/2023
你是对的,编码风格有点古老。这是因为我从中提取此代码片段的代码库的其余部分也如下所示。(我刚刚将代码转换为示例的 ARC......另外,我个人不喜欢“现代”Objective-C 中点表示法和括号式方法调用的混合,所以我倾向于完全避免它。你当然是对的,因为使用屏幕尺寸是一个坏主意。然而,在过去的十年里,代码曾经是这样工作的,我不想完全重新设计它(并把我的头缠绕在自动布局上)......好吧,也许时机已经到来。
0赞 tajmahal 1/26/2023
因此,我最终将当前实现替换为 UITableViewCell 子类。修复这样一个小错误需要付出很多努力,但你能做什么......

答: 暂无答案