那麼我們的設置界面到底要怎麼寫才能最方便使用呢?下面我就來說說我的想法。 1.觀察原型圖 2.找出相同的東西,目的是抽出一個基類模塊,只要我寫好了這個控制器,其它的界面全部都寫好了 3.判斷是用純代碼還是storyboard,如果界面的控件位置都是固定,用storyboard。 什麼時候用靜態單元格:如果界面cell跟系統自帶的cell完全差不多,就可以選擇靜態單元格 如果不相似: 1.判斷其它cell是否全部差不多,如果全部差不多,可以使用靜態單元格 2.如果界面差別很大,就不使用靜態單元格,就用代碼 那麼下面我們就來抽取設置界面: 首先繼承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}]; }