iOS開發之設置界面的抽取

幾乎每款app都會有一個設置的界面!!!安全

那麼咱們的設置界面到底要怎麼寫才能最方便使用呢?下面我就來講說個人想法。app

1.觀察原型圖post

2.找出相同的東西,目的是抽出一個基類模塊,只要我寫好了這個控制器,其它的界面所有都寫好了字體

3.判斷是用純代碼仍是storyboard,若是界面的控件位置都是固定,用storyboard。atom

何時用靜態單元格:若是界面cell跟系統自帶的cell徹底差很少,就能夠選擇靜態單元格spa

若是不類似:code

1.判斷其它cell是否所有差很少,若是所有差很少,可使用靜態單元格orm

2.若是界面差異很大,就不使用靜態單元格,就用代碼server

而後要注意一點的就是循環利用的問題了blog

若是一個控件,常常循環利用,就不能在給這個控件屬性賦值的時候,添加它的子控件,應該在初始化這個控件的時候把全部的子控件加上去

注意在循環利用的時候,只要有if就必定要有else,else作的事情就是把以前的狀態清空,就是還原最開始的狀態。

那麼下面咱們就來抽取設置界面:

首先繼承UITableViewController寫一個BasicSettingViewController
.h
//這一組有多少行cell<SettingItem>
@property (nonatomic, strong) NSMutableArray *groups;
.m
#import "BasicTableViewController.h"
#import "GroupItem.h"
#import "SettingItem.h"
#import "BasicCell.h"

@interface BasicTableViewController ()

@end

@implementation BasicTableViewController

//讓這個類一初始化就是組樣式的
- (instancetype)init { return [self initWithStyle:UITableViewStyleGrouped]; } - (void)viewDidLoad { [super viewDidLoad];
//設置tableView的一些基本信息 self.tableView.backgroundColor
= [UIColor colorWithRed:211 green:211 blue:211 alpha:1]; self.tableView.sectionHeaderHeight = 10; self.tableView.sectionFooterHeight = 0; self.tableView.contentInset = UIEdgeInsetsMake(-25, 0, 0, 0); self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; } //必定要對組進行懶加載,否則的話,子類是沒有辦法初始化他的 - (NSMutableArray *)groups { if (!_groups) { _groups = [NSMutableArray array]; } return _groups; } #pragma mark - Table view data source //返回組數 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { #warning Incomplete implementation, return the number of sections return self.groups.count; } //返回行數 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { #warning Incomplete implementation, return the number of rows GroupItem *group = self.groups[section]; return group.items.count; } //初始化cell並給cell賦值 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { BasicCell *cell = [BasicCell cellWithTableView:tableView]; GroupItem *group = self.groups[indexPath.section]; SettingItem *item = group.items[indexPath.row]; cell.item = item; [cell setIndexPath:indexPath rowCount:group.items.count]; return cell; } //返回腳部標題 - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { GroupItem *group = self.groups[section]; return group.footTitle; } //返回頭部標題 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { GroupItem *group = self.groups[section]; return group.headTitle; } //當cell選中的時候執行該方法 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; GroupItem *group = self.groups[indexPath.section]; SettingItem *item = group.items[indexPath.row]; if (item.destVc) {//若是有跳轉就執行跳轉 UIViewController *destVc = [[item.destVc alloc] init]; [self.navigationController pushViewController:destVc animated:YES]; } if (item.option) {//哪一個cell有事情就作事情(本身的事情本身幹) item.option(); } }

設置組模型(基類):

@interface GroupItem : NSObject
//每一組的行數
@property (nonatomic, strong) NSArray *items;
//頭標題
@property (nonatomic, copy) NSString *headTitle;
//腳標題
@property (nonatomic, copy) NSString *footTitle;

@end
typedef void (^SettingItemOption) ();

@interface SettingItem : NSObject
//左邊神圖
@property (nonatomic, strong) UIImage *image;
//標題
@property (nonatomic, copy) NSString *title;
//子標題
@property (nonatomic, copy) NSString *subTitle;
@property (nonatomic, assign) Class destVc;//跳轉到目標控制器(最好不要用NSString)
@property (nonatomic, copy) SettingItemOption option;//在ARC模型下只能使用copy,MRC可使用copy或者strong,爲了把他放到堆內存中,若是放在棧內存中會被釋放

//提供兩個建立的item的方法
+ (instancetype)itemWithTitle:(NSString *)title;
+ (instancetype)itemWithTitle:(NSString *)title image:(UIImage *)image;

@end

由於內容是根據模型的改變而改變,那麼咱們就建立幾個模型(繼承於SettingItem):

每一個基類要是有本身特有的一些屬性也能夠設置

@interface ArrowItem : SettingItem

@end
@interface BadgeItem : SettingItem

@property (nonatomic, copy) NSString *badgeValue;

@end
@interface SwitchItem : SettingItem

@property (nonatomic, assign) BOOL isOn;//是否打開

@end
@interface LabelItem : SettingItem

@property (nonatomic, copy) NSString *text;//label上面的text

@end
@interface CheakItem : SettingItem

@property (nonatomic, assign) BOOL isCheak;//是否打勾

@end

 

設置的cell(基類):

@class SettingItem;

@interface BasicCell : UITableViewCell
//根據settingItem模型來顯示內容
@property (nonatomic, strong) SettingItem *item;
//給外部提供一個建立cell的方法
+ (instancetype)cellWithTableView:(UITableView *)tableView;
//設置每一組的背景圖片的方法
- (void)setIndexPath:(NSIndexPath *)indexPath rowCount:(NSInteger)rowCount; @end
@interface BasicCell ()
//這裏必定要用strong,由於是加在視圖上面而不是加在contentView;
//箭頭格式的cell
@property (nonatomic, strong) UIImageView *arrowView;
//開關格式的cell
@property (nonatomic, strong) UISwitch *switchView;
//打勾格式的cell
@property (nonatomic, strong) UIImageView *cheakView;
//label格式的cell
@property (nonatomic, weak) UILabel *labelView;

@end

//不變形的拉伸圖片(通常要是寫項目最好寫成category)
@implementation UIImage (Resizable)

+ (UIImage *)resizableWithImageName:(NSString *)imageName {
    UIImage *image = [UIImage imageNamed:imageName];
    return [image stretchableImageWithLeftCapWidth:image.size.width/2 topCapHeight:image.size.height/2];
}

@end

@implementation BasicCell

#pragma mark - 對全部的控件懶加載

- (UIImageView *)arrowView
{
    if (_arrowView == nil) {
        _arrowView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"common_icon_arrow"]];
    }
    return _arrowView;
}

- (UISwitch *)switchView
{
    if (_switchView == nil) {
        _switchView = [[UISwitch alloc] init];
        [_switchView addTarget:self action:@selector(switchChange:) forControlEvents:UIControlEventValueChanged];
        
    }
    return _switchView;
}

- (UIImageView *)cheakView
{
    if (_cheakView == nil) {
        _cheakView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"common_icon_checkmark"]];
    }
    return _cheakView;
}

- (UILabel *)labelView {
    if (!_labelView) {
        UILabel *labelView = [[UILabel alloc] initWithFrame:self.bounds];
        labelView.textAlignment = NSTextAlignmentCenter;
        labelView.textColor = [UIColor redColor];
        [self.contentView addSubview:labelView];
        _labelView = labelView;
    }
    return _labelView;
}

#pragma mark - switchChange
- (void)switchChange:(UISwitch *)switchView {
    
}

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
//只須要設置一次的東西最好放到這個方法中執行,由於這個方法只會在建立cell的時候執行一次,而不會每次給模型賦值的時候都會執行 self.detailTextLabel.font
= [UIFont systemFontOfSize:14]; self.backgroundColor = [UIColor clearColor]; self.backgroundView = [[UIImageView alloc] init]; self.selectedBackgroundView = [[UIImageView alloc] init]; } return self; } + (instancetype)cellWithTableView:(UITableView *)tableView { static NSString *ID = @"cell"; BasicCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; if (!cell) { //這裏必定要用self cell = [[self alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:ID]; } return cell; } - (void)setItem:(SettingItem *)item { _item = item; //設置數據 [self setUpData]; //設置模型 [self setUpRightView]; } - (void)setUpData { self.textLabel.text = _item.title; self.detailTextLabel.text = _item.subTitle; self.imageView.image = _item.image; } - (void)setUpRightView { if ([_item isKindOfClass:[ArrowItem class]]) { //箭頭 self.accessoryView = self.arrowView; } else if ([_item isKindOfClass:[BadgeItem class]]) { //badgeView self.accessoryView = self.badgeView; } else if ([_item isKindOfClass:[SwitchItem class]]) { //開關 self.accessoryView = self.switchView; } else if ([_item isKindOfClass:[LabelItem class]]) { //Label LabelItem *labelItem = (LabelItem *)_item; UILabel *label = self.labelView; label.text = labelItem.text; } else if ([_item isKindOfClass:[CheakItem class]]) { //打勾 CheakItem *cheakItem = (CheakItem *)_item; if (cheakItem.isCheak) { self.accessoryView = self.cheakView; } else { self.accessoryView = nil; } } else { [_labelView removeFromSuperview]; _labelView = nil; self.accessoryView = nil; } } - (void)setIndexPath:(NSIndexPath *)indexPath rowCount:(NSInteger)rowCount { UIImageView *bgView = (UIImageView *)self.backgroundView; UIImageView *selBgView = (UIImageView *)self.selectedBackgroundView; if (rowCount == 1) { // 只有一行 bgView.image = [UIImage resizableWithImageName:@"common_card_background"]; selBgView.image = [UIImage resizableWithImageName:@"common_card_background_highlighted"]; }else if(indexPath.row == 0){ // 頂部cell bgView.image = [UIImage resizableWithImageName:@"common_card_top_background"]; selBgView.image = [UIImage resizableWithImageName:@"common_card_top_background_highlighted"]; }else if (indexPath.row == rowCount - 1){ // 底部 bgView.image = [UIImage resizableWithImageName:@"common_card_bottom_background"]; selBgView.image = [UIImage resizableWithImageName:@"common_card_bottom_background_highlighted"]; }else{ // 中間 bgView.image = [UIImage resizableWithImageName:@"common_card_middle_background"]; selBgView.image = [UIImage resizableWithImageName:@"common_card_middle_background_highlighted"]; } } #pragma mark - 這裏寫才能居中對齊 - (void)layoutSubviews { [super layoutSubviews]; _labelView.frame = self.bounds; }

到此,全部的都已經抽出來了。你可能想問了那要麼是子類和父類長的很像可是卻不同怎麼辦?那麼就能用到OC中繼承的這個性質了,子類只要重寫一下父類的方法就能夠了。

隨便寫幾個控制器,繼承於BasicSettingViewController

個人界面

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self setUpNav];
    [self setUpGroup0];
    [self setUpGroup1];
    [self setUpGroup2];
    [self setUpGroup3];
}

- (void)setUpNav {
    UIBarButtonItem *setting = [[UIBarButtonItem alloc] initWithTitle:@"設置" style:UIBarButtonItemStylePlain target:self action:@selector(setting)];
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    dict[NSForegroundColorAttributeName] = [UIColor blackColor];
    [setting setTitleTextAttributes:dict forState:UIControlStateNormal];
    self.navigationItem.rightBarButtonItem = setting;
}

#pragma mark - 設置

- (void)setting {
    SettingViewController *setVc = [[SettingViewController alloc] init];
    [self.navigationController pushViewController:setVc animated:YES];
}

- (void)setUpGroup0
{
    // 新的好友
    ArrowItem *friend = [ArrowItem itemWithTitle:@"新的好友" image:[UIImage imageNamed:@"new_friend"]];
    
    GroupItem *group = [[GroupItem alloc] init];
    group.items = @[friend];
    [self.groups addObject:group];
}
- (void)setUpGroup1
{
    // 個人相冊
    ArrowItem *album = [ArrowItem itemWithTitle:@"個人相冊" image:[UIImage imageNamed:@"album"]];
    album.subTitle = @"(12)";
    
    // 個人收藏
    ArrowItem *collect = [ArrowItem itemWithTitle:@"個人收藏" image:[UIImage imageNamed:@"collect"]];
    collect.subTitle = @"(0)";
    
    //
    ArrowItem *like = [ArrowItem itemWithTitle:@"" image:[UIImage imageNamed:@"like"]];
    like.subTitle = @"(0)";
    GroupItem *group = [[GroupItem alloc] init];
    group.items = @[album,collect,like];
    [self.groups addObject:group];
}
- (void)setUpGroup2{
    // 微博支付
    ArrowItem *pay = [ArrowItem itemWithTitle:@"微博支付" image:[UIImage imageNamed:@"pay"]];
    // 個性化
    ArrowItem *vip = [ArrowItem itemWithTitle:@"個性化" image:[UIImage imageNamed:@"vip"]];
    vip.subTitle = @"微博來源、皮膚、封面圖";
    GroupItem *group = [[GroupItem alloc] init];
    group.items = @[pay,vip];
    [self.groups addObject:group];
}
- (void)setUpGroup3
{
    // 個人二維碼
    ArrowItem *card = [ArrowItem itemWithTitle:@"個人二維碼" image:[UIImage imageNamed:@"card"]];
    // 草稿箱
    ArrowItem *draft = [ArrowItem itemWithTitle:@"草稿箱" image:[UIImage imageNamed:@"draft"]];
    
    GroupItem *group = [[GroupItem alloc] init];
    group.items = @[card,draft];
    [self.groups addObject:group];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    ProfileCell *cell = [ProfileCell cellWithTableView:tableView];
    GroupItem *group = self.groups[indexPath.section];
    SettingItem *item = group.items[indexPath.row];
    cell.item = item;
    [cell setIndexPath:indexPath rowCount:group.items.count];
    return cell;
}

由於cell和父類不太同樣,因此cell要繼承於BasicCell重寫一下

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
        self.detailTextLabel.font = [UIFont systemFontOfSize:12];
    }
    return self;
}
//必定要在這個方法中重寫,否則可能會沒用,這個是在加載完成即將顯示的時候調用,加載的frame是100%正確的
- (void)layoutSubviews {
    [super layoutSubviews];
    CGRect frame = self.detailTextLabel.frame;
    frame.origin.x = CGRectGetMaxX(self.textLabel.frame) + 5;
    self.detailTextLabel.frame = frame;
}

 

設置界面

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    // 添加第0組
    [self setUpGroup0];
    // 添加第1組
    [self setUpGroup1];
    // 添加第2組
    [self setUpGroup2];
    // 添加第3組
    [self setUpGroup3];
}

- (void)setUpGroup0
{
    // 帳號管理
    ArrowItem *account = [ArrowItem itemWithTitle:@"帳號管理"];
//    account.badgeValue = @"8";
    GroupItem *group = [[GroupItem alloc] init];
    group.items = @[account];
    [self.groups addObject:group];
}
- (void)setUpGroup1
{
    // 提醒和通知
    ArrowItem *notice = [ArrowItem itemWithTitle:@"個人相冊" ];
    // 通用設置
    ArrowItem *setting = [ArrowItem itemWithTitle:@"通用設置" ];
    setting.destVc = [CommonViewController class];
    // 隱私與安全
    ArrowItem *secure = [ArrowItem itemWithTitle:@"隱私與安全" ];
    
    GroupItem *group = [[GroupItem alloc] init];
    group.items = @[notice,setting,secure];
    [self.groups addObject:group];
}
- (void)setUpGroup2{
    // 意見反饋
    ArrowItem *suggest = [ArrowItem itemWithTitle:@"意見反饋" ];
    // 關於微博
    ArrowItem *about = [ArrowItem itemWithTitle:@"關於微博"];
    GroupItem *group = [[GroupItem alloc] init];
    group.items = @[suggest,about];
    [self.groups addObject:group];
}
- (void)setUpGroup3
{
    // 帳號管理
    LabelItem *layout = [[LabelItem alloc] init];
    layout.text = @"退出當前帳號";
    
    GroupItem *group = [[GroupItem alloc] init];
    group.items = @[layout];
    [self.groups addObject:group];
}

通用設置界面

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    // 添加第0組
    [self setUpGroup0];
    // 添加第1組
    [self setUpGroup1];
    // 添加第2組
    [self setUpGroup2];
    // 添加第3組
    [self setUpGroup3];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refresh:) name:@"FontSizeChangeNote" object:nil];
}

- (void)refresh:(NSNotification *)notification {
    _fontSize.subTitle = notification.userInfo[FontSizeKey];
    [self.tableView reloadData];
}

- (void)setUpGroup0
{
    // 閱讀模式
    SettingItem *read = [SettingItem itemWithTitle:@"閱讀模式"];
    read.subTitle = @"有圖模式";
    
    // 字體大小
    SettingItem *fontSize = [SettingItem itemWithTitle:@"字體大小"];
    _fontSize = fontSize;
    NSString *fontSizeStr =  [[NSUserDefaults standardUserDefaults] objectForKey:FontSizeKey];
    if (fontSizeStr == nil) {
        fontSizeStr = @"";
    }
    fontSize.subTitle = fontSizeStr;
    fontSize.destVc = [FontViewController class];
    
    // 顯示備註
    SwitchItem *remark = [SwitchItem itemWithTitle:@"顯示備註"];
    
    
    GroupItem *group = [[GroupItem alloc] init];
    group.items = @[read,fontSize,remark];
    [self.groups addObject:group];
}
- (void)setUpGroup1
{
    // 圖片質量
    ArrowItem *quality = [ArrowItem itemWithTitle:@"圖片質量" ];
    GroupItem *group = [[GroupItem alloc] init];
    group.items = @[quality];
    [self.groups addObject:group];
}
- (void)setUpGroup2{
    // 聲音
    SwitchItem *sound = [SwitchItem itemWithTitle:@"聲音" ];
    
    GroupItem *group = [[GroupItem alloc] init];
    group.items = @[sound];
    [self.groups addObject:group];
}
- (void)setUpGroup3
{
    // 多語言環境
    SettingItem *language = [SettingItem itemWithTitle:@"多語言環境"];
    language.subTitle = @"跟隨系統";
    GroupItem *group = [[GroupItem alloc] init];
    group.items = @[language];
    [self.groups addObject:group];
}

字體大小界面

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self setUpGroup0];
}

- (void)setUpGroup0
{
    
#pragma mark - 這種方法能消除block中的循環警告
    //
    __weak typeof(self) weakSelf = self;
     CheakItem * __weak big = [CheakItem itemWithTitle:@""];
    big.option = ^{
        [weakSelf selItem:big];
    };
    
    //
    CheakItem * __weak middle = [CheakItem itemWithTitle:@""];
    
    middle.option = ^{
        [weakSelf selItem:middle];
    };
    _selCheakItem = middle;
    //
    CheakItem * __weak small = [CheakItem itemWithTitle:@""];
    small.option = ^{
        [weakSelf selItem:small];
    };
    GroupItem *group = [[GroupItem alloc] init];
    group.headTitle = @"上傳圖片質量";
    group.items = @[big,middle,small];
    [self.groups addObject:group];
    
    // 默認選中item
    [self setUpSelItem:middle];
    
}

- (void)setUpSelItem:(CheakItem *)item
{
    NSString *fontSizeStr =  [[NSUserDefaults standardUserDefaults] objectForKey:FontSizeKey];
    if (fontSizeStr == nil) {
        [self selItem:item];
        return;
    }
    
    for (GroupItem *group in self.groups) {
        for (CheakItem *item in group.items) {
            if ( [item.title isEqualToString:fontSizeStr]) {
                [self selItem:item];
            }
            
        }
        
    }
}

- (void)selItem:(CheakItem *)item
{
    _selCheakItem.isCheak = NO;
    item.isCheak = YES;
    _selCheakItem = item;
    [self.tableView reloadData];
    
    
    // 存儲
    [[NSUserDefaults standardUserDefaults] setObject:item.title forKey:FontSizeKey];
    [[NSUserDefaults standardUserDefaults] synchronize];
    
    // 發出通知
    [[NSNotificationCenter defaultCenter] postNotificationName:@"FontSizeChangeNote" object:nil userInfo:@{FontSizeKey:item.title}];
    
}

 具體也能夠下載的個人上傳的DEMO看一下,http://i.cnblogs.com/Files.aspx

相關文章
相關標籤/搜索