IOS开发教程第一季之UI基础day9合并IOS学习009仿QQ界面(UITableView静态单元格)、仿QQ好友列表
1.仿QQ界面UITableView静态单元格
使用静态单元格,必须使用UITableViewController控制器
-
静态单元格使用建议:
1> 先保留1个Section, 1个Cell。
2> 设置好这个Cell以后, 在设置section的个数以及每个section中行的个数。- 静态单元格设置大致步骤:
1> 选中TableView设置Content为static cell(静态单元格)
2> 删除静态单元格, 只保留一个。
3> 选中TableView设置style为grouped
4> 选中单元格, 设置设置style为basic、设置Accessory为Disclosure Indicator。
5> 双击"Title"设置文字.
6> 选中单元格设置Image属性为: found_icons_qzone
6.1> 选中 UITableView设置 style 为 Grouped7> 选中tableView设置Section为 3。
8> 选中第二个Section设置Rows为 2
9> 选中第三个Section设置Rows为 3
** 注意: 当设置了数据源对象, 并且实现了数据源方法的时候, 即便有静态单元格也优先调用数据源方法来生成数据。
- 静态单元格设置大致步骤:
效果如下:
2.仿QQ好友列表分组显示完整版本
plist文件
1、创建FRFriend模型
FRFriend.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
//创建数据模型
@interface FRFriend : NSObject
@property(nonatomic,copy)NSString* icon;//头像
@property(nonatomic,copy)NSString* intro;//签名
@property(nonatomic,copy)NSString* name;//昵称
@property(nonatomic,assign,getter=isVip)BOOL vip;//是否vip
-(instancetype)initWithDictionary:(NSDictionary*)dict;
+(instancetype)friendWithDictionary:(NSDictionary*)dict;
@end
NS_ASSUME_NONNULL_END
FRFriend.m
#import "FRFriend.h"
@implementation FRFriend
-(instancetype)initWithDictionary:(NSDictionary*)dict{
if (self= [super init]) {
[self setValuesForKeysWithDictionary:dict];
}
return self;
}
+(instancetype)friendWithDictionary:(NSDictionary*)dict{
return [[self alloc]initWithDictionary:dict];
}
@end
2、创建FRFriendGroup模型
FRFriendGroup.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface FRFriendGroup : NSObject
@property(nonatomic,strong)NSArray* friends;//所有好友
@property(nonatomic,copy)NSString* name;//组名
@property(nonatomic,assign)NSNumber* online;//在线人数
@property(nonatomic,assign,getter=isVisible)BOOL visible;//表示该组是否可见(展开)
-(instancetype)initWithDictionary:(NSDictionary*)dict;
+(instancetype)groupWithDictionary:(NSDictionary*)dict;
@end
NS_ASSUME_NONNULL_END
FRFriendGroup.m
#import "FRFriendGroup.h"
#import "FRFriend.h"
@implementation FRFriendGroup
-(instancetype)initWithDictionary:(NSDictionary*)dict{
if (self=[super init]) {
[self setValuesForKeysWithDictionary:dict];
//把字典里的friends数组再转一次模型
NSMutableArray* arrayModelM=[NSMutableArray array];
for (NSDictionary* subdict in self.friends) {
//创建FRiend模型
FRFriend* friendModel=[FRFriend friendWithDictionary:subdict];
[arrayModelM addObject:friendModel];
}
self.friends=arrayModelM;
}
return self;
}
+(instancetype)groupWithDictionary:(NSDictionary*)dict{
return [[self alloc]initWithDictionary:dict];
}
@end
3、创建FRFriendCell单元格类
FRFriendCell.h
#import <UIKit/UIKit.h>
@class FRFriend;
NS_ASSUME_NONNULL_BEGIN
@interface FRFriendCell : UITableViewCell
//friend模型属性
@property(nonatomic,strong)FRFriend* friendModel;
//创建单元格的类方法
+(instancetype)friendCellWithTableView:(UITableView*)tableView;
@end
NS_ASSUME_NONNULL_END
FRFriendCell.m
#import "FRFriendCell.h"
#import "FRFriend.h"
@implementation FRFriendCell
+(instancetype)friendCellWithTableView:(UITableView*)tableView{
//创建单元格(视图)
NSString* strId=@"friend_cell";
FRFriendCell *cell = [tableView dequeueReusableCellWithIdentifier:strId];
if (cell==nil) {
cell = [[FRFriendCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:strId];
}
return cell;
}
//重写friendModel属性的set方法
-(void)setFriendModel:(FRFriend *)friendModel{
_friendModel=friendModel;
//设置各个控件的值,把模型数据的各个值设置给单元的子控件
self.imageView.image=[UIImage imageNamed:friendModel.icon];
self.textLabel.text=friendModel.name;
self.detailTextLabel.text=friendModel.intro;
//根据当前的好友是不是vip设置好友不同的名字显示颜色
self.textLabel.textColor=friendModel.isVip?[UIColor redColor]:[UIColor blackColor];
}
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
@end
4、创建FRGroupHeadView标题类
FRGroupHeadView.h
#import <UIKit/UIKit.h>
#import "FRFriendGroup.h"
@class FRGroupHeadView;
NS_ASSUME_NONNULL_BEGIN
//创建一个协议
@protocol FRGroupHeadViewDelegate <NSObject>
-(void)groupHeaderViewDidClickTitleButton:(FRGroupHeadView*) groupHeaderView;
@end
@interface FRGroupHeadView : UITableViewHeaderFooterView
@property(nonatomic,strong) FRFriendGroup* group;
//添加一个代理属性
@property(nonatomic,weak)id<FRGroupHeadViewDelegate> delegate;
-(void)didMoveToSuperview;
+(instancetype)groupHeaderViewWithTableView:(UITableView*)tableView;
@end
NS_ASSUME_NONNULL_END
FRGroupHeadView.m
#import "FRGroupHeadView.h"
#import "FRFriendGroup.h"
@interface FRGroupHeadView()
@property(nonatomic,weak)UIButton* btnGroupTitle;
@property(nonatomic,weak)UILabel* lblCount;
@end
@implementation FRGroupHeadView
//封装一个类方法来创建一个headerView
+(instancetype)groupHeaderViewWithTableView:(UITableView*)tableView{
//2、创建UITableViewHeaderFooterView,这里和创建单元格很像
static NSString* strId=@"group_header_view";
FRGroupHeadView* headerView=[tableView dequeueReusableHeaderFooterViewWithIdentifier:strId];
if (headerView==nil) {
//创建一个新的UITableViewHeaderFooterView
headerView=[[FRGroupHeadView alloc]initWithReuseIdentifier:strId];
}
//headerView.contentView.backgroundColor=[UIColor greenColor];
return headerView;
}
//重写initWithReuseIdentifier方法
-(instancetype)initWithReuseIdentifier:(NSString*)reuseIdentifier{
if (self=[super initWithReuseIdentifier:reuseIdentifier]) {
//创建按钮
UIButton *btnGroupTitle=[[UIButton alloc]init];
//设置按钮的图片
[btnGroupTitle setImage:[UIImage imageNamed:@"buddy_header_arrow"] forState:UIControlStateNormal];
//设置按钮的文字演示
[btnGroupTitle setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
//设置按钮的背景图
[btnGroupTitle setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg"] forState:UIControlStateNormal];
[btnGroupTitle setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg_highlighted"] forState:UIControlStateHighlighted];
//设置按钮内容左对齐
btnGroupTitle.contentHorizontalAlignment=UIControlContentHorizontalAlignmentLeft;
//设置按钮的左边距
btnGroupTitle.contentEdgeInsets=UIEdgeInsetsMake(0, 10, 0, 0);
//设置按钮标题距离左边的边距
btnGroupTitle.titleEdgeInsets=UIEdgeInsetsMake(0, 5, 0, 0);
//设置按钮的点击事件
[btnGroupTitle addTarget:self action:@selector(btnGroupTitleClicked) forControlEvents:UIControlEventTouchUpInside];
//设置按钮中图片的显示模式
btnGroupTitle.imageView.contentMode=UIViewContentModeCenter;
//设置图片框超出的部分不要截取
btnGroupTitle.imageView.clipsToBounds=NO;
//将按钮添加到contentview上
[self.contentView addSubview:btnGroupTitle];
self.btnGroupTitle=btnGroupTitle;
//创建lable
UILabel* lblCount=[[UILabel alloc]init];
[self.contentView addSubview:lblCount];
self.lblCount=lblCount;
}
return self;
}
//创建一个主标题按钮点击事件
-(void)btnGroupTitleClicked{
//1.设置组状态
self.group.visible = !self.group.isVisible;
//2.刷新tableview,通过代理来实现
if ([self.delegate respondsToSelector:@selector(groupHeaderViewDidClickTitleButton:)]) {
//调用代理方法
[self.delegate groupHeaderViewDidClickTitleButton:self];
}
}
//当一个新的headerview已经加载到某个父控件中的时候执行这个方法
-(void)didMoveToSuperview{
if (self.group.isVisible) {
//3、让按钮中的图片实现旋转
self.btnGroupTitle.imageView.transform=CGAffineTransformMakeRotation(M_PI_2);
}else{
//让按钮中的图片实现旋转回到原来的位置
self.btnGroupTitle.imageView.transform=CGAffineTransformMakeRotation(0);
}
}
//重写group的set方法
-(void)setGroup:(FRFriendGroup *)group{
_group=group;
//设置数据
[self.btnGroupTitle setTitle:group.name forState:UIControlStateNormal];
self.lblCount.text=[NSString stringWithFormat:@"%@ / %ld",group.online,group.friends.count];
//设置按钮中图片的旋转问题
if (self.group.isVisible) {
//3、让按钮中的图片实现旋转
self.btnGroupTitle.imageView.transform=CGAffineTransformMakeRotation(M_PI_2);
}else{
//让按钮中的图片实现旋转回到原来的位置
self.btnGroupTitle.imageView.transform=CGAffineTransformMakeRotation(0);
}
//设置frame不要写在这里
}
//重写重新布局子控件
//当年控件的frame发生改变的时候会调用这个方法
-(void)layoutSubviews{
[super layoutSubviews];
//设置frame
self.btnGroupTitle.frame=self.bounds;
CGFloat lblW=100;
CGFloat lblH=self.bounds.size.height;
CGFloat lblX=self.bounds.size.width-10-lblW;
CGFloat lblY=0;
self.lblCount.frame=CGRectMake(lblX, lblY, lblW, lblH);
}
@end
4、自定义FRQQFriendsTableViewController控制器类
FRQQFriendsTableViewController.m
#import "FRQQFriendsTableViewController.h"
#import "FRFriendGroup.h"
#import "FRFriend.h"
#import "FRFriendCell.h"
#import "FRGroupHeadView.h"
@interface FRQQFriendsTableViewController ()<FRGroupHeadViewDelegate>
//保存所有的分组信息
@property(nonatomic,strong)NSArray* groups;
@end
@implementation FRQQFriendsTableViewController
//实现FRGroupHeadViewDelegate代理方法
-(void)groupHeaderViewDidClickTitleButton:(FRGroupHeadView *)groupHeaderView{
//全局刷新tableview
//[self.tableView reloadData];
//局部刷新(只刷新某个组)
//创建一个用来表示某个组的对象
NSIndexSet* indexSet=[NSIndexSet indexSetWithIndex:groupHeaderView.tag];
[self.tableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationFade];
}
//懒加载数据
//重写group的get方法
-(NSArray*)groups{
if (_groups==nil) {
//获取plist文件路径
NSString* path=[[NSBundle mainBundle]pathForResource:@"friends.plist" ofType:nil];
//通过path路径获得plist文件中字典的集合
NSArray* arrayDict=[NSArray arrayWithContentsOfFile:path];
//创建group模型可变数组
NSMutableArray* arrayModelM=[NSMutableArray array];
//遍历字典数组
for (NSDictionary* dict in arrayDict) {
FRFriendGroup* groupModel=[FRFriendGroup groupWithDictionary:dict];
[arrayModelM addObject:groupModel];
}
//创建模型并将其加入模型数组中
_groups=arrayModelM;
}
//返回goups属性
return _groups;
}
- (void)viewDidLoad {
[super viewDidLoad];
//统一设置每组组标题的高度
self.tableView.sectionHeaderHeight=44;
}
#pragma mark - Table view data source
//返回数据源方法
//返回分组数量
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.groups.count;
}
//返回每组的行数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//因为要根据当前组的状态(是否展开),来设置不同的返回值,所以要为FRFriendGroup模型
//增加一个用来保存”是否展开“状态的属性
FRFriendGroup* group=self.groups[section];
if (group.isVisible) {//如果可见
return group.friends.count;//返回实际条数,即展开
}else{
return 0;//如果不可见,返回0条记录,即收拢
}
}
//返回每行的单元格
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//获取模型(数据)
//先获取组模型,在获取friend模型
FRFriendGroup* group=self.groups[indexPath.section];
FRFriend* friend=group.friends[indexPath.row];
//创建单元格(视图)
FRFriendCell *cell =[FRFriendCell friendCellWithTableView:tableView];
//给单元格赋值(把模型设置给单元格)
cell.friendModel=friend;
//返回单元格
return cell;
}
//设置每一组的组标题(该方法仅能设置组标题字符串,但我们需要更多的内容,该方法不太够用了)
/*
-(NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
//创建组模型
FRFriendGroup* group=self.groups[section];
//总组模型中取name属性
return group.name;
}
*/
//设置组标题返回一个view
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
//创建一个UITableViewHeaderFooterView,实现重用,千万不要创建UIView
//1、获取模型数据(分组模型就可以了)
FRFriendGroup* group=self.groups[section];
//2、创建UITableViewHeaderFooterView,这里和创建单元格很像
FRGroupHeadView* headerView=[FRGroupHeadView groupHeaderViewWithTableView:tableView];
headerView.tag=section;
//3、设置数据
headerView.group=group;
//设置headerView的代理为当前控制器
headerView.delegate=self;
//在刚刚创建好的headerView中获取的Frame都是0,因为我们没有为其frame赋值,因此其frame都是0,
//但程序运行时能看到起frame,是因为,当前方法中,将headerview返回以后,UITableView在执行时,会用到headerView,
//UITableView既然要用HeaderView,那么必须将headview添加到UITableView,UITableView内部会根据 一些设置来动态地为headerview的frame赋值,
//也就是,UITableView在即将用headerv的时候才会为headerview来设置值
//4、返回view
return headerView;
}
@end
效果:
源码下载
本文地址:https://blog.csdn.net/weixin_43745804/article/details/107178684