iOS_25_彩票設置的cell的數據源模型的封裝
來源:程序員人生 發布時間:2014-09-19 14:20:15 閱讀次數:2530次
組模型的封裝
SettingGroup
//
// SettingGroup.h
// 25_彩票
//
// Created by beyond on 14-8-28.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// 模型,一組(Section,Group),包括 組的header,組的footer,中間的條目(cell數組)
#import <Foundation/Foundation.h>
@interface SettingGroup : NSObject
// 頭部標題
@property (nonatomic, copy) NSString *header;
// 中間的條目(SettingItem對象數組)
@property (nonatomic, strong) NSArray *items;
// 尾部標題
@property (nonatomic, copy) NSString *footer;
@end

父類SettingItem
//
// SettingItem.h
// 25_彩票
//
// Created by beyond on 14-8-28.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// 一個SettingItem模型 對應一個Cell需要的數據源
// 父類,用來描述當前cell里面要顯示的內容,描述點擊cell后做什么事情
#import <Foundation/Foundation.h>
@interface SettingItem : NSObject
// 為一行(cell)提供 圖標名
@property (nonatomic, copy) NSString *icon;
// 為一行(cell)提供 標題
@property (nonatomic, copy) NSString *title;
// 為一行(cell)提供 子標題
@property (nonatomic, copy) NSString *subtitle;
// 為一行(cell)提供 點擊后,要執行的操作
@property (nonatomic, copy) void (^operation)() ; // 點擊cell后要執行的操作
#pragma mark - 類方法,生成模型實例
// 有標題 有圖片的模型
+ (id)itemWithIcon:(NSString *)icon title:(NSString *)title;
// 只有標題的模型
+ (id)itemWithTitle:(NSString *)title;
@end
//
// SettingItem.m
// 25_彩票
//
// Created by beyond on 14-8-28.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// 一個SettingItem模型 對應一個Cell需要的數據源
// 父類,用來描述當前cell里面要顯示的內容,描述點擊cell后做什么事情
#import "SettingItem.h"
@implementation SettingItem
// 有標題 有圖片的模型
+ (id)itemWithIcon:(NSString *)icon title:(NSString *)title
{
SettingItem *item = [[self alloc] init];
item.icon = icon;
item.title = title;
return item;
}
// 只有標題的模型
+ (id)itemWithTitle:(NSString *)title
{
return [self itemWithIcon:nil title:title];
}
@end
父類SettingItemArchive
//
// SettingItemArchive.h
// 25_彩票
//
// Created by beyond on 14-8-29.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// 中間父類,僅一個成員,key,所有需要歸檔的settingItem的子類(如開關等) 都可以繼承本模型
#import "SettingItem.h"
@interface SettingItemArchive : SettingItem
// 存儲數據時用的key,取數據時也是用該key
@property (nonatomic, copy) NSString *key;
@end
子類SettingItemArrow
//
// SettingItemArrow.h
// 25_彩票
//
// Created by beyond on 14-8-28.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// 子類 最右邊是箭頭的item數據模型,專業提供數據源,給右邊是箭頭的cell
#import "SettingItem.h"
@interface SettingItemArrow : SettingItem
// 一般帶箭頭的cell,被點擊時候,是要跳到另一個界面(控制器)
@property (nonatomic, assign) Class showVCClass; // 即將顯示的控制器的類名
@end
子類SettingItemSwitch
//
// SettingItemSwitch.h
// 25_彩票
//
// Created by beyond on 14-8-28.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// 子類 最右邊是【開關】的item數據模型,專業提供數據源,給右邊是開關的cell
// 繼承自SettingItemArchive,而SettingItemArchive又繼承自SettingItem
#import "SettingItemArchive.h"
@interface SettingItemSwitch : SettingItemArchive
// 開關需要保存的是狀態,在設置時,就歸檔
@property (nonatomic, assign) BOOL off;
@end
//
// SettingItemSwitch.m
// 25_彩票
//
// Created by beyond on 14-8-28.
// Copyright (c) 2014年 com.beyond. All rights reserved.
//
#import "SettingItemSwitch.h"
@implementation SettingItemSwitch
// 開關需要保存的是狀態,在設置時,就歸檔
- (void)setOff:(BOOL)off
{
_off = off;
[SettingTool setBool:off forKey:self.key];
}
- (void)setKey:(NSString *)key
{
[super setKey:key];
_off = [SettingTool boolForKey:key];
}
@end
子類SettingItemLabel
//
// SettingItemLabel.h
// 25_彩票
//
// Created by beyond on 14-8-28.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// 子類 最右邊是【文字】的item數據模型,專業提供數據源,給右邊是Label的cell
#import "SettingItemArchive.h"
@interface SettingItemLabel : SettingItemArchive
// cell右邊顯示的文字,在設置時就要歸檔
@property (nonatomic, copy) NSString *text;
@end
//
// SettingItemLabel.m
// 25_彩票
//
// Created by beyond on 14-8-28.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// 子類 最右邊是【文字】的item數據模型,專業提供數據源,給右邊是Label的cell
#import "SettingItemLabel.h"
@implementation SettingItemLabel
// 攔截,cell右邊顯示的文字,賦值時,就必須歸檔
- (void)setText:(NSString *)text
{
_text = text;
// 歸檔
[SettingTool setObject:text forKey:self.key];
}
// 為key賦值的時候,就必須解檔
- (void)setKey:(NSString *)key
{
[super setKey:key];
_text = [SettingTool objectForKey:key];
}
@end
自定義cell視圖View的封裝 SettingCell
//
// SettingCell.h
// 25_彩票
//
// Created by beyond on 14-8-28.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// view,自定義cell,接收數據源為其內部子控件提供數據
#import <UIKit/UIKit.h>
// 模型,數據源,為view cell 提供數據
@class SettingItem;
@interface SettingCell : UITableViewCell
// 模型,數據源,為view cell 提供數據
@property (nonatomic, strong) SettingItem *item;
// cell所在的組和行號
@property (nonatomic, strong) NSIndexPath *indexPath;
// 類方法創建cell實例對象,使用instancetype好處多多,更加嚴謹,讓編譯器更智能提示錯誤
+ (instancetype)settingCellWithTableView:(UITableView *)tableView;
@end
//
// SettingCell.m
// 25_彩票
//
// Created by beyond on 14-8-28.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// view,自定義cell,接收數據源為其內部子控件提供數據
#import "SettingCell.h"
// 數據源
#import "SettingItem.h"
#import "SettingItemSwitch.h"
#import "SettingItemArrow.h"
#import "SettingItemLabel.h"
// 在ios6中,cell的contentView的x是10,因此,要想讓cell全屏寬,必須使用cell左移10,寬度+20
const int MakeCellToLeftBy = 10;
@interface SettingCell()
{
// 每一個進入視野的cell 都循環利用(共用)一個arrow,switch,label
UIImageView *_arrowImgView;
UISwitch *_switch;
UILabel *_label;
UIView *_divider;
}
@end
@implementation SettingCell
#pragma mark - 生命周期
// 類方法創建cell實例對象,使用instancetype好處多多,更加嚴謹,讓編譯器更智能提示錯誤
// 先從參數tableView的緩存池中取,取不到,才要創建
+ (instancetype)settingCellWithTableView:(UITableView *)tableView
{
// 0.用static修飾的局部變量,只會初始化一次
static NSString *ID = @"SettingCell";
// 1.拿到一個標識先去緩存池中查找對應的Cell
SettingCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
// 2.如果緩存池中沒有,才需要傳入一個標識創建新的Cell
if (cell == nil) {
cell = [[SettingCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:ID];
}
return cell;
}
// 重寫父類的方法,創建cell實例
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
// 先調用父類的方法
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// 1.設置全局統一的cell背景view
[self setupCellBgView];
// 2.設置子控件屬性
[self setupCellLabelBgColor];
// 3.添加cell底部的分隔線(為了統一,先移除系統自帶的separateLine)
[self setupCellUnderLine];
}
return self;
}
#pragma mark - 初始化 屬性設置
#pragma mark 1.設置cell背景view
- (void)setupCellBgView
{
// 1.默認 cell背景view (白色)
UIView *bgView = [[UIView alloc] init];
bgView.backgroundColor = [UIColor whiteColor];
self.backgroundView = bgView;
// 2.選中 cell背景view (灰色)
UIView *selectedBgView = [[UIView alloc] init];
selectedBgView.backgroundColor = kColor(237, 233, 218);
self.selectedBackgroundView = selectedBgView;
}
#pragma mark 2.設置cell內子控件label背景
- (void)setupCellLabelBgColor
{
// 標題 去其默認的背景
self.textLabel.backgroundColor = [UIColor clearColor];
self.textLabel.font = [UIFont systemFontOfSize:14];
// 子標題 去其默認的背景
self.detailTextLabel.backgroundColor = [UIColor clearColor];
self.detailTextLabel.font = [UIFont systemFontOfSize:12];
}
#pragma mark 3.設置分隔線
// 3.添加cell底部的分隔線(為了統一,先移除系統自帶的separateLine)
- (void)setupCellUnderLine
{
UIView *divider = [[UIView alloc] init];
divider.backgroundColor = kColor(200, 200, 200);
// 不能在這里設置分隔線的x值(原因:cell沒有具體的數據,里面的label就不知道最終的位置)
// divider.frame = CGRectMake(0, 0, self.contentView.frame.size.width, 1.5);
[self.contentView addSubview:divider];
_divider = divider;
}
#pragma mark - 攔截setter方法
// 根據所在的組,所在的行號,設置分割線的顯示狀態
- (void)setIndexPath:(NSIndexPath *)indexPath
{
_indexPath = indexPath;
// 設置underLine的可見性,根據該cell所在的indexPath
_divider.hidden = indexPath.row == 0;
}
// 攔截數據源,為子控件們賦值
- (void)setItem:(SettingItem *)item
{
_item = item;
// 設置數據
self.imageView.image = [UIImage imageNamed:item.icon];
self.textLabel.text = item.title;
self.detailTextLabel.text = item.subtitle;
// 根據數據源模型的不同,創建不同的最右邊的accessoryView
if ([item isKindOfClass:[SettingItemArrow class]]) {
// 1.設置箭頭
[self setAccessoryViewArrow];
} else if ([item isKindOfClass:[SettingItemSwitch class]]) {
// 2.設置開關
[self setAccessoryViewSwitch];
} else if ([item isKindOfClass:[SettingItemLabel class]]) {
// 3.設置文本
[self setAccessoryViewLabel];
} else {
// 什么也沒有,必須清空右邊顯示的view,因為cell循環使用
self.accessoryView = nil;
// 并且要,還原,使用默認的選中樣式(即可以產生選中效果)
self.selectionStyle = UITableViewCellSelectionStyleDefault;
}
}
#pragma mark 設置右邊的箭頭
// 每一個進入視野的cell 都循環利用(共用)一個arrow,switch,label
- (void)setAccessoryViewArrow
{
if (_arrowImgView == nil) {
_arrowImgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"CellArrow"]];
}
// 右邊顯示箭頭
self.accessoryView = _arrowImgView;
// 用默認的選中樣式
self.selectionStyle = UITableViewCellSelectionStyleDefault;
}
#pragma mark 設置右邊的文本標簽
// 每一個進入視野的cell 都循環利用(共用)一個arrow,switch,label
- (void)setAccessoryViewLabel
{
if (_label == nil) {
_label = [[UILabel alloc] init];
_label.bounds = CGRectMake(0, 0, 100, self.frame.size.height);
_label.textAlignment = NSTextAlignmentRight;
_label.backgroundColor = [UIColor clearColor];
_label.textColor = kColor(173, 69, 14);
_label.font = [UIFont systemFontOfSize:13];
}
// 設置右邊label的值
SettingItemLabel *labelItem = (SettingItemLabel *)_item;
_label.text = labelItem.text;
// 右邊顯示子文本
self.accessoryView = _label;
// 允許選中本行
self.selectionStyle = UITableViewCellSelectionStyleDefault;
}
#pragma mark 設置右邊的開關
// 每一個進入視野的cell 都循環利用(共用)一個arrow,switch,label
- (void)setAccessoryViewSwitch
{
if (_switch == nil) {
_switch = [[UISwitch alloc] init];
[_switch addTarget:self action:@selector(switchChange) forControlEvents:UIControlEventValueChanged];
}
// 設置開關的狀態
SettingItemSwitch *switchItem = (SettingItemSwitch *)_item;
_switch.on = !switchItem.off;
// 右邊顯示開關
self.accessoryView = _switch;
// 因為是開關,所以要禁止選中本行
self.selectionStyle = UITableViewCellSelectionStyleNone;
}
#pragma mark 開關狀態改變
- (void)switchChange
{
SettingItemSwitch *switchItem = (SettingItemSwitch *)_item;
switchItem.off = !_switch.on;
}
#pragma mark - 當cell的寬高改變了就會調用
// 父類方法,需要調節cell內部子控件的frame,只有在layoutSubviews方法中,才最可靠最有效
- (void)layoutSubviews
{
// 必須先調用父類的方法
[super layoutSubviews];
// 0.設置cell分隔線的位置 (從文字處開始)
_divider.frame = CGRectMake(self.textLabel.frame.origin.x, 0, self.contentView.frame.size.width + 100, 1.2);
if (iOS7) return;
// 以下是iOS6,設置cell占整個屏幕的寬度
[self makeCellFullWidth];
}
// 以下是iOS6,設置cell占整個屏幕的寬度
- (void)makeCellFullWidth
{
// 在ios6中,cell的contentView的x默認是10,因此,要想讓cell全屏寬,必須使用cell的x左移10,寬度+20,相當于把整個cell,先左平移,再扯寬
// 1.將cell的frame拉寬
CGRect cellF = self.frame;
// cell整體先左平移10
cellF.origin.x = -MakeCellToLeftBy;
// cell整體寬度再+20,這樣cell的contentView就全屏寬了
CGFloat deltaW = MakeCellToLeftBy * 2;
cellF.size.width = [UIScreen mainScreen].bounds.size.width + deltaW;
self.frame = cellF;
// 2.右邊控件的frame (左移)
// accessoryView不屬于contentView, 屬于cell
CGRect accessF = self.accessoryView.frame;
accessF.origin.x = cellF.size.width - accessF.size.width - deltaW;
self.accessoryView.frame = accessF;
}
@end
父類控制器的封裝
BaseSettingController
//
// BaseSettingController.h
// 25_彩票
//
// Created by beyond on 14-8-28.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// 父類,內部維護了一個tableView,子類提供數據源數組(GroupsArr)
#import <UIKit/UIKit.h>
#import "SettingGroup.h"
#import "SettingItem.h"
// 導入數據模型
// 右側是箭頭的數據模型
#import "SettingItemArrow.h"
// 右側是開關的數據模型
#import "SettingItemSwitch.h"
// 右邊是子文本
#import "SettingItemLabel.h"
// 所有聲明的將要被存儲到沙盒中的key
#import "SettingArchiveKeys.h"
@interface BaseSettingController : UIViewController<UITableViewDataSource, UITableViewDelegate>
{
// 開放給子類用,父類只負責初始化,子類負責添加一個個Group對象,一個group模型對應一個section
NSMutableArray *_allGroups; // 所有的組模型
}
@property (nonatomic, weak, readonly) UITableView *tableView;
@end
//
// BaseSettingController.m
// 25_彩票
//
// Created by beyond on 14-8-28.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// 父類,內部維護了一個tableView,子類提供數據源數組(GroupsArr)
#import "BaseSettingController.h"
#import "SettingCell.h"
// 每一個section之間的頂部間距
const int SectionHeaderMargin = 20;
@interface BaseSettingController ()
@end
@implementation BaseSettingController
// 直接讓tableView就是控制器的view
- (void)loadView
{
// 父類的組數組 初始化放在LoadView方法中,好處是,子類在viewDidLoad時,就已經擁有初始化的_allGroups,而不再需要先調用父類的viewDidLoad,然后才可向數組添加成員
_allGroups = [NSMutableArray array];
// 創建并維護自己的tableView,子類僅需提供數據源 groupsArr 即可
[self createTableView];
}
// 創建并維護自己的tableView,子類僅需提供數據源 groupsArr 即可
- (void)createTableView
{
UITableView *tableView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame style:UITableViewStyleGrouped];
// 設置數據源和代理 為當前父控制器
tableView.delegate = self;
tableView.dataSource = self;
// 設置全局統一的表格背景
// 如果是分組,則要先清空背景view,才可設置表格背景顏色(colorWithPattern平鋪)
tableView.backgroundView = nil;
tableView.backgroundColor = kGlobalBg;
// group狀態下,sectionFooterHeight和sectionHeaderHeight是有值的
tableView.sectionFooterHeight = 0;
tableView.sectionHeaderHeight = SectionHeaderMargin;
// 在tableView初始化的時候設置contentInset
// 在tableView展示完數據的時候給contentInset.top增加(20+44)的值
// 重要~~ ?????
if (iOS7) {
tableView.contentInset = UIEdgeInsetsMake(SectionHeaderMargin - 35, 0, 0, 0);
}
// 先隱藏表格默認的分隔線,cell內部在根據所在的indexPath繪制underLine
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
self.view = tableView;
_tableView = tableView;
}
#pragma mark - 數據源
// 多少組
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// 返回組 數組的長度
return _allGroups.count;
}
// 各個組有多少行
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// 取出組模型
SettingGroup *group = _allGroups[section];
// 返回組模型中成員---settingItems數組的長度
return group.items.count;
}
// 每當有一個cell進入視野范圍內就會調用,返回當前這行顯示的cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 1.創建一個SettingCell 自定義的view
SettingCell *cell = [SettingCell settingCellWithTableView:tableView];
// 2.取出組模型
SettingGroup *group = _allGroups[indexPath.section];
// 3.取出組中的被點的cell模型,并賦值給自定義的view,供其內部子控件使用
cell.item = group.items[indexPath.row];
// 根據所在的組,所在的行號,設置分割線的顯示狀態
cell.indexPath = indexPath;
return cell;
}
#pragma mark - 代理
// 點擊了cell后的操作
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// 1.去除選中時的背景
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// 2.取出這行對應的模型
SettingGroup *group = _allGroups[indexPath.section];
// 取出對應的cell數據源模型
SettingItem *item = group.items[indexPath.row];
// 3.取出這行對應模型中有block代碼
if (item.operation) {
// 執行block
item.operation();
return;
}
// 4.檢測有沒有要跳轉的控制器
if ([item isKindOfClass:[SettingItemArrow class]]) {
// 將cell對應的數據源模型 轉成具體的子類
SettingItemArrow *arrowItem = (SettingItemArrow *)item;
// 創建并跳轉到指定的控制器
if (arrowItem.showVCClass) {
UIViewController *vc = [[arrowItem.showVCClass alloc] init];
[self.navigationController pushViewController:vc animated:YES];
}
}
}
#pragma mark 返回每一組的header標題
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
// 取得組模型
SettingGroup *group = _allGroups[section];
// 返回組的頭部標題
return group.header;
}
#pragma mark 返回每一組的footer標題
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
{
// 取得組模型
SettingGroup *group = _allGroups[section];
// 返回組的尾部標題
return group.footer;
}
@end
子類設置控制器
//
// SettingController.h
// 25_彩票
//
// Created by beyond on 14-8-28.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// 點擊【設置】按鈕跳轉到本控制器,本控制器繼承自BaseSettingController
#import "BaseSettingController.h"
@interface SettingController : BaseSettingController
@end
//
// SettingController.m
// 25_彩票
//
// Created by beyond on 14-8-28.
// Copyright (c) 2014年 com.beyond. All rights reserved.
//
#import "SettingController.h"
#import "PushNoticeController.h"
#import "ShareController.h"
#import "AboutController.h"
#import "HelpController.h"
#import "ProductController.h"
@interface SettingController ()
@end
@implementation SettingController
- (void)viewDidLoad
{
[super viewDidLoad];
// 1.第0組:3個
[self add0SectionItems];
// 2.第1組:6個
[self add1SectionItems];
}
#pragma mark 添加第0組的模型數據
- (void)add0SectionItems
{
// 1.1.推送和提醒
SettingItemArrow *push = [SettingItemArrow itemWithIcon:@"MorePush" title:@"推送和提醒"];
push.showVCClass = [PushNoticeController class];
// copy狀態下的block(堆里面的block)會對里面所使用的外界變量 產生 強引用
// __weak SettingController *setting = self;
// __unsafe_unretained
// 1.2.搖一搖機選
SettingItemSwitch *shake = [SettingItemSwitch itemWithIcon:@"handShake" title:@"搖一搖機選"];
shake.key = ILSettingShakeChoose;
// 1.3.聲音效果
SettingItemSwitch *sound = [SettingItemSwitch itemWithIcon:@"sound_Effect" title:@"聲音效果"];
sound.key = ILSettingSoundEffect;
SettingGroup *group = [[SettingGroup alloc] init];
group.items = @[push, shake, sound];
[_allGroups addObject:group];
}
#pragma mark 添加第1組的模型數據
- (void)add1SectionItems
{
// 2.1.檢查新版本
SettingItemArrow *update = [SettingItemArrow itemWithIcon:@"MoreUpdate" title:@"檢查新版本"];
update.operation = ^{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"目前已是最新版本了" delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
[alert show];
};
// 2.2.幫助
SettingItemArrow *help = [SettingItemArrow itemWithIcon:@"MoreHelp" title:@"幫助"];
help.showVCClass = [HelpController class];
// 2.3.分享
SettingItemArrow *share = [SettingItemArrow itemWithIcon:@"MoreShare" title:@"分享"];
share.showVCClass = [ShareController class];
// 2.4.查看消息
SettingItemArrow *msg = [SettingItemArrow itemWithIcon:@"MoreMessage" title:@"查看消息"];
// 2.5.產品推薦
SettingItemArrow *product = [SettingItemArrow itemWithIcon:@"MoreNetease" title:@"產品推薦"];
product.showVCClass = [ProductController class];
// 2.6.關于
SettingItemArrow *about = [SettingItemArrow itemWithIcon:@"MoreAbout" title:@"關于"];
about.showVCClass = [AboutController class];
SettingGroup *group = [[SettingGroup alloc] init];
group.items = @[update, help, share, msg, product, about];
[_allGroups addObject:group];
}
@end
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈