UIButton的使用

  • 改變按鈕內(nèi)部控件的位置
  • UIButton的一些常用屬性
  • 九宮格的布局
  • 字典轉模型
  • 封裝控件的基本步驟
  • XIB封裝View

UIButton,俗稱“按鈕”
一般情況下,點擊某個控件后,會做出相應反應的都是按鈕
按鈕的功能比較多,既能顯示文字,又能顯示圖片,還能隨時調(diào)整內(nèi)部圖片和文字的位置,比如


點贊 喜歡
圖片在上,文字在下的按鈕

這里對于UIButton的一些常用屬性就不在一一介紹了,本文主要作為自己在使用過程中 經(jīng)常用到的一些功能點 或者說遇到的問題 進行一個總結,方便日后 遇到相同的問題能夠馬上定位到

改變按鈕內(nèi)部控件的位置

我們知道普通的按鈕都是圖片在左文字在右, 但是開發(fā)中我們經(jīng)常會遇到一些特殊的需求,比如上面列舉的圖片, 圖片在上文字在下的效果,這里我們就來總結一下常見的幾種實現(xiàn)方案吧

方案一:
重寫如下方法來對按鈕內(nèi)部的子控件進行布局:

- (CGRect)contentRectForBounds:(CGRect)bounds;
- (CGRect)titleRectForContentRect:(CGRect)contentRect;
- (CGRect)imageRectForContentRect:(CGRect)contentRect;

方案二:
重寫layoutSubviews方法,在該方法內(nèi)部對按鈕內(nèi)部的子控件進行布局:

- (void)layoutSubviews
{
    [super layoutSubviews];    
    CGFloat buttonW = self.frame.size.width;
    CGFloat buttonH = self.frame.size.height;    
    CGFloat imageH = buttonW - 10;
    self.imageView.frame = CGRectMake(0, 0, buttonW, imageH);    
    self.titleLabel.frame = CGRectMake(0, imageH, buttonW, buttonH - imageH);
    self.titleLabel.textAlignment = NSTextAlignmentCenter;
    self.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
    self.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
}

方案三:
該方案也是我個人比較喜歡的一種方案,其實就是直接操作titleEdgeInsetsimageEdgeInsets

1. 普通按鈕的樣子: 圖片在左,文字在右

普通按鈕

其實對應的代碼就是:

    self.btnScan.titleEdgeInsets = UIEdgeInsetsZero;
    self.btnScan.imageEdgeInsets = UIEdgeInsetsZero;

2. 文字圖片都居中顯示

    self.btnScan.titleEdgeInsets = UIEdgeInsetsMake(0, -self.btnScan.imageView.frame.size.width, 0, 0);
     self.btnScan.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, -self.btnScan.titleLabel.frame.size.width);

居中

3. 文字在左圖片在右

    self.btnScan.titleEdgeInsets = UIEdgeInsetsMake(0, -self.btnScan.imageView.frame.size.width - self.btnScan.frame.size.width + self.btnScan.titleLabel.intrinsicContentSize.width, 0, 0);
    self.btnScan.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, -self.btnScan.titleLabel.frame.size.width - self.btnScan.frame.size.width + self.btnScan.imageView.frame.size.width);
文字在左

4. 圖片在上,文字在下

    self.btnScan.titleEdgeInsets = UIEdgeInsetsMake(0, -self.btnScan.imageView.frame.size.width, -self.btnScan.imageView.frame.size.height, 0);
    self.btnScan.imageEdgeInsets = UIEdgeInsetsMake(-self.btnScan.titleLabel.intrinsicContentSize.height, 0, 0, -self.btnScan.titleLabel.intrinsicContentSize.width);
圖片在上

如果感覺距離有些近,我們可以調(diào)節(jié)間距

 CGFloat offset = 40.0f;
    self.btnScan.titleEdgeInsets = UIEdgeInsetsMake(0, -self.btnScan.imageView.frame.size.width, -self.btnScan.imageView.frame.size.height-offset/2, 0);
    self.btnScan.imageEdgeInsets = UIEdgeInsetsMake(-self.btnScan.titleLabel.intrinsicContentSize.height-offset/2, 0, 0, -self.btnScan.titleLabel.intrinsicContentSize.width);
image.png

設置按鈕的背景圖片

為了保證高亮狀態(tài)下的圖片正常顯示,必須設置按鈕的type為custom

UIButton *loginBtn = [UIButton buttonWithType:UIButtonTypeCustom];

讓按鈕無法點擊的2種方法

button.enabled = NO; //會進入UIControlStateDisabled狀態(tài)
button.userInteractionEnabled = NO; //不會進入UIControlStateDisabled狀態(tài),繼續(xù)保持當前狀態(tài)

設置按鈕背景圖片和圖片的區(qū)別

 // 設置背景圖片 圖片會被拉伸充滿整個btn.frame
[btn setBackgroundImage:[UIImage imageNamed:@""] forState:UIControlStateNormal];

// 設置按鈕上的圖片,圖片不會被拉伸,原比例顯示在btn.frame)
[btn setImage:[UIImage imageNamed:@""] forState:UIControlStateNormal];

點擊按鈕的時候是否會發(fā)光

// 當點擊按鈕的時候是否會發(fā)光
// default is NO. if YES, show a simple feedback (currently a glow) while highlighted.
btn.showsTouchWhenHighlighted=NO;

設置內(nèi)容、標題或者是圖標間距

//contentEdgeInsets  titleEdgeInsets  imageEdgeInsets
btn.contentEdgeInsets=UIEdgeInsetsMake(10,0,0,0);

設置按鈕字體大小

[btn.titleLabel setFont:[UIFont systemFontOfSize:18]];
 self.titleLabel.font = [UIFont boldSystemFontOfSize:22];

設置按鈕禁用或者高亮時候按鈕圖標是否變灰色

// default is YES. if YES, image is drawn darker when highlighted(pressed)
btn.adjustsImageWhenHighlighted=NO;
   
 // default is YES. if YES, image is drawn lighter when disabled
btn.adjustsImageWhenDisabled=NO;

九宮格的布局

九宮格

這里不討論用CollectionView實現(xiàn),主要就是一些簡單的計算來實現(xiàn)我們想要的效果:

    CGFloat shopW = 80;
    CGFloat shopH = 90;
    
    NSInteger index = self.shopsView.subviews.count;
    CGFloat margin = (self.shopsView.frame.size.width - shopW*columnNum)/(columnNum -1);
    
    //計算行和列
    NSInteger column = index % columnNum;
    NSInteger row = index / columnNum;
    
    //計算X和Y的值
    CGFloat shopX = column * (shopW + margin);
    CGFloat shopY = row * (shopH +margin);
    
    //創(chuàng)建View
    GSShopView *shopView = [[GSShopView alloc] init];   
    shopView.frame = CGRectMake(shopX, shopY, shopW, shopH);
    
    [self.shopsView addSubview:shopView];

字典轉模型

字典轉模型的過程最好封裝在模型內(nèi)部,同時模型應該提供一個可以傳入字典參數(shù)的構造方法

#import <Foundation/Foundation.h>

@interface GSShop : NSObject

/** 名稱*/
@property (nonatomic,copy) NSString *name;

/** 圖片*/
@property (nonatomic,copy) NSString *icon;

//instancetype:編譯器會檢測instancetype的真實類型
+ (instancetype)shopWithDict:(NSDictionary *)dic;
- (instancetype)initWithDict:(NSDictionary *)dic;
@end
#import "GSShop.h"

@implementation GSShop

+ (instancetype)shopWithDict:(NSDictionary *)dic{
    return [[self alloc] initWithDict:dic];
}

-(instancetype)initWithDict:(NSDictionary *)dic{
    if (self = [super init]) {
        self.name = dic[@"name"];
        self.icon = dic[@"icon"];
    }
    return self;
}
@end

封裝控件的基本步驟

  1. initWithFrame:方法中添加子控件,提供便利構造方法
  2. layoutSubviews方法中設置子控件的frame(一定要調(diào)用super的layoutSubviews)
  3. 增加模型屬性,在模型屬性set方法中設置數(shù)據(jù)到子控件上

這里以上面九宮格圖片為例子,封裝一個商品數(shù)據(jù)的代碼:

/**
 1.0 在該方法中初始化控件
 init方法內(nèi)部會自動調(diào)用initWithFrame:方法
 */
-(instancetype)initWithFrame:(CGRect)frame{
    if(self = [super initWithFrame:frame]){

        //1.0 創(chuàng)建icon
        UIImageView *iconView = [[UIImageView alloc] init];
        [self addSubview:iconView];
        self.iconView = iconView;

        //2.0 創(chuàng)建名稱
        UILabel *nameLabel = [[UILabel alloc] init];
        nameLabel.font = [UIFont systemFontOfSize:11];
        nameLabel.textAlignment = NSTextAlignmentCenter;
        [self addSubview:nameLabel];
        self.nameLabel = nameLabel;
    }
    return self;

}

//2.0 布局Frame
-(void)layoutSubviews{
    [super layoutSubviews];
    CGFloat width = self.frame.size.width;
    CGFloat height = self.frame.size.height;
    self.iconView.frame = CGRectMake(0, 0, width, width);
    self.nameLabel.frame = CGRectMake(0, width, width, height-width);
}

//3.0 給數(shù)據(jù)賦值
-(void)setShop:(GSShop *)shop{
    _shop = shop;
    self.iconView.image = [UIImage imageNamed:shop.icon];
    self.nameLabel.text = shop.name;
}

當然如果考慮到性能,我們也可以將使用的控件進行懶加載創(chuàng)建,這樣 使用到的時候才會去創(chuàng)建該控件,就不用在調(diào)用initWithFrame:方法了

#pragma mark 控件懶加載 這樣更加節(jié)約性能,用到的時候再去創(chuàng)建控件;
-(UIImageView *)iconView{
    if (!_iconView) {
        UIImageView *iconView = [[UIImageView alloc] init];
        [self addSubview:iconView];
        _iconView = iconView;
    }
    return _iconView;
}
-(UILabel *)nameLabel{
    if(!_nameLabel){
        UILabel *nameLabel = [[UILabel alloc] init];
        nameLabel.font = [UIFont systemFontOfSize:11];
        nameLabel.textAlignment = NSTextAlignmentCenter;
        [self addSubview:nameLabel];
        _nameLabel = nameLabel;
    }
    return  _nameLabel;
}

XIB封裝View

上面封裝控件是通過代碼來實現(xiàn)的,其實有時候我們利用XIB來封裝控件速度也是非常的快,這里我們來貼一下通過XIB封裝控件的代碼

#import <UIKit/UIKit.h>
@class GSShop;
@interface GSShopView2 : UIView

/**模型對象*/
@property (nonatomic, strong) GSShop *shop;

//為了讓外界在調(diào)用的時候方便可以提供兩個創(chuàng)建View的方法
+ (instancetype) shopViewWithShop:(GSShop *)shop;
+ (instancetype) shopView;
@end

#import "GSShopView2.h"
#import "GSShop.h"

@interface GSShopView2()
@property (weak, nonatomic) IBOutlet UIImageView *iconView;
@property (weak, nonatomic) IBOutlet UILabel *nameLabel;

@end
@implementation GSShopView2

+(instancetype)shopView{
    return [self shopViewWithShop:nil];
}

+(instancetype)shopViewWithShop:(GSShop *)shop{
    //加載xib文件
   GSShopView2 *shopView =  [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self) owner:nil options:nil] lastObject];
    shopView.shop = shop;
    return  shopView;
}

-(void)setShop:(GSShop *)shop{
    _shop = shop;
    self.iconView.image = [UIImage imageNamed:shop.icon];
    self.nameLabel.text = shop.name;
}
@end

注意點
一個控件有2種創(chuàng)建方式

  • 通過代碼創(chuàng)建
    初始化時一定會調(diào)用initWithFrame:方法

  • 通過xib\storyboard創(chuàng)建
    初始化時不會調(diào)用initWithFrame:方法,只會調(diào)用initWithCoder:方法,初始化完畢后會調(diào)用awakeFromNib方法

所以當我們封裝一個控件給別人使用的時候,最好是如下操作,這樣不管是通過代碼還是xib都可以


-(instancetype)initWithFrame:(CGRect)frame{
    if (self = [super initWithFrame:frame]) {
        [self setupUI];
    }
    return self;
}
-(void)awakeFromNib{
    [self setupUI];
}
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結構(3).初始化時...
    歐辰_OSR閱讀 30,194評論 8 265
  • 1、通過CocoaPods安裝項目名稱項目信息 AFNetworking網(wǎng)絡請求組件 FMDB本地數(shù)據(jù)庫組件 SD...
    陽明AI閱讀 16,172評論 3 119
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,621評論 1 32
  • 揮手 離影逝去 回首 不堪回憶 那熟悉的地方 似有飄雪 落在心上 是誰 負了誓言 消失在 我的天際 從此 睡夢里 ...
    習慣不哭閱讀 157評論 0 1
  • 今天又開始做項目了,第二次做比第一次做肯定是成長了很多,懂得也多了些,同學之間的配合程度也較上次有了更大的進展和突...
    Cyril丶閱讀 236評論 0 0

友情鏈接更多精彩內(nèi)容