如何使用自动布局故事板实现 30 个按钮的网格?
How can I achieve a 30 button grid using autolayout storyboards?
所以我让这个用于 12 个按钮 (4x3) 的按钮网格。
我希望所有按钮大小相同,彼此之间的距离相同,并且整个网格在设备上居中,如下所示:
问题是,当我构建项目时,它看起来像一团乱麻。
我可以正确定位分段控件、得分或重置按钮,但网格只会把一切都搞乱。
我一直在使用中间工具在网格上设置约束,这对 12 按钮网格来说效果很好:
但是,使用它只会产生 xcode 无法解决的无限冲突约束。
我是 iOS 的新手,可能会遗漏一些简单的东西,但我一直在尽最大努力尽可能匹配这里的蓝色自动建议行。
感谢任何建议。
使用带有 UICollectionViewFlowLayout 的 UICollectionView 并让流布局为您创建网格会简单得多。
但即使您不打算这样做,我的建议仍然是:不要在 Xcode / Interface Builder 中进行设置;在代码中制作整个网格(如果需要的话还有约束)。它更简单(也更有趣,更不乏味,当然也更不容易出错)。
1.) 无需在界面构建器中设置每个按钮,而只需创建整个网格应适合的容器(UIView
)。将 constraints
添加到该容器,了解您希望它如何随屏幕尺寸扩展和收缩。
2.) Link 那个容器 UIView
到你的 .h 视图控制器 class 并将其命名为 gridContainer
或其他名称。
3.) 在您的 .h class:
中创建一个 属性
@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"];
}
}
}
}
我在没有 运行 的情况下将所有内容写在此处的方框中,希望对您有用。结果比预期多了几行。
编辑:忘了补充一点,我把卡片按钮的构建和它们的显示分开了,这样你就可以单独调用显示方法了。使用 属性,您还拥有所有卡片的保留来源,因此您可以将它们从数组中取出并根据需要更改您需要的内容。
所以我让这个用于 12 个按钮 (4x3) 的按钮网格。
我希望所有按钮大小相同,彼此之间的距离相同,并且整个网格在设备上居中,如下所示:
问题是,当我构建项目时,它看起来像一团乱麻。
我可以正确定位分段控件、得分或重置按钮,但网格只会把一切都搞乱。
我一直在使用中间工具在网格上设置约束,这对 12 按钮网格来说效果很好:
但是,使用它只会产生 xcode 无法解决的无限冲突约束。
我是 iOS 的新手,可能会遗漏一些简单的东西,但我一直在尽最大努力尽可能匹配这里的蓝色自动建议行。
感谢任何建议。
使用带有 UICollectionViewFlowLayout 的 UICollectionView 并让流布局为您创建网格会简单得多。
但即使您不打算这样做,我的建议仍然是:不要在 Xcode / Interface Builder 中进行设置;在代码中制作整个网格(如果需要的话还有约束)。它更简单(也更有趣,更不乏味,当然也更不容易出错)。
1.) 无需在界面构建器中设置每个按钮,而只需创建整个网格应适合的容器(UIView
)。将 constraints
添加到该容器,了解您希望它如何随屏幕尺寸扩展和收缩。
2.) Link 那个容器 UIView
到你的 .h 视图控制器 class 并将其命名为 gridContainer
或其他名称。
3.) 在您的 .h class:
中创建一个 属性@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"];
}
}
}
}
我在没有 运行 的情况下将所有内容写在此处的方框中,希望对您有用。结果比预期多了几行。
编辑:忘了补充一点,我把卡片按钮的构建和它们的显示分开了,这样你就可以单独调用显示方法了。使用 属性,您还拥有所有卡片的保留来源,因此您可以将它们从数组中取出并根据需要更改您需要的内容。