iOS-UI-QQ好友界面實現

一.項目前準備

1.pch文件如下

//  Prefix header
//
//  The contents of this file are implicitly included at the beginning of every source file.
//

#import <Availability.h>

#ifndef __IPHONE_5_0
#warning "This project uses features only available in iOS SDK 5.0 and later."
#endif

#ifdef __OBJC__
    #import <UIKit/UIKit.h>
    #import <Foundation/Foundation.h>
#endif
2.friends.plist文件如下


3.根控制器設置爲MJTableViewController



二.使用MVC開發模式

1.模型文件分別是朋友模型和組模型

①.朋友模型:

//  MJFriend.h

#import <Foundation/Foundation.h>

@interface MJFriend : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *icon;
@property (nonatomic, copy) NSString *intro;
@property (nonatomic, assign, getter = isVip) BOOL vip;

+ (instancetype)friendWithDict:(NSDictionary *)dict;
- (instancetype)initWithDict:(NSDictionary *)dict;
@end
//  MJFriend.m

#import "MJFriend.h"

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

- (instancetype)initWithDict:(NSDictionary *)dict
{
    if (self = [super init]) {
        [self setValuesForKeysWithDictionary:dict];
    }
    return self;
}
@end
②.組模型:

//  MJFriendGroup.h

#import <Foundation/Foundation.h>

@interface MJFriendGroup : NSObject
@property (nonatomic, copy) NSString *name;
/**
 *  數組中裝的都是MJFriend模型
 */
@property (nonatomic, strong) NSArray *friends;
@property (nonatomic, assign) int online;

/**
 *  標識這組是否需要展開,  YES : 展開 ,  NO : 關閉
 */
@property (nonatomic, assign, getter = isOpened) BOOL opened;

+ (instancetype)groupWithDict:(NSDictionary *)dict;
- (instancetype)initWithDict:(NSDictionary *)dict;
@end
//  MJFriendGroup.m

#import "MJFriendGroup.h"
#import "MJFriend.h"

@implementation MJFriendGroup
+ (instancetype)groupWithDict:(NSDictionary *)dict
{
    return [[self alloc] initWithDict:dict];
}

//將friends的數據存起來
- (instancetype)initWithDict:(NSDictionary *)dict
{
    if (self = [super init]) {
        // 1.注入所有屬性
        [self setValuesForKeysWithDictionary:dict];
        
        // 2.特殊處理friends屬性
        NSMutableArray *friendArray = [NSMutableArray array];
        for (NSDictionary *dict in self.friends) {
            MJFriend *friend = [MJFriend friendWithDict:dict];
            [friendArray addObject:friend];
        }
        self.friends = friendArray;
    }
    return self;
}
@end

2.View文件代碼:

①.cell代碼

//  MJFriendCell.h

#import <UIKit/UIKit.h>
@class MJFriend;

@interface MJFriendCell : UITableViewCell
+ (instancetype)cellWithTableView:(UITableView *)tableView;
// friend是C++的關鍵字,不能用friend作爲屬性名
@property (nonatomic, strong) MJFriend *friendData;
@end
//  MJFriendCell.m

#import "MJFriendCell.h"
#import "MJFriend.h"

@implementation MJFriendCell

+ (instancetype)cellWithTableView:(UITableView *)tableView
{
    static NSString *ID = @"friend";
    MJFriendCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        cell = [[MJFriendCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
    }
    return cell;
}

- (void)setFriendData:(MJFriend *)friendData
{
    _friendData = friendData;
    
    self.imageView.image = [UIImage imageNamed:friendData.icon];
    self.textLabel.text = friendData.name;
    self.textLabel.textColor = friendData.isVip ? [UIColor redColor] : [UIColor blackColor];
    self.detailTextLabel.text = friendData.intro;
}
@end

②.組視圖代碼

//  MJHeaderView.h

#import <UIKit/UIKit.h>

@class MJFriendGroup, MJHeaderView;

//點擊了頭視圖,傳遞給控制器
@protocol MJHeaderViewDelegate <NSObject>
@optional
- (void)headerViewDidClickedNameView:(MJHeaderView *)headerView;
@end


@interface MJHeaderView : UITableViewHeaderFooterView

+ (instancetype)headerViewWithTableView:(UITableView *)tableView;


@property (nonatomic, strong) MJFriendGroup *group;
@property (nonatomic, weak) id<MJHeaderViewDelegate> delegate;

@end
//  MJHeaderView.m

#import "MJHeaderView.h"
#import "MJFriendGroup.h"

/**
 某個控件出不來:
 1.frame的尺寸和位置對不對
 
 2.hidden是否爲YES
 
 3.有沒有添加到父控件中
 
 4.alpha 是否 < 0.01
 
 5.被其他控件擋住了
 
 6.父控件的前面5個情況
 */

@interface MJHeaderView()
@property (nonatomic, weak) UILabel *countView;
@property (nonatomic, weak) UIButton *nameView;
@end

@implementation MJHeaderView

+ (instancetype)headerViewWithTableView:(UITableView *)tableView
{
    static NSString *ID = @"header";
    MJHeaderView *header = [tableView dequeueReusableHeaderFooterViewWithIdentifier:ID];
    if (header == nil) {
        header = [[MJHeaderView alloc] initWithReuseIdentifier:ID];
    }
    return header;
}

/**
 *  在這個初始化方法中,MJHeaderView的frame\bounds沒有值
 */
- (id)initWithReuseIdentifier:(NSString *)reuseIdentifier
{
    if (self = [super initWithReuseIdentifier:reuseIdentifier]) {
        // 添加子控件
        // 1.添加按鈕
        UIButton *nameView = [UIButton buttonWithType:UIButtonTypeCustom];
        // 背景圖片
        [nameView setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg"] forState:UIControlStateNormal];
        [nameView setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg_highlighted"] forState:UIControlStateHighlighted];
        // 設置按鈕內部的左邊箭頭圖片
        [nameView setImage:[UIImage imageNamed:@"buddy_header_arrow"] forState:UIControlStateNormal];
        [nameView setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        // 設置按鈕的內容左對齊
        nameView.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
        // 設置按鈕的內邊距
//        nameView.imageEdgeInsets
        nameView.titleEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
        nameView.contentEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
        [nameView addTarget:self action:@selector(nameViewClick) forControlEvents:UIControlEventTouchUpInside];
        
        // 設置按鈕內部的imageView的內容模式爲居中
        nameView.imageView.contentMode = UIViewContentModeCenter;
        // 超出邊框的內容不需要裁剪
        nameView.imageView.clipsToBounds = NO;
        
        [self.contentView addSubview:nameView];
        self.nameView = nameView;
        
        // 2.添加好友數
        UILabel *countView = [[UILabel alloc] init];
        countView.textAlignment = NSTextAlignmentRight;
        countView.textColor = [UIColor grayColor];
        [self.contentView addSubview:countView];
        self.countView = countView;
    }
    return self;
}

/**
 *  當一個控件的frame發生改變的時候就會調用
 *
 *  一般在這裏佈局內部的子控件(設置子控件的frame)
 */
- (void)layoutSubviews
{
#warning 一定要調用super的方法
    [super layoutSubviews];
    
    // 1.設置按鈕的frame
    self.nameView.frame = self.bounds;
    
    // 2.設置好友數的frame
    CGFloat countY = 0;
    CGFloat countH = self.frame.size.height;
    CGFloat countW = 150;
    CGFloat countX = self.frame.size.width - 10 - countW;
    self.countView.frame = CGRectMake(countX, countY, countW, countH);
}

- (void)setGroup:(MJFriendGroup *)group
{
    _group = group;
    
    // 1.設置按鈕文字(組名)
    [self.nameView setTitle:group.name forState:UIControlStateNormal];
    
    // 2.設置好友數(在線數/總數)
    self.countView.text = [NSString stringWithFormat:@"%d/%d", group.online, group.friends.count];
}

/**
 *  監聽組名按鈕的點擊
 */
- (void)nameViewClick
{
    // 1.修改組模型的標記(狀態取反)
    self.group.opened = !self.group.isOpened;
    
    // 2.刷新表格  點擊那個頭視圖就把誰傳過去
    if ([self.delegate respondsToSelector:@selector(headerViewDidClickedNameView:)]) {
        [self.delegate headerViewDidClickedNameView:self];
    }
}

/**
 *  當一個控件被添加到父控件中就會調用,如果把這個方法裏面的代碼寫在nameViewClick裏面,這樣點擊按鈕的時候控制器就會刷新cell,就會從緩存池裏面取出新的headview,這樣我們的旋轉就沒用了,所以我們把旋轉的處理寫在這個方法裏面
 */
- (void)didMoveToSuperview
{
    if (self.group.opened) {
        self.nameView.imageView.transform = CGAffineTransformMakeRotation(M_PI_2);
    } else {
        self.nameView.imageView.transform = CGAffineTransformMakeRotation(0);
    }
}

/**
 *  當一個控件即將被添加到父控件中會調用
 */
//- (void)willMoveToSuperview:(UIView *)newSuperview
//{
//    
//}
@end

3.控制器文件如下

.h文件

//  MJViewController.h

#import <UIKit/UIKit.h>

@interface MJViewController : UITableViewController

@end
.m文件

//  MJViewController.m

#import "MJViewController.h"
#import "MJFriendGroup.h"
#import "MJFriend.h"
#import "MJHeaderView.h"
#import "MJFriendCell.h"

@interface MJViewController () <MJHeaderViewDelegate>
@property (nonatomic, strong) NSArray *groups;
@end

@implementation MJViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // 每一行cell的高度
    self.tableView.rowHeight = 50;
    // 每一組頭部控件的高度
    self.tableView.sectionHeaderHeight = 44;
}

- (NSArray *)groups
{
    if (_groups == nil) {
        NSArray *dictArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"friends.plist" ofType:nil]];
        
        NSMutableArray *groupArray = [NSMutableArray array];
        for (NSDictionary *dict in dictArray) {
            MJFriendGroup *group = [MJFriendGroup groupWithDict:dict];
            [groupArray addObject:group];
        }
        
        _groups = groupArray;
    }
    return _groups;
}

- (BOOL)prefersStatusBarHidden
{
    return YES;
}

#pragma mark - 數據源方法
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return self.groups.count;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    MJFriendGroup *group = self.groups[section];
    
    return (group.isOpened ? group.friends.count : 0);
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 1.創建cell
    MJFriendCell *cell = [MJFriendCell cellWithTableView:tableView];
    
    // 2.設置cell的數據
    MJFriendGroup *group = self.groups[indexPath.section];
    cell.friendData = group.friends[indexPath.row];
    
    return cell;
}

/**
 *  返回每一組需要顯示的頭部標題(字符出納)
 */
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    // 1.創建頭部控件
    MJHeaderView *header = [MJHeaderView headerViewWithTableView:tableView];
    header.delegate = self;
    
    // 2.給header設置數據(給header傳遞模型)
    header.group = self.groups[section];
    
    return header;
}

#pragma mark - headerView的代理方法
/**
 *  點擊了headerView上面的名字按鈕時就會調用, 重新刷新cell
 */
- (void)headerViewDidClickedNameView:(MJHeaderView *)headerView
{
    [self.tableView reloadData];
}
@end



發佈了4 篇原創文章 · 獲贊 1 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章