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;

  • 相关阅读:
    [enum]enum的用法
    gridview汇出EXCEL (ExportGridViewToExcel(dt, HttpContext.Current.Response);)
    c#用正则表达式判断字符串是否全是数字、小数点、正负号组成 Regex reg = new Regex(@"^(([0-9]+.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*.[0-9]+)|([0-9]*[1-9][0-9]*))$");
    GridView里的文本框改变事件
    转发 win7+iis7.5+asp.net下 CS0016: 未能写入输出文件“c:WindowsMicrosoft.NETFrameworkv2.0.50727Temporary ASP.NET Files 解决方案
    验证上转文件类型的正则表达式
    EXCEL设置选中单元格样式
    转发!HTML 复选框 checkbox 的 JavaScript 的全选和全反选
    dataGrid转换dataTable
    wince mobile环境下播放WAV声音
  • 原文地址:https://www.cnblogs.com/yipingios/p/5549773.html
Copyright © 2011-2022 走看看