Cowboy Tech

iOS项目8.QQ下拉菜单

效果图

项目分析

JKFriendsModel

加载数据(字典)

- (instancetype)initWithDict:(NSDictionary *)dict{
if (self = [super init]) {
    [self setValuesForKeysWithDictionary:dict];
}
return self;
}

构建class method

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

JKGroupModel

加载数据(字典内含数组)

- (instancetype)initWithDict:(NSDictionary *)dict{

if (self = [super init]) {

    //加载组内字典数据
    [self setValuesForKeysWithDictionary:dict];

    //加载组内数组数据
    NSMutableArray *muArray = [NSMutableArray array];
    for (NSDictionary *dict in self.friends) {
        JKFriendsModel *model = [JKFriendsModel friendWithDict:dict];
        [muArray addObject:model];
    }
    self.friends = muArray;
}
return self;
}

HeaderView

子类

@interface HeaderView : UITableViewHeaderFooterView

初始化headerView

//类似cell的创建

+ (instancetype)headerView:(UITableView *)tableView{

    static NSString *identifier = @"header";
    HeaderView *header =(HeaderView *) [tableView dequeueReusableCellWithIdentifier:identifier];

    //用以下这个方式,则只创建一次,此项目不采用
    //HeaderView *header = [tableView dequeueReusableHeaderFooterViewWithIdentifier:identifier];

    if (!header) {
header = [[HeaderView alloc] initWithReuseIdentifier:identifier];
}
return header;
}


//这个headerview其实就是个button
- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier{

if (self = [super initWithReuseIdentifier:reuseIdentifier]) {

    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button setBackgroundImage:[UIImage imageNamed:@"header_bg"] forState:UIControlStateNormal];
    //[button setBackgroundImage:[UIImage imageNamed:@"header_bg_highlighted"] forState:UIControlStateHighlighted];
    [button setImage:[UIImage imageNamed:@"arrow"] forState:UIControlStateNormal];
    [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    button.contentEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
    button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
    button.titleEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
    button.imageView.contentMode = UIViewContentModeCenter;
    [button addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
    button.imageView.clipsToBounds = NO;
    _arrowBtn = button;

    [self addSubview:_arrowBtn];
    //创建label,显示当前在线人数
    UILabel *labelRight = [[UILabel alloc] init];
    labelRight.textAlignment = NSTextAlignmentCenter;
    _label = labelRight;
    [self addSubview:_label];
}

return self;
}

UIButton的属性设置

//内容框的内边距
button.contentEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);

//内容的对齐
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;

//标题的内边距
button.titleEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);

//为button设定方法
[button addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];

BOOL值取反

self.groupModel.isOpen = !self.groupModel.isOpen;

调用代理方法

代理就好比是自己有个武器不能用,然后让自己的小喽啰”id delegate” 交给他人来”viewController” 使用

if ([self.delegate respondsToSelector:@selector(clickView)]) {
[self.delegate clickView];
}

小箭头的旋转

//调用了tableView 的 reload方法,这个方法就会刷新headview,那样的话,就会重新生成一个headview
- (void)didMoveToSuperview{
    _arrowBtn.imageView.transform = self.groupModel.isOpen ? CGAffineTransformMakeRotation(M_PI_2):CGAffineTransformMakeRotation(0);
}

布局子视图

- (void)layoutSubviews{
    [super layoutSubviews];
    _arrowBtn.frame = self.bounds;
    _label.frame = CGRectMake(self.frame.size.width - 70, 0, 60, self.frame.size.height);
}
  1. layoutSubviews方法,是当改变父控件高度的时候,自动调用这个方法,所以一般在这里面设置子控件的frame。因为子控件随着父控件而改变。
  2. UITableViewHeaderFooterView不可以用xib,只能用代码创建

setter赋值button title

- (void)setGroupModel:(JKGroupModel *)groupModel{
_groupModel = groupModel;
[_arrowBtn setTitle:_groupModel.name forState:UIControlStateNormal];
_label.text = [NSString stringWithFormat:@"%@/%lu",_groupModel.online,(unsigned long)_groupModel.friends.count];
}

imageView.contentMode

button.imageView.contentMode = UIViewContentModeCenter;
button.imageView.clipsToBounds = NO;

这个居中是包括了,横向和纵向都是居中。图片不会拉伸或者压缩,就是按照imageView的frame和图片的大小来居中显示的。

这里有两种情况:

  1. 图片比view的区域更大。这个时候会截取图片的中间部位显示在frame区域里面。
  2. 图片比view的区域更小。这个时候图片会完整的显示在frame的中间位置。

如果在默认情况,图片的多出来的部分还是会显示屏幕上。如果不希望超过frame的区域显示在屏幕上要设置。clipsToBounds属性。

ListTableViewController

加载数据

- (NSArray *)dataArray{
//为什么不能用self.dataArray?? BadAccess
if (!_dataArray) {
    NSString *path = [[NSBundle mainBundle] pathForResource:@"friends.plist" ofType:nil];
    NSArray *array = [NSArray arrayWithContentsOfFile:path];
    NSMutableArray *muArray = [NSMutableArray arrayWithCapacity:array.count];
    for (NSDictionary *dict in array) {
        JKGroupModel *groupModel = [JKGroupModel GroupWithDict:dict];
        [muArray addObject:groupModel];
    }
    _dataArray = [muArray copy];
}
return _dataArray;
}
  1. 每个字典对应一个数据模型(Model class),plist中有多少个字典就有多少个Model class
  2. 使用该方法加载数据 — [self setValuesForKeysWithDictionary:dict]
  3. plist的第一层级都是数组,所以懒加载返回的也是数组

尾部去掉多余的线

#pragma mark - 去掉多余的线 ,将尾部设为一个透明的UIView
- (void)clipExtraCellLine:(UITableView *)tableView{
UIView *view = [[UIView alloc] init];
view.backgroundColor = [UIColor clearColor];
[self.tableView setTableFooterView:view];
}

Section Header

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section

每次表视图变动需要reload

[self.tableView reloadData];

判断展开的Item数量

NSInteger count = groupModel.isOpen ? groupModel.friends.count : 0;

设置cell的代码

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *identifier = @"friendCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
    if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];    
}
//对应的哪一个section
JKGroupModel *groupModel = self.dataArray[indexPath.section];
//对应的哪一个row
JKFriendsModel *friendModel = groupModel.friends[indexPath.row];
cell.imageView.image = [UIImage imageNamed:friendModel.icon];
cell.textLabel.text = friendModel.name;
cell.detailTextLabel.text = friendModel.intro;
return cell;
}

AppDelegate

创建导航视图

ListTableViewController *listVC = [[ListTableViewController alloc] init];
UINavigationController *navCtrl = [[UINavigationController alloc] initWithRootViewController:listVC];
self.window.rootViewController = navCtrl;