UIButton的自动排列

news/2024/7/20 20:53:02 标签: iOS, objective-c, UIButton, 布局

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


目录

      • 实现效果
      • 基本思路
      • 核心代码
      • 附录固定列数的button布局
        • 效果图
        • 核心代码

实现效果

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];

http://www.niftyadmin.cn/n/1035855.html

相关文章

java异常-捕获异常

在Java中&#xff0c;凡是可能抛出异常的语句&#xff0c;都可以用try … catch捕获。把可能发生异常的语句放在try { … } 中&#xff0c;然后使用catch捕获对应的Exception及其子类。 1.在多个catch的时候&#xff0c;catch的顺序非常重要&#xff1a;子类必须写在前面&#…

Nullability and Objective-C

更新&#xff1a;这篇文章为Xcode 7 的新语法 _Nullable 而更新。 由于Swfit能够和Objective-C代码混编&#xff0c;所以它在OC的框架和你的app代码里都存在。然而&#xff0c;在Swift中&#xff0c;optional 与non-optional有很大的不同&#xff0c;例如&#xff1a;NSView V…

js中typeof的用法

一、 经常会在js里用到数组,比如 多个名字相同的input, 若是动态生成的, 提交时就需要判断其是否是数组. if(document.mylist.length ! "undefined" ) {} 这个用法有误. 正确的是 if( typeof(document.mylist.length) ! "undefined" ) {} 或 if( !isNaN(do…

java高级-反射一

反射 概念&#xff1a; JAVA反射机制是在运行状态中&#xff0c;对于任意一个类&#xff0c;都能够知道这个类的所有属性和方法&#xff1b;对于任意一个对象&#xff0c;都能够调用它的任意一个方法和属性&#xff1b;这种动态获取的信息以及动态调用对象的方法的功能称为jav…

[objc explain]: Non-fragile ivars

写在前面&#xff1a; Non-fragile 非脆弱性fragile 非脆弱性ivars 实例变量-instance variables的缩写 非脆弱[Non-fragile] 实例变量是现代版Objective-C的一个新功能&#xff0c;应用于iPhone和64位Mac上。它们提供给框架开发者更多的灵活性&#xff0c;且不会失去二进制的…

html input文本框 输入框提示(hint)内容的实现

HTML开发中经常遇到input元素&#xff0c;往往又需要提示使用者输入一定规则的内容&#xff0c;这时最好的一个方法就是在input里面实现一个提示&#xff0c;实现如下方式&#xff1a;输入框为空时提示内容出现&#xff0c;当输入框获得焦点时或输入框不为空时则消失。 1.通过…

Objective-C Runtime 编程指南

简介 Objective-C 从编译、链接接到运行需要遵守许多规则&#xff0c;只要有可能&#xff0c;它会动态的做一些事情。这意味着代码需要的不仅仅是一个编译&#xff0c;而且也有一个运行时系统去执行被编译的代码。运行时系统的行为作为Objective-C语言的一种操作方式。也是这门…

java高级-反射二

反射机制的相关类 类名用途Class类代表类的实体&#xff0c;在运行的Java应用程序中表示类和接口Field类代表类的成员变量&#xff08;成员变量也称为类的属性&#xff09;Method类代表类的方法Constructor类代表类的构造方法一.Class类 获得类相关的方法 方法用途asSubclas…