button自适应宽度 并根据屏幕宽自动换行排列

这是一个封装好的类TagListView,

1. 只需要调用两个方法 设置宽度,间距,边距 并赋给它需要显示的字符串数组;

2. 遵循tagListView的协议, 并实现返回buttonView的方法.

即可展现.

这里我用了SDAutoLayout, 一个三方布局, 用cocopod安装一下就好;

一下是具体的实现代码 带 注释解释

//  TagListView.h 该类的.h文件

#import <UIKit/UIKit.h>
@protocol TagListViewDelegate<NSObject>
@required
- (UIButton *)setItemBtnView;   //必须实现方法:返回buttonView
@optional
- (void)clickWithBtn:(UIButton *)btn idx:(NSInteger)idx; //点击button触发方法
@end

typedef void(^ReturnClickBtnArr)(NSArray *btnArr);  // 返回已选中的按钮数组

@interface TagListView : UIView

@property(nonatomic, strong) UIButton *itemBtn;
@property(nonatomic, assign) NSUInteger maxSelectedTags;    // 多选值
@property(nonatomic, strong) NSMutableArray *selectedTitles;    //已选中的按钮标题数组
@property(nonatomic, weak) id <TagListViewDelegate> delegate;

#pragma mark - 设置宽度 间距 边距
- (void)setWid:(CGFloat)wid btnTitlePadding_X:(CGFloat)horizontailX btnTitlePadding_Y:(CGFloat)vertailY marginX:(CGFloat)marginX marginY:(CGFloat)marginY itemHeight:(CGFloat)height;

#pragma mark - 设置字符串数组 (该方法必须在setWid...方法后执行)
- (void)setTagViewWithTitles:(NSArray *)titleArr;

- (NSArray *)getAllSubBtns;
@end
//  TagListView.m 该类的.m文件

#import "TagListView.h"
#import "UIView+SDAutoLayout.h"
#define kHorizontalX 7
#define kVerticalY 3
#define kMarginY 10
#define kMarginX 10

@implementation TagListView {
    CGFloat _horizontailX;  // btn的左右间距
    CGFloat _vertailY;  // btn的上下间距
    CGFloat _marginX;   // tagView的左右边距
    CGFloat _marginY;   // tagVIew的上下边距
    CGFloat _wid;       // tagView的宽度
    CGFloat _itemHeight;    // btn的高度
    NSArray *_titleArray;   // 需要展示的字符串数组
}

- (instancetype)init {
    if (self = [super init]) {
        _horizontailX = kHorizontalX;
        _vertailY = kVerticalY;
        _marginX = kMarginY;
        _marginY = kMarginX;
        _wid = 0;
        _maxSelectedTags = 3; //default
        _selectedTitles = [NSMutableArray array];
    }
    return self;
}

#pragma mark - 设置宽度 间距 边距
- (void)setWid:(CGFloat)wid btnTitlePadding_X:(CGFloat)horizontailX btnTitlePadding_Y:(CGFloat)vertailY marginX:(CGFloat)marginX marginY:(CGFloat)marginY itemHeight:(CGFloat)height {
    if (wid) {
        _wid = wid;
    }
    if (horizontailX) {
        _horizontailX = horizontailX;
    }
    if (vertailY) {
        _vertailY = vertailY;
    }
    if (marginX) {
        _marginX = marginX;
    }
    if (marginY) {
        _marginY = marginY;
    }
    if (height) {
        _itemHeight = height;
    }
}

#pragma mark - 设置字符串数组 (该方法必须在setWid...方法后执行)
- (void)setTagViewWithTitles:(NSArray *)titleArr {
    _titleArray = [titleArr copy];

    // 清除所有子视图
    while (self.subviews.count) {
        UIView *child = self.subviews.lastObject;
        [child removeFromSuperview];
    }

    // 若未指定宽度 就 获得当前视图宽度
    if (_wid == 0) {
        [self updateLayout];
        _wid = self.width;
    }

    __block int totalHeight = 0;
    __block CGRect previousFrame = CGRectMake(0, 0, 0, 0);
    __block CGFloat height = 0;

    // 循环title数组
    [titleArr enumerateObjectsUsingBlock:^(NSString *title, NSUInteger idx, BOOL * _Nonnull stop) {
        UIButton *tag = [self.delegate setItemBtnView];
        [tag setTitle:title forState:UIControlStateNormal];
        [tag addTarget:self action:@selector(onClick:) forControlEvents:UIControlEventTouchUpInside];
        tag.tag = idx;

        // 设置已选中title的选中状态
        if ([self.selectedTitles containsObject:title]) {
            tag.selected = YES;
        } else {
            tag.selected = NO;
        }

        // 1. 计算size
        // 获得title字体对应的size
        NSDictionary *attrs = @{NSFontAttributeName : tag.titleLabel.font};
        CGSize Size_str = [title sizeWithAttributes:attrs];

        // 给size加上 上下边距
        Size_str.width += _horizontailX * 2;
        if (_itemHeight) {
            Size_str.height = _itemHeight;
        } else {
            Size_str.height += _vertailY * 2;
        }

        CGRect newRect = CGRectZero;
        newRect.size = Size_str;
        // 2. 计算origin
        if (CGRectGetMaxX(previousFrame) + Size_str.width + _marginX > _wid) { //换行
            newRect.origin = CGPointMake(0, CGRectGetMaxY(previousFrame) + _marginY);
            totalHeight += Size_str.height + _marginY;
        } else {    //未换行
            newRect.origin = CGPointMake((CGRectGetMaxX(previousFrame) == 0 ? 0 : CGRectGetMaxX(previousFrame) + _marginX), previousFrame.origin.y);
        }
        [tag setFrame:newRect];

        previousFrame = tag.frame;
        height = totalHeight + Size_str.height;

        [self addSubview:tag];
    }];

    self.sd_layout.heightIs(height);
}

- (NSArray *)getAllSubBtns {
    return  self.subviews;
}

#pragma mark - btn的点击方法
- (void)onClick:(UIButton *)btn {
    // 1.如果超出最多选中数 则需把最先选中的删除
    if (!btn.selected && self.selectedTitles.count >= _maxSelectedTags){
        NSString *title = [self.selectedTitles objectAtIndex:0];
        NSUInteger firstSelectedIndex = [_titleArray indexOfObject:title];
        if (firstSelectedIndex != NSNotFound) {
            UIButton *selectedButton = [self.subviews objectAtIndex:firstSelectedIndex];
            selectedButton.selected = NO;
            [self.selectedTitles removeObjectAtIndex:0];
        }
    }
    long index = btn.tag;
    NSString *title = [_titleArray objectAtIndex:index];
    if (btn.selected) {     // 设置为未选中状态
        btn.selected = NO;
        [self.selectedTitles removeObject:title];
    } else {                // 设置为选中状态
        btn.selected = YES;
        [self.selectedTitles addObject:title];
    }
    // 若delegate包含该方法 则让其执行
    if ([self.delegate respondsToSelector:@selector(clickWithBtn:idx:)]) {
        [self.delegate clickWithBtn:btn idx:index];
    }
}
@end

具体使用如下:

//  ViewController.m

#import "ViewController.h"
#import "UIView+SDAutoLayout.h"
#import "TagListView.h"

#define kScreenWidth self.view.frame.size.width

@interface ViewController ()<TagListViewDelegate>
@property (nonatomic, strong)TagListView *tagListView;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.tagListView = [[TagListView alloc] init];
    self.tagListView.delegate = self;
    self.tagListView.backgroundColor = [UIColor cyanColor];
    self.tagListView.maxSelectedTags = 3;
    [self.view addSubview:self.tagListView];
    self.tagListView.sd_layout.topSpaceToView(self.view, 50).leftSpaceToView(self.view, 16).rightSpaceToView(self.view, 16);
    // 设置宽度 间距 边距
    [self.tagListView setWid:(kScreenWidth - 20) btnTitlePadding_X:20 btnTitlePadding_Y:20 marginX:20 marginY:20 itemHeight:20];
    // 设置需要显示的字符串数组
    [self.tagListView setTagViewWithTitles:@[@"周一", @"周二", @"周三", @"周四", @"周五", @"礼拜六", @"礼拜天", @"一月", @"二月", @"三月", @"四月", @"五月", @"六月", @"七月", @"八月", @"九月", @"十月", @"十一月", @"十二月", @"春天", @"夏天", @"秋天", @"冬天", @"张三", @"李四", @"王五"]];
}

#pragma mark - TagListViewDelegate
// 必须实现的协议方法 返回buttonView
- (UIButton *)setItemBtnView {
    UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
    [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [btn setTitleColor:[UIColor redColor] forState:UIControlStateSelected];
    btn.layer.borderWidth = 0.4;
    btn.layer.cornerRadius = 2;
    btn.layer.borderColor = [UIColor grayColor].CGColor;
    return btn;
}

@end
时间: 2024-08-07 00:11:15

button自适应宽度 并根据屏幕宽自动换行排列的相关文章

解决Button在IE6、7下的自适应宽度问题

很早就遇到过这么个小问题,但由于其并未影响到实际作用和美观就没有正面解决它,现在,我们来试着解决它. 写一个Button,有两种方式:其一,直接button标签:其二,input type=”button”. 不管哪种方式,Button的宽度在IE6.7下总是不能完美,接下来我们演示一个普通的Button,你可以用IE6或者IE7浏览器看看其显示宽度,然后对比Chrome或者IE8等浏览器,你会发现Bug的所在. 1.一个普通的Button: 可以很直接的看到Button的两边有空隙,当然,这个

屏幕自适应宽度

移动设备正超过桌面设备,成为访问互联网的最常见终端.于是,网页设计师不得不面对一个难题:如何才能在不同大小的设备上呈现同样的网页? 很多网站的解决方法,是为不同的设备提供不同的网页,比如专门提供一个mobile版本,或者iPhone / iPad版本.这样做固然保证了效果,但是比较麻烦,同时要维护好几个版本,而且如果一个网站有多个portal(入口),会大大增加架构设计的复杂度. 于是,很早就有人设想,能不能"一次设计,普遍适用",让同一张网页自动适应不同大小的屏幕,根据屏幕宽度,自动

从三栏自适应宽度布局到css布局的讨论

如何实现一个三栏自适应布局,左右各100px,中间随着浏览器宽度自适应? 第一个想到的是使用table布局,设置table的宽度为100%,三个td,第1个和第3个固定宽度为100px,那么中间那个就会自适应了,下面是一个实时的demo: left  middle  right  但是table布局是不推荐的,table布局是css流行之前使用的布局,有很多缺点:当table加载完之前,整个table的都是空白的,table将数据和排版参和在一起,使得页面混乱,并且table布局修改排版十分麻烦

CSS布局——左定宽度右自适应宽度并且等高布局

今天有位朋友一早从妙味课堂转来一个有关于CSS布局的面试题,需要解决,花了点时间写了几个DEMO,放上来与大家分享受.那么我们在看DEMO之前一起先来看看这个面试题的具体要求吧: 左侧固定宽,右侧自适应屏幕宽: 左右两列,等高布局: 左右两列要求有最小高度,例如:200px;(当内容超出200时,会自动以等高的方式增高) 要求不用JS或CSS行为实现: 仔细分析试题要求,要达到效果其实也并不是太难,只是给人感觉像有点蛋疼的问题一样.但是你仔细看后你会觉得不是那么回事: 左边固定,右边自适应布局,

解决左边固定右边自适应宽度的方案

上一篇文章中有提及过很多web前端开发者用float+margin+position:absolute来实现表单内容的左边文字固定右边的输入框自适应宽度的问题,当然,这个问题我也在百度中搜索过,基本搜索出来的答案都是这样描述的,我也在上一篇文章中提出过浮动和绝对定位属于脱离文档流布局,是会损耗性能的,但是百度中却没有给出我所想表达出的解决方案,所以不得不在此将该方案具体的描述清楚. 首先,我需要介绍的是display:box这个属性,它是今天弹性布局的主角,虽然它有个更加强大的弟弟display

[Winform]DataGridView列自适应宽度

引言 在做winform项目中,数据控件DataGridView的使用多多少少是会用到的,如果不设置它的属性,默认情况下是不会自适应宽度的,你想查看某项的数据,就不得不将标题栏拖来拖去,挺烦的. 方法 建一个用于测试的Person类 1 public class Person 2 { 3 [Description("姓名")] 4 public string Name { get; set; } 5 [Description("性别")] 6 public stri

UEditor百度富文本编辑器--让编辑器自适应宽度的解决方案

UEditor百度富文本编辑器的initialFrameWidth属性,默认值是1000. 不能够自适应屏幕宽度.如图1: 刚开始的时候,我是直接设置initialFrameWidth=null的.效果如图2: 这样子UEditor百度富文本编辑器会在第一次加载的时候获取屏幕宽度,然后赋值给initialFrameWidth属性. 这样子确实是可以在第一次加载的时候适应屏幕宽度,但是却似乎宽度稍微过了一点点,超过上面的灰条了.而且这里还有一个问题: 当你改变浏览器大小时,会有个很严重的排版BUG

js获取浏览器宽高、网页宽高、屏幕宽高、鼠标位置等(带图片说明)

网页可见区域宽: document.body.clientWidth;网页可见区域高: document.body.clientHeight;(点击查看大图) 网页可见区域宽: document.body.offsetWidth (包括边线的宽);网页可见区域高: document.body.offsetHeight (包括边线的宽);(点击查看大图)有没有发现,offsetWidth和clientWidth的区别,offsetWidt是连滚动条一起包含在内的. 网页正文全文宽: documen

[转]UEditor百度富文本编辑器--让编辑器自适应宽度的解决方案

转自http://www.cnblogs.com/VAllen/p/UEditor-InitialFrameWidth-Auto.html UEditor百度富文本编辑器的initialFrameWidth属性,默认值是1000. 不能够自适应屏幕宽度.如图1: 刚开始的时候,我是直接设置initialFrameWidth=null的.效果如图2: 这样子UEditor百度富文本编辑器会在第一次加载的时候获取屏幕宽度,然后赋值给initialFrameWidth属性. 这样子确实是可以在第一次加