zoukankan      html  css  js  c++  java
  • iOS开发UI篇—使用UItableview完成一个简单的QQ好友列表(二)

    iOS开发UI篇—使用UItableview完成一个简单的QQ好友列表(二)

    一、实现效果

     

    二、实现代码

    1.数据模型部分

     YYQQGroupModel.h文件

    //
    //  YYQQGroupModel.h
    //  02-QQ好友列表(基本数据的加载)
    //
    //  Created by apple on 14-5-31.
    //  Copyright (c) 2014年 itcase. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @interface YYQQGroupModel : NSObject
    /**
     *  名称属性
     */
    @property(nonatomic,copy)NSString *name;
    /**
     *  是否在线
     */
    @property(nonatomic,copy)NSString *online;
    /**
     *  好友列表
     */
    @property(nonatomic,strong)NSArray *friends;
    
    //记录当前组是否要打开
    @property(nonatomic,assign,getter = isOpen)BOOL open;
    
    -(instancetype)initWithDict:(NSDictionary *)dict;
    +(instancetype) qqGroupModelWithDict:(NSDictionary *)dict;
    @end

    YYQQGroupModel.m文件

    //
    //  YYQQGroupModel.m
    //  02-QQ好友列表(基本数据的加载)
    //
    //  Created by apple on 14-5-31.
    //  Copyright (c) 2014年 itcase. All rights reserved.
    //
    
    #import "YYQQGroupModel.h"
    #import "YYFriendsModel.h"
    
    @implementation YYQQGroupModel
    -(instancetype)initWithDict:(NSDictionary *)dict
    {
        if (self=[super init]) {
            //将字典转换为模型
            [self setValuesForKeysWithDictionary:dict];
            
            //定义一个数组来保存转换后的模型
            NSMutableArray *models=[NSMutableArray arrayWithCapacity:self.friends.count];
            for (NSDictionary *dict in self.friends) {
                YYFriendsModel *friends=[YYFriendsModel friendsWithDict:dict];
                [models addObject:friends];
            }
            _friends=[models copy];
        }
        return self;
    }
    
    +(instancetype)qqGroupModelWithDict:(NSDictionary *)dict
    {
        return  [[self alloc]initWithDict:dict];
    }
    @end

    YYFriendsModel.h文件

    //
    //  YYFriendsModel.h
    //  02-QQ好友列表(基本数据的加载)
    //
    //  Created by apple on 14-5-31.
    //  Copyright (c) 2014年 itcase. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @interface YYFriendsModel : NSObject
    /**
     *  每个好友的名称
     */
    @property(nonatomic,copy)NSString *name;
    /**
     *每个好友的头像
     */
    @property(nonatomic,copy)NSString *icon;
    /**
     *  每个好友的个性签名
     */
    @property(nonatomic,copy)NSString *intro;
    /**
     *  该好友是否是vip
     */
    @property(nonatomic,assign,getter = isVip)BOOL vip;
    
    -(instancetype)initWithDict:(NSDictionary *)dict;
    +(instancetype)friendsWithDict:(NSDictionary *)dict;
    @end

    YYFriendsModel.m文件

    //
    //  YYFriendsModel.m
    //  02-QQ好友列表(基本数据的加载)
    //
    //  Created by apple on 14-5-31.
    //  Copyright (c) 2014年 itcase. All rights reserved.
    //
    
    #import "YYFriendsModel.h"
    
    @implementation YYFriendsModel
    -(instancetype)initWithDict:(NSDictionary *)dict
    {
        if (self=[super init]) {
            [self setValuesForKeysWithDictionary:dict];
        }
        return self;
    }
    
    +(instancetype)friendsWithDict:(NSDictionary *)dict
    {
        return [[self alloc]initWithDict:dict];
    }
    @end

    2.视图部分

    YYfriendCell.h文件

    //
    //  YYfriendCell.h
    //  02-QQ好友列表(基本数据的加载)
    //
    //  Created by apple on 14-5-31.
    //  Copyright (c) 2014年 itcase. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    @class YYFriendsModel;
    @interface YYfriendCell : UITableViewCell
    
    @property(nonatomic,strong)YYFriendsModel *friends;
    
    +(instancetype)cellWithTableview:(UITableView *)tableView;
    @end

    YYfriendCell.m文件

    //
    //  YYfriendCell.m
    //  02-QQ好友列表(基本数据的加载)
    //
    //  Created by apple on 14-5-31.
    //  Copyright (c) 2014年 itcase. All rights reserved.
    //
    
    #import "YYfriendCell.h"
    #import "YYFriendsModel.h"
    //私有扩展
    @interface YYfriendCell()
    
    
    @end
    @implementation YYfriendCell
    
    +(YYfriendCell *)cellWithTableview:(UITableView *)tableView
    {
        static NSString *identifier=@"qq";
        YYfriendCell *cell=[tableView dequeueReusableCellWithIdentifier:identifier];
        if (cell==nil) {
            //这里使用系统自带的样式
            cell=[[YYfriendCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
            NSLog(@"创建一个cell");
        }
        return cell;
    }
    
    -(void)setFriends:(YYFriendsModel *)friends
    {
        _friends=friends;
        //1.设置头像
        self.imageView.image=[UIImage imageNamed:_friends.icon];
           //2.设置昵称
        self.textLabel.text=_friends.name;
        
         //3.设置简介
        self.detailTextLabel.text=_friends.intro;
     //判断是否是会员
        
        /**
         *  这里有个注意点,如果不写else设置为黑色,会怎么样?
         */
        if (_friends.isVip) {
            [self.textLabel setTextColor:[UIColor redColor]];
        }else
        {
        [self.textLabel setTextColor:[UIColor blackColor]];
        }
         //调整字体的大小
        self.textLabel.font=[UIFont systemFontOfSize:15.f];
        self.detailTextLabel.font=[UIFont systemFontOfSize:10.f];
    }
    @end

    YYHeaderView.h文件

    //
    //  YYHeaderView.h
    //  02-QQ好友列表(基本数据的加载)
    //
    //  Created by apple on 14-6-1.
    //  Copyright (c) 2014年 itcase. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    
    @class YYQQGroupModel,YYHeaderView;
    
    //商量一个协议
    @protocol YYHeaderViewDelegate <NSObject>
    -(void)headerViewDidClickHeaderView:(YYHeaderView *)headerView;
    @end
    
    @interface YYHeaderView : UITableViewHeaderFooterView
    
    @property(nonatomic,strong)YYQQGroupModel *group;
    //提供一个类方法,创建一个头部视图
    +(instancetype)headerWithTableView:(UITableView *)tableView;
    
    
    //delegate遵守YYHeaderViewDelegate这个协议,可以使用协议中的方法
    @property(nonatomic,weak)id<YYHeaderViewDelegate> delegate;
    @end

    YYHeaderView.m文件

    //
    //  YYHeaderView.m
    //  02-QQ好友列表(基本数据的加载)
    //
    //  Created by apple on 14-6-1.
    //  Copyright (c) 2014年 itcase. All rights reserved.
    //
    
    #import "YYHeaderView.h"
    #import "YYQQGroupModel.h"
    
    @interface YYHeaderView()
    @property(nonatomic,strong)UIButton *btn;
    @property(nonatomic,strong)UILabel *lab;
    @end
    @implementation YYHeaderView
    
    
    //创建一个自定义的头部分组视图
    +(instancetype)headerWithTableView:(UITableView *)tableView
    {
        static NSString *indentifier=@"header";
        //先到缓存池中去取数据
        YYHeaderView *headerview=[tableView dequeueReusableCellWithIdentifier:indentifier];
        //如果没有,则自己创建
        if (headerview==nil) {
            headerview=[[YYHeaderView alloc]initWithReuseIdentifier:indentifier];
        }
        //返回一个头部视图
        return headerview;
    }
    
    #warning 注意在构造方法中为控件设置的frame是无效的
    -(id)initWithReuseIdentifier:(NSString *)reuseIdentifier
    {
        //初始化父类中的构造方法
        if (self=[super initWithReuseIdentifier:reuseIdentifier]) {
            //创建一个按钮
            UIButton *btn=[UIButton buttonWithType:UIButtonTypeCustom];
            //设置按钮的属性
            //设置普通状态下按钮的背景图片
            [btn setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg"] forState:UIControlStateNormal];
            //设置高亮状态下按钮的背景图片
            [btn setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg_highlighted"] forState:UIControlStateHighlighted];
            
            //设置按钮上的小三角图片
            [btn setImage:[UIImage imageNamed:@"buddy_header_arrow"] forState:UIControlStateNormal];
            //设置按钮上信息的对其方式为左对齐
            btn.contentHorizontalAlignment=UIControlContentHorizontalAlignmentLeft;
            //设置小三角图片的内边距
            btn.contentEdgeInsets=UIEdgeInsetsMake(0, 20, 0, 0);
            //设置按钮上文字距离小三角图片的距离
            btn.titleEdgeInsets=UIEdgeInsetsMake(0, 20, 0, 0);
            //设置按钮上分组标题的文本颜色(默认是白色)
            //[btn setTintColor:[UIColor blackColor]];
            [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
            //添加按钮的点击事件
            [btn addTarget:self action:@selector(btnOnclick:) forControlEvents:UIControlEventTouchUpInside];
            
            // 设置btn中的图片不填充整个imageview
            btn.imageView.contentMode = UIViewContentModeCenter;
            // 超出范围的图片不要剪切
                   // btn.imageView.clipsToBounds = NO;
            btn.imageView.layer.masksToBounds = NO;
            
            //把按钮添加到视图
            [self addSubview:btn];
            self.btn=btn;
            
            //创建一个lab
            UILabel *lab=[[UILabel alloc]init];
            //设置在线人数的对齐方式为右对齐
            lab.textAlignment=NSTextAlignmentRight;
            //设置在线人数的文本颜色为灰色
            lab.textColor=[UIColor grayColor];
            [self addSubview:lab];
            self.lab=lab;
        }
        return self;
    }
    
    
    -(void)btnOnclick:(UIButton *)btn
    {
        NSLog(@"按钮被点击了");
        //修改模型的isopen属性
        //1.修改模型数据
        self.group.open=!self.group.isOpen;
        //2.刷新表格
        //(刷新表格的功能由控制器完成,在这里可以设置一个代理),当按钮被点击的时候,就通知代理对表格进行刷新
        //通知代理
        if ([self.delegate respondsToSelector:@selector(headerViewDidClickHeaderView:)]) {
            [self.delegate headerViewDidClickHeaderView:self];
        }
    }
    
    //当控件的frame值改变时,会自动调用该方法,故可以在该方法中设置控件的frame;
    -(void)layoutSubviews
    {
    #warning 一定不要忘记调用父类的方法
        [super layoutSubviews];
        //设置按钮的frame和头部视图一样大小
        self.btn.frame=self.bounds;
        
        //设置lab的frame
        CGFloat padding=20;
        CGFloat labW=50;
        CGFloat labH=self.frame.size.height;
        CGFloat labY=0;
        CGFloat labX=self.frame.size.width-padding-labW;
        self.lab.frame=CGRectMake(labX, labY, labW, labH);
    }
    
    #pragma mark - 当一个控件被添加到其它视图上的时候会调用以下方法
    // 已经被添加到父视图上的时候会调用
    - (void)didMoveToSuperview
    {
        NSLog(@"已经添加到视图了");
        // 在这个方法中就快要拿到最新的被添加到tableview上的头部视图修改它的图片
        if (self.group.isOpen) {
            //让小三角图片向下旋转
            self.btn.imageView.transform = CGAffineTransformMakeRotation(M_PI_2);
        }
    }
    
    // 即将被添加到父视图上的时候会调用
    - (void)willMoveToSuperview:(UIView *)newSuperview
    {
         NSLog(@"将要添加到视图了");
    }
    
    
    //重写get方法,设置数据
    -(void)setGroup:(YYQQGroupModel *)group
    {
        _group=group;
        //设置分组标题
    
        //self.btn.titleLabel.text=_group.name;
        #warning 请注意在设置按钮的文本时,一定要设置按钮的状态,像上面这样设置不会显示
        [self.btn setTitle:_group.name forState:UIControlStateNormal];
        NSLog(@"%@",self.btn.titleLabel.text);
        //设置在线人数
        self.lab.text=[NSString stringWithFormat:@"%@/%d",_group.online,_group.friends.count];
    }
    
    @end

    3.控制器部分

    YYViewController.h文件

    //
    //  YYViewController.h
    //  02-QQ好友列表(基本数据的加载)
    //
    //  Created by apple on 14-5-31.
    //  Copyright (c) 2014年 itcase. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    
    @interface YYViewController : UITableViewController
    
    @end

    YYViewController.m文件

    //
    //  YYViewController.m
    //  02-QQ好友列表(基本数据的加载)
    //
    //  Created by apple on 14-5-31.
    //  Copyright (c) 2014年 itcase. All rights reserved.
    //
    
    #import "YYViewController.h"
    #import "YYQQGroupModel.h"
    #import "YYfriendCell.h"
    #import "YYFriendsModel.h"
    #import "YYHeaderView.h"
    
    @interface YYViewController ()<YYHeaderViewDelegate>
    /**
     *  用来保存所有的分组数据
     */
    @property(nonatomic,strong)NSArray *groupFriends;
    @end
    
    @implementation YYViewController
    #pragma mark-懒加载
    //1.先拿到数据,实现懒加载
    -(NSArray *)groupFriends
    {
        if (_groupFriends==nil) {
            NSString *fullpath=[[NSBundle mainBundle]pathForResource:@"friends.plist" ofType:nil];
            NSArray *arrayM=[NSArray arrayWithContentsOfFile:fullpath];
            
            NSMutableArray *models=[NSMutableArray arrayWithCapacity:arrayM.count];
            for (NSDictionary *dict in arrayM) {
                YYQQGroupModel *group=[YYQQGroupModel qqGroupModelWithDict:dict];
                [models addObject:group];
            }
            _groupFriends=[models copy];
        }
        return _groupFriends;
    }
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
         self.tableView.sectionHeaderHeight = 100;
            
    }
    
    #pragma mark-  设置数据源
    //返回多少组
    -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        return self.groupFriends.count;
    }
    //每组返回多少行
    -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
    //    //取出对应的组模型
            YYQQGroupModel *group=self.groupFriends[section];
    //    //返回对应组中的好友数
    //    return group.friends.count;
        
        //在这里进行判断,如果该组收拢,那就返回0行,如果该组打开,就返回实际的行数
    //    if (group.isOpen) {
    //        return group.friends.count;
    //    }else
    //    {
    //        return 0;
    //    }
        
        if (group.isOpen) {
            // 代表要展开
            return group.friends.count;
        }else
        {
            // 代表要合拢
            return 0;
        }
    }
    //每组每行的内容
    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        //1.创建cell
        YYfriendCell *cell=[YYfriendCell cellWithTableview:tableView];
    
        //2.设置cell
        YYQQGroupModel *group=self.groupFriends[indexPath.section];
        YYFriendsModel *friends=group.friends[indexPath.row];
        cell.friends=friends;
        //3.返回一个cell
        return cell;
    }
    
    
    #pragma mark - 代理方法
    // 当一个分组标题进入视野的时候就会调用该方法
    - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
    {
    //    //    1.创建头部视图
    //    UIView *view = [[UIView alloc] init];
    //    view.backgroundColor = [UIColor grayColor];
    //    //    2.返回头部视图
    //    return view;
        
        //创建自定义的头部视图
        YYHeaderView *headerview=[YYHeaderView headerWithTableView:tableView];
        
        //设置当前控制器为代理
        headerview.delegate=self;
        //设置头部视图的数据
        YYQQGroupModel *groupmodel=self.groupFriends[section];
        headerview.group=groupmodel;
        //返回头部视图
        return headerview;
    }
    
    
    #pragma mark - YYHeaderViewDelegate
    -(void)headerViewDidClickHeaderView:(YYHeaderView *)headerView
    {
        //重新调用数据源的方法刷新数据
        [self.tableView reloadData];
    }
    //设置分组头部标题的高度
    -(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
    {
        return 30;
    }
    
    #pragma mark  隐藏状态栏
    -(BOOL)prefersStatusBarHidden
    {
        return YES;
    }
    @end

    三、代码说明

    1.项目文件结构

     

    2.注意点

    (1)调整字体的大小:    self.textLabel.font=[UIFont systemFontOfSize:15.f];

    (2)-(void)layoutSubviews方法。该方法在控件的frame被改变的时候就会调用,这个方法一般用于调整子控件的位置,注意一定要调用[super layoutSubviews];

    (3)但凡在init方法中获取到的frame都是0;

    (4)如果控件不显示,有以下一些排错方法

    a.frame为空(没有设置frame)
    b.hidden是否为YES
    c.alpha<=0.1(透明度)
    d.没有添加到父控件中
    e.查看父控件以上几点

    (5)请注意在设置按钮的文本时,一定要设置按钮的状态

    正确:[self.btn setTitle:_group.name forState:UIControlStateNormal];
    错误: self.btn.titleLabel.text=_group.name;

    (6)调用构造方法时,一定要先初始化父类的方法,先判断,再进行自己属性的初始化

    self=[super initWithReuseIdentifier:reuseIdentifier]
    if(self)
    {
    ……
    }
    (7)当一个控件被添加到其它视图上的时候会调用以下方法

    1) 已经被添加到父视图上的时候会调用- (void)didMoveToSuperview

    2) 即将被添加到父视图上的时候会调用- (void)willMoveToSuperview:(UIView *)newSuperview

    (8)图片填充知识

       1)设置btn中的图片不填充整个imageview btn.imageView.contentMode = UIViewContentModeCenter;

       2)超出范围的图片不要剪切

      //btn.imageView.clipsToBounds = NO;

      btn.imageView.layer.masksToBounds = NO;

    四、补充(代理)

    设置代理的几个步骤
    (1)如果一个视图中的某个按钮被点击了,这个时候需要去主控制器中刷新数据。有一种做法是,让这个视图拥有控制器这个属性,然后当按钮被点击的时候去利用该属性去做刷新数据的操作。另一种做法是把控制器设置为这个视图的代理,当视图中的某个按钮被点击的时候,通知它的代理(主控制器)去干刷新数据这件事。
    (2)要成为代理是由条件的,有以下几个步骤
    1).双方约定一个协议(代理协议,注意命名规范),在视图中自定义一个协议,协议中提供一个方法。

    @protocol YYHeaderViewDelegate <NSObject>

    -(void)headerViewDidClickHeaderView:(YYHeaderView *)headerView;

    @end

    2).在视图中添加一个id类型的属性变量,任何人只要遵守了约定协议的都可以成为它的代理。

    //delegate遵守YYHeaderViewDelegate这个协议,可以使用协议中的方法

    @property(nonatomic,weak)id<YYHeaderViewDelegate> delegate;

    3).在控制器中,遵守自定义的代理协议,就可以使用代理提供的方法,在这个方法中对数据进行刷新。

    @interface YYViewController ()<YYHeaderViewDelegate>

    -(void)headerViewDidClickHeaderView:(YYHeaderView *)headerView

    {

        [self.tableView reloadData];

    }

    4).把控制器设置作为按钮点击事件的代理。

    headerview.delegate=self;

  • 相关阅读:
    使用javap分析Java的字符串操作
    使用javap深入理解Java整型常量和整型变量的区别
    分享一个WebGL开发的网站-用JavaScript + WebGL开发3D模型
    Java动态代理之InvocationHandler最简单的入门教程
    Java实现 LeetCode 542 01 矩阵(暴力大法,正反便利)
    Java实现 LeetCode 542 01 矩阵(暴力大法,正反便利)
    Java实现 LeetCode 542 01 矩阵(暴力大法,正反便利)
    Java实现 LeetCode 541 反转字符串 II(暴力大法)
    Java实现 LeetCode 541 反转字符串 II(暴力大法)
    Java实现 LeetCode 541 反转字符串 II(暴力大法)
  • 原文地址:https://www.cnblogs.com/yipingios/p/5549773.html
Copyright © 2011-2022 走看看