UIButton的自动排列

本文介绍了如何在iOS开发中,根据UIButton的不同宽度自动进行排列布局。通过创建一个继承自UIView的子类ButtonLayoutView,实现了动态计算每个按钮的位置,以适应不同宽度的按钮。文章提供了核心代码示例,并附带了固定列数按钮布局的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在工作中用到了UIButton的排布,需求是根据button的不同宽度(高度相同)实现自动排布。这是第四次用到了,前面分别写了3个项目,用到了三次,感觉还是比较常用的小功能;第一次自己写了个算法,第二次和三次写成固定宽高的按钮规则排布,这次由于要适应不同宽度的需要,在原有基础上做了修改,可以适应不同的按钮宽度,布局自动计算。


目录

实现效果

Button排列

基本思路

核心问题是根据button的数量,和每一个button的宽度(宽度由文字多少决定)计算button的排布,button高度和内间距可以设为固定常数。
1. 将创建好的按钮放在数组中;
2. 解决分类和计算逻辑:先确定第一个button的位置,然后计算第二个button的位置,第二个button的位置可能在当前行,也可能在下一行。需要两个if else嵌套,在循环遍历button的过程中,动态确定每一个button的位置。

核心代码

1.创建继承于UIView的子类:ButtonLayoutView,在ButtonLayoutView.m中实现计算:

#import "ButtonsLayoutView.h"

CGFloat const buttonH = 30;
CGFloat const buttonInset = 20;

@interface ButtonsLayoutView()
/** button array */
@property (strong, nonatomic) NSMutableArray *buttonArray;
@end

@implementation ButtonsLayoutView

-(NSMutableArray *)buttonArray {
    if (!_buttonArray) {
        _buttonArray = [NSMutableArray array];
    }
    return _buttonArray;
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self createButtons:@[@"30 g",@"20 g",@"40 g",@"50 g",@"样例样例",@"样例样例样例",@"样例",@"30 g",@"20 g",@"40 g",@"50 g",@"样例样例",@"样例样例样例",@"样例"]];
    }
    return self;
}

- (void)createButtons:(NSArray *)titles{
    for (int i = 0; i < titles.count; i++) {
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.backgroundColor = [UIColor purpleColor];
        [button setTitle:titles[i] forState:UIControlStateNormal];
        [self addSubview:button];

        // calucate frame
        [button sizeToFit];
        CGRect rect = button.frame;
        rect.size.width += 2 * buttonInset;
        rect.size.height = buttonH;
        button.frame = rect;
        // add array
        [self.buttonArray addObject:button];
    }
}

- (void)layoutSubviews {
    [super layoutSubviews];
    for (int i = 0; i < self.buttonArray.count; i ++) {
        // 1.take out button
        UIButton *button = self.buttonArray[i];
        CGRect rect = button.frame;
        CGRect superRect = self.frame;
        // 2.calucate layout
        if (i == 0) { // the first button
            rect.origin.x = buttonInset;
            rect.origin.y = buttonInset;
        } else { // the behind button
            UIButton *lastButton = self.buttonArray[i - 1];
            CGRect lastRect = lastButton.frame;
            CGFloat leftButtonW = CGRectGetMaxX(lastButton.frame) + buttonInset;
            // over legnth
            CGFloat rightW = superRect.size.width - leftButtonW - buttonInset;
            if (rightW < rect.size.width) { // next line
                rect.origin.x = buttonInset;
                rect.origin.y = CGRectGetMaxY(lastButton.frame) + buttonInset;

            } else {// current line
                rect.origin.x = leftButtonW;
                rect.origin.y = lastRect.origin.y;
            }
        }

        button.frame = rect;
    }
    // superView Height
    UIButton *button = [self.buttonArray lastObject];
    CGRect rect = self.frame;
    rect.size.height = CGRectGetMaxY(button.frame) + buttonInset;
    self.frame = rect;
}

@end

2.测试:在ViewController.m中导入ButtonLayoutView的头文件,开始使用,需要给出ButtonsLayoutView的宽度,和起点坐标,高度会自动被计算:

- (void)viewDidLoad {
    [super viewDidLoad];
    ButtonsLayoutView *layoutView = [[ButtonsLayoutView alloc]init];
    layoutView.backgroundColor = [UIColor brownColor];
    CGRect rect = layoutView.frame;
    rect.size.width = 300;
    rect.origin.x = 50;
    rect.origin.y = 50;
    layoutView.frame = rect;
    layoutView.clipsToBounds = YES;
    [self.view addSubview:layoutView];
}

附录:固定列数的button布局

利用固定列计算button布局,带单选功能。

效果图

举报

核心代码

1.定义

#import "ZFLReportAbuse.h"

@interface ZFLReportAbuse()
/** 被选中的button */
@property (strong, nonatomic) UIButton *selectedButton;
@end

@implementation ZFLReportAbuse

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        self.backgroundColor = ZFLRGBColor(30, 30, 30);
        NSArray *titleArray = @[@"网络盗图",@"垃圾广告",@"不实信息",@"敏感信息",@"其他",@"人身攻击"];
        // 最大列数
        int maxCols = 2;
        // 根据最大列算最大行数
        int maxRows;
        if (titleArray.count <= 3) {
            maxRows = 1;
        } else {
            // 整除,除尽
            BOOL isDivisible = (titleArray.count % maxCols) == 0;
            if (isDivisible) {
                maxRows = (int)titleArray.count / maxCols;
            } else {
                maxRows = (int)titleArray.count / maxCols + 1;
            }
        }

        CGFloat insetMargin = 15;
        CGFloat buttonHeight = 30;
        for (int i = 0; i < titleArray.count; i++) {
            UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
            [button setTitle:titleArray[i] forState:UIControlStateNormal];
            [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
            [button setImage:[UIImage imageNamed:@"normal_icon"] forState:UIControlStateNormal];
            [button setImage:[UIImage imageNamed:@"selected_icon"] forState:UIControlStateSelected];
            button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
            button.width = 100;
            button.height = buttonHeight;
            button.top = insetMargin  + (i / maxCols) * button.height + (i / maxCols) * insetMargin;
            button.left = insetMargin  + (i % maxCols) * button.width + (i % maxCols) * insetMargin;
            [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
            [self addSubview:button];

            // 默认选中第一个
            if (i == 0) {
                button.selected = YES;
                self.selectedButton = button;
            }

            self.height = (buttonHeight + insetMargin) * maxRows + insetMargin;
            self.width = SCREEN_WIDTH;
        }

    }
    return self;
}

- (void)buttonClick:(UIButton *)button {
    self.selectedButton.selected = NO;
    self.selectedButton = button;
    self.selectedButton.selected = YES;
}

@end

2.使用

ZFLReportAbuse *reportView = [[ZFLReportAbuse alloc]init];
reportView.top = 44;
reportView.left = 0;
[self.view addSubview:reportView];
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值