App裡『設定』模組,通用配置
阿新 • • 發佈:2019-01-30
我們知道常見的App裡,『設定』這一塊都長的差不多,都是表格展示,我們是否可以靈活配置cell呢?
我們可以寫一個基礎的類,來實現常見功能。
1.現在看結構
model說明:我們的表格是分組樣式,模型裡一個item就對應表格的一個cell, 一個group裡有多個item。
2.cell模型程式碼:
// // SettingItem.h // 表格每一個cell對應一個SettingItem模型 #import <Foundation/Foundation.h> /** * 定義一個block型別 */ typedef void (^SettingItemOption)(); @interface SettingItem : NSObject /** * cell上的圖示 */ @property(nonatomic,copy)NSString *icon; /** * cell標題 */ @property(nonatomic,copy)NSString *title; /** * 子標題 */ @property(nonatomic,copy)NSString *subtitle; /** * 點選那個cell需要做什麼事情 */ @property(nonatomic,copy) SettingItemOption option; /** * 返回一個cell(圖示和大標題) * * @param icon 圖示 * @param title 大標題 */ + (instancetype) itemWithIcon:(NSString *)icon title:(NSString *)title; /** * 返回一個cell(只有大標題) */ + (instancetype)itemWithTitle:(NSString *)title; /** * 返回一個cell * * @param icon 圖示 * @param title 大標題 * @param subtitle 子標題 */ + (instancetype) itemWithIcon:(NSString *)icon title:(NSString *)title subtitle:(NSString *)subtitle; @end
3.組模型程式碼:// // SettingItem.m #import "SettingItem.h" @implementation SettingItem + (instancetype) itemWithIcon:(NSString *)icon title:(NSString *)title subtitle:(NSString *)subtitle { SettingItem *item = [[self alloc]init]; item.icon = icon; item.title = title; item.subtitle = subtitle; return item; } + (instancetype) itemWithIcon:(NSString *)icon title:(NSString *)title { return [self itemWithIcon:icon title:title subtitle:nil]; } + (instancetype)itemWithTitle:(NSString *)title { return [self itemWithIcon:nil title:title subtitle:nil]; } @end
// // SettingGroup.h // 『設定模組』裡表格組模型 #import <Foundation/Foundation.h> @interface SettingGroup : NSObject /** * 組頭部標題 */ @property(nonatomic,copy)NSString *header; /** * 組尾部標題 */ @property(nonatomic,copy)NSString *footer; /** * 該組所有模型資料(SettingItem物件) */ @property(nonatomic,copy)NSArray *items; @end
//
// SettingGroup.m
#import "SettingGroup.h"
@implementation SettingGroup
@end
4.其他幾個繼承自SettingItem的子分類(不同形式的cell)
//
// SettingArrowItem.h
// cell模型(cell右側展示箭頭的)
#import "SettingItem.h"
@interface SettingArrowItem : SettingItem
/**
* 點選這行cell要跳轉的控制器
*/
@property(nonatomic,assign) Class destClass;
/**
* 返回一個cell(點選這個cell要跳轉)
*
* @param icon 圖示
* @param title 標題
* @param subtitle 子標題
* @param destClass 要跳轉過去的目標控制器
*/
+ (instancetype) itemWithIcon:(NSString *)icon title:(NSString *)title subtitle:(NSString *)subtitle destClass:(Class)destClass;
/**
* 返回一個點選可以跳轉的cell
*
* @param icon 圖示
* @param title 標題
* @param destClass 要跳轉過去的目標控制器
*/
+ (instancetype) itemWithIcon:(NSString *)icon title:(NSString *)title destClass:(Class)destClass;
/**
* 返回一個點選可以跳轉的cell
*
* @param title 標題
* @param destClass 要跳轉過去的目標控制器
*/
+ (instancetype) itemWithTitle:(NSString *)title destClass:(Class)destClass;
@end
//
// SettingArrowItem.m
// 高考志願填報指南
#import "SettingArrowItem.h"
@implementation SettingArrowItem
+ (instancetype) itemWithIcon:(NSString *)icon title:(NSString *)title subtitle:(NSString *)subtitle destClass:(__unsafe_unretained Class)destClass
{
SettingArrowItem *item = [self itemWithIcon:icon title:title subtitle:subtitle];
item.destClass = destClass;
return item;
}
+ (instancetype) itemWithIcon:(NSString *)icon title:(NSString *)title destClass:(__unsafe_unretained Class)destClass
{
SettingArrowItem *item = [self itemWithIcon:icon title:title subtitle:nil destClass:destClass];
return item;
}
+ (instancetype) itemWithTitle:(NSString *)title destClass:(Class)destClass
{
return [self itemWithIcon:nil title:title subtitle:nil destClass:destClass];
}
@end
//
// SettingSwitchItem.h
// cell模型(cell上要展示Switch開關的)
#import "SettingItem.h"
@interface SettingSwitchItem : SettingItem
@end
//
// SettingSwitchItem.m
// 高考志願填報指南
#import "SettingSwitchItem.h"
@implementation SettingSwitchItem
@end
//
// SettingLabelItem.h
// cell模型(右邊是一個Label,不是箭頭,不是Switch開關)
#import "SettingItem.h"
@interface SettingLabelItem : SettingItem
@end
//
// SettingLabelItem.m
#import "SettingLabelItem.h"
@implementation SettingLabelItem
@end
5.cell檢視
//
// SettingCell.h
// 『設定模組』cell檢視
#import <UIKit/UIKit.h>
@class SettingItem;
@interface SettingCell : UITableViewCell
/**
* 這個屬性用於接收外界傳遞給cell的模型資料
*/
@property(nonatomic,strong) SettingItem *item;
/**
* 快速建立一個cell的方法
*/
+(instancetype)cellWithTableView:(UITableView *)tableView;
@end
//
// SettingCell.m
#import "SettingCell.h"
#import "SettingItem.h"
#import "SettingArrowItem.h"
#import "SettingSwitchItem.h"
#import "SettingLabelItem.h"
@interface SettingCell()
// UI控制元件要實時保留,所以用 strong
@property(nonatomic,strong)UIImageView *arrowView;
@property(nonatomic,strong)UISwitch *switchView;
@property(nonatomic,strong)UILabel *labelView;
@end
@implementation SettingCell
/**
* 懶載入建立arrowView控制元件
*/
- (UIImageView *)arrowView
{
if (_arrowView == nil) {
_arrowView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"CellArrow"]];
}
return _arrowView;
}
/**
* 懶載入建立switchView控制元件
*/
- (UILabel *)labelView
{
if (_labelView == nil) {
_labelView = [[UILabel alloc]init];
_labelView.bounds = CGRectMake(0, 0, 100, 30);
_labelView.backgroundColor = [UIColor redColor];
}
return _labelView;
}
/**
* 懶載入建立switchView控制元件
*/
- (UISwitch *)switchView
{
if (_switchView == nil) {
_switchView = [[UISwitch alloc]init];
[_switchView addTarget:self action:@selector(switchStateChange) forControlEvents:UIControlEventValueChanged];
}
return _switchView;
}
/**
* 監聽swicth開關狀態的改變
*/
- (void)switchStateChange
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:self.switchView.isOn forKey:self.item.title];
[defaults synchronize];
}
/**
* 提供一個建立cell的類方法
*/
+(instancetype)cellWithTableView:(UITableView *)tableView
{
static NSString *ID = @"setting";
SettingCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (cell == nil) {
cell = [[SettingCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:ID];
}
return cell;
}
/**
* 重寫item屬性,設定cell上的資料
*/
- (void)setItem:(SettingItem *)item
{
_item = item;
//1.設定資料
[self setupData];
//2.設定cell右邊的內容(箭頭)
[self setupRightContent];
}
/**
* 給cell設定資料
*/
- (void)setupData
{
if (self.item.icon) {
self.imageView.image = [UIImage imageNamed:self.item.icon];
}
self.textLabel.text = self.item.title;
self.detailTextLabel.text = self.item.subtitle;
}
/**
* 給cell設定右邊的樣式(箭頭)
*/
- (void)setupRightContent
{
if ([self.item isKindOfClass:[SettingArrowItem class]]) { //箭頭
// self.accessoryView = self.arrowView;
// 如果沒有自定義箭頭,使用系統預設的
self.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
self.selectionStyle = UITableViewCellSelectionStyleDefault;
}else if ([self.item isKindOfClass:[SettingSwitchItem class]]){ //開關
self.accessoryView = self.switchView;
//如果是開關該cell不能有點選樣式
self.selectionStyle = UITableViewCellSelectionStyleNone;
//設定開關狀態
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
self.switchView.on = [defaults boolForKey:self.item.title];
}else if ([self.item isKindOfClass:[SettingLabelItem class]]){ //標籤
self.accessoryView = self.labelView;
self.selectionStyle = UITableViewCellSelectionStyleDefault;
}else{
self.accessoryView = nil;
}
}
@end
6.控制器
//
// BaseSettingViewController.h
// 專案常見"設定模組"基礎類
#import <UIKit/UIKit.h>
@interface BaseSettingViewController : UITableViewController
/**
* 資料來源
*/
@property(nonatomic,strong)NSMutableArray *dataSources;
@end
//
// BaseSettingViewController.m
#import "BaseSettingViewController.h"
#import "SettingGroup.h"
#import "SettingItem.h"
#import "SettingSwitchItem.h"
#import "SettingArrowItem.h"
#import "SettingCell.h"
@interface BaseSettingViewController ()
@end
@implementation BaseSettingViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// 1.設定表格背景色
self.tableView.backgroundView = nil;
self.tableView.backgroundColor = [UIColor colorWithRed:240/255.0 green:240/255.0 blue:240/255.0 alpha:1.0];
}
/**
* 懶載入建立資料來源陣列
*/
- (NSMutableArray *)dataSources
{
if (_dataSources == nil) {
_dataSources = [NSMutableArray array];
}
return _dataSources;
}
/**
* 初始化tablView的樣式
*/
- (instancetype)init
{
/*
UITableViewStylePlain, 普通樣式
UITableViewStyleGrouped 分組樣式
*/
return [super initWithStyle:UITableViewStyleGrouped];
}
/**
* 初始化tableView的樣式(也有可能呼叫這個方法)
*/
- (instancetype)initWithStyle:(UITableViewStyle)style
{
return [super initWithStyle:UITableViewStyleGrouped];
}
#pragma mark - Table view data source
/**
* 有多少組
*/
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.dataSources.count;
}
/**
* 該組裡面有多少行
*/
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
SettingGroup *group = self.dataSources[section];
return group.items.count;
}
/**
* 返回UITableViewCell
*/
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 1.建立cell
SettingCell *cell = [SettingCell cellWithTableView:tableView];
// 2.給cell傳遞模型資料
SettingGroup *group = self.dataSources[indexPath.section];
SettingItem *item = group.items[indexPath.row];
cell.item = item;
// 3.返回cell
return cell;
}
/**
* 設定組頭部標題
*/
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
SettingGroup *group = self.dataSources[section];
return group.header;
}
/**
* 設定組尾部標題
*/
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
{
SettingGroup *group = self.dataSources[section];
return group.footer;
}
#pragma mark - 代理方法
/**
* 點選了cell會呼叫
*/
-(void)tableView:(UITableView *)tableView <span style="font-family: Arial, Helvetica, sans-serif;">didSelectRowAtIndexPath</span>:(NSIndexPath *)indexPath
{
// 0.取消cell選中樣式(預設cell選中會變灰)
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// 1.拿到模型
SettingGroup *group = self.dataSources[indexPath.section];
SettingItem *item = group.items[indexPath.row];
if (item.option) { //block有值,點選這個cell有特定的操作執行
item.option();
}
//需要跳轉的控制器
if ([item isKindOfClass:[SettingArrowItem class]]) { //箭頭
SettingArrowItem *arrowItem = (SettingArrowItem *)item;
if (arrowItem.destClass == nil) return;
UIViewController *vc = [[arrowItem.destClass alloc]init];
vc.title = arrowItem.title;
[self.navigationController pushViewController:vc animated:YES];
}
}
@end
自從,一個基礎的可以通用的設定模組就完成了。
那麼,在我們的專案裡,應該如何使用呢?
1.我們需要建立一個繼承自BaseSettingViewController的控制器
//
// SettingViewController.h
#import "BaseSettingViewController.h"
@interface SettingViewController : BaseSettingViewController
@end
2.然後在viewDidLoad初始化資料來源://
// SettingViewController.m
#import "SettingViewController.h"
#import "SettingItem.h"
#import "SettingSwitchItem.h"
#import "SettingArrowItem.h"
#import "SettingGroup.h"
#import "SettingCell.h"
@interface SettingViewController ()
@end
@implementation SettingViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// 1.設定當前控制器標題
self.title = @"設定";
// 2.新增要資料
[self setupGroup0];
}
/**
* 第0組資料
*/
- (void)setupGroup0
{
// 1.設定cell模型
SettingItem *item0 = [SettingArrowItem itemWithIcon:@"subject-of-attention_icon" title:@"科目"];
SettingItem *item1 = [SettingSwitchItem itemWithIcon:@"subject-of-attention_icon" title:@"搖一搖機選" ];
SettingItem *item2 = [SettingSwitchItem itemWithIcon:@"subject-of-attention_icon" title:@"聲音效果" ];
// 2.把cell模型新增到組
SettingGroup *group = [[SettingGroup alloc]init];
group.items = @[item0,item1,item2];
// 3.把組模型新增到資料來源
[self.dataSources addObject:group];
}
@end
dataSource裡裝的是組模型資料,組資料裡裝的是item模型資料。
這裡值添加了一組陣列,如果要新增第二組資料,照例配置,先把item加到group,再把group加到dataSoures
效果展示: