如何使用自动布局故事板实现 30 个按钮网格?

Posted

技术标签:

【中文标题】如何使用自动布局故事板实现 30 个按钮网格?【英文标题】:How can I achieve a 30 button grid using autolayout storyboards? 【发布时间】:2015-05-24 03:42:37 【问题描述】:

因此,我将其用于 12 个按钮 (4x3) 的按钮网格。

我希望所有按钮的大小相同,彼此上方和侧面的距离相同,并且整个网格以设备为中心,如下所示:

问题是,当我构建项目时,它看起来像是一团糟。

我可以正确定位分段控制、得分或重置按钮,但网格只会把所有东西都弄乱了。

我一直在使用中间工具在网格上设置约束,这对于 12 按钮网格效果很好:

但是,使用它只会创建 xcode 无法解决的无限冲突约束。

我对 ios 很陌生,可能会遗漏一些简单的东西,但我一直在尽我所能在这里尽可能地匹配蓝色自动建议的行。

感谢您的建议。

【问题讨论】:

这不是界面生成器的任务。正如马特建议的那样,您应该使用 UICollectionView。它可以做你想做的所有事情,并且比这些布局约束更容易设置。或者,您可以使用几行代码更快地完成此操作。 你能帮我用几行代码完成它吗?我也在尝试 UICollectionView,但在 Interface Builder 中为它们设置图像时遇到了一些问题 我会发布一些你可以尝试的东西。 ermahgerd...虽然限制了混乱:O 哈哈,很高兴社区认为这势不可挡。作为一个新手,我认为这可能是 ios UI 开发的世界之道 【参考方案1】:

将 UICollectionView 与 UICollectionViewFlowLayout 一起使用并让流布局为您创建网格会简单得多。

但即使你不打算这样做,我的建议仍然是:不要在 Xcode/Interface Builder 中设置它;用代码制作整个网格(如果需要,还有约束)。它更简单(更有趣,更不乏味,当然也更不容易出错)。

【讨论】:

你能帮我用几行代码完成它吗?我也在尝试 UICollectionView,但在 Interface Builder 中为它们设置图像时遇到了一些问题 您不会在 Interface Builder 中做任何事情。您实现集合视图数据源/委托方法,就像填充 UITableView。 我正在构建一个翻牌游戏,我希望每张卡片都显示卡片的背面,直到它被翻转。我刚刚开始使用 ios,并且正在完成来自 iTunesU 的斯坦福 2013 年 iOS 课程的两门功课。这是一个家庭作业问题。我在课程中学到的东西还不够多,无法按照您的建议进行操作。教授似乎希望我们使用界面生成器,就像我们为 12 卡版本所做的那样,这是家庭作业 1。UITableViews 将在第 17 课中介绍。我在第 4 课。 好的,很公平。但我向你保证,我写过翻牌游戏,而且我总是用代码来布置整个事情。比使用 IB 更容易(也更有趣!)。不是集合视图,而只是表示卡片的视图网格。 自动布局和界面构建器是必不可少的,但在我看来,这意味着您可以布置视图的基础。任何出现重复元素的地方,通常最好使用 tableView、collectionView 或代码生成的视图。【参考方案2】:

1.) 无需在界面构建器中设置每个按钮,只需创建整个网格应放入其中的容器(UIView)。将constraints 添加到该容器中,以了解您希望它如何随屏幕大小扩展和收缩。

2.) 将该容器 UIView 链接到您的 .h 视图控制器类并将其命名为 gridContainer 或其他名称。

3.) 在您的 .h 类中创建一个属性:

@property (strong, nonatomic) NSMutableArray *twoDimensionalArrayContainingRowsOfCardButtons;

4.) 然后:

- (void)viewDidLoad 

    // other stuff you're doing to set up your app
    self.twoDimensionalArrayContainingRowsOfCardButtons = [NSMutableArray new];

    //Do this inside the main thread to make sure all your other views are laid out before this starts
    //Sometimes when you do layout stuff before the rest of the view is set up from Interface Builder you will get weird results.
    dispatch_async(dispatch_get_main_queue(), ^
        [self createTwoMentionalArrayHoldingCardButtons];
        [self displayCardGrid];
    ); 




- (void)createTwoMentionalArrayHoldingCardButtons 
    NSMutableArray *arrayWithRowsOfButtons= [NSMutableArray new];
    for (int x = 0; x < 6; x++) 
        NSMutableArray *arrayOfButtonsAtRowX = [NSMutableArray new];
        for (int i = 0; i < 6; i++) 
           CGRect rect = self.gridContainer.bounds;
           CGSize cellSize = CGSizeMake(rect.size.width / 6, rect.size.height / 6);
           UIButton *buttonInColumnI = [UIButton alloc] initWithFrame:CGRectMake(cellSize.width * i, cellSize.height * x, cellSize.width, cellSize.height);
           [buttonInColumnI setImage:[UIImage imageNamed:@"yourCardImage"] forState:UIControlStateNormal];
           [buttonInColumnI addTarget:self action:@selector(yourButtonAction:) forControlEvents:UIControlEventTouchUpInside];
           [arrayOfButtonsAtRowX addObject:buttonInColumnI];
         
        [arrayOfRowsOfButtons addObject:arrayOfButtonsAtRowX];
    

    self.twoDimensionalArrayContainingRowsOfCardButtons = arrayWithRowsOfButtons;


- (void)displayCardGrid 
    for (int x = 0; x < self.twoDimensionalArrayContainingRowsOfCardButtons.count; x++) 
        NSMutableArray *arrayOfButtonsAtColumnsAtRowX = self.twoDimensionalArrayContainingRowsOfCardButtons[x];
        for (int i = 0; i < arrayOfButtonsAtColumnsAtRowX.count; i++) 
            UIButton *buttonAtColumnI = arrayOfButtonsAtColumnsAtRowX[i];
            [self.gridContainer addSubview:buttonAtColumnI];
        
    


- (void)yourButtonAction:(UIButton *)tappedCard 
    //To swap the card image on your tapped button
    for (int x = 0; x < self.twoDimensionalArrayContainingRowsOfCardButtons.count; x++) 
        NSMutableArray *arrayOfButtonsAtColumnsAtRowX = self.twoDimensionalArrayContainingRowsOfCardButtons[x];
        for (int i = 0; i < arrayOfButtonsAtColumnsAtRowX.count; i++) 
            UIButton *buttonAtColumnI = arrayOfButtonsAtColumnsAtRowX[i];
            if (tappedCard == buttonAtColumnI) 
                int row = x;
                int column = i;
                //Now you can save that the user has tapped something at this row and column.
                //While you're here, you can update the card image.
                [tappedCard setImage:[UIImage imageNamed:@"CardExposedImage"];
            
        
    

我在没有运行它的情况下将所有内容都写在这里,所以希望这对你有用。结果比预期的要多几行。

编辑:忘记补充了,我将卡片按钮的构建和它们的显示分开,以便您可以单独调用显示方法。使用该属性,您还可以保留所有卡片的来源,因此您可以将它们从数组中取出并根据需要更改您需要的内容。

【讨论】:

更新了方法名。 看起来不错...有什么方法可以在图块之间添加间距? 这有两种选择,第一种是简单的——只需将您的卡片图像缩小一点,并让边缘保持透明,以便在按钮之间产生空间错觉。或者在创建 cellSize 时查看数学并计​​算所需的额外空间。

以上是关于如何使用自动布局故事板实现 30 个按钮网格?的主要内容,如果未能解决你的问题,请参考以下文章

使用故事板中的自动布局使 UIButtons 居中

约束/自动布局栏隐藏,Xcode 6

如何在情节提要中使用带有一行按钮的自动布局[重复]

Xcode 6.3 故事板自动布局约束

iOS 自动布局:如何在 Xcode 故事板中为 iPad 横向和 iPad 纵向设计不同的布局?

iOS - 自动布局与不同屏幕尺寸的不同故事板