OC纯代码仿写微信首页记录文档
OC纯代码仿写微信首页记录文档
[toc]
0.前置知识
- 视图和控件
大致了解iOS 中的视图和控件的作用,苹果官方文档
一般APP的界面结构就是使用 导航栏 + 根视图+ 标签栏 构成的。
UIWindow
是一种特殊的 UIView,通常在一个 app 中只会有一个 UIWindow,iOS 程序启动完毕后,创建的第一个视图控件就是 UIWindow,接下来再创建其他控件。所以在 AppDelegate 中的 didFinishLaunchingWithOptions 方法中,先创建 UIwindow,再创建控制器,创建控制器的 view,然后将控制器的 view 添加到 UIWindow 上。
UITabBarController
选项卡控制器,与导航控制器一样,也被广泛用于各种ios应用程序。顾名思义,选项卡控制器在屏幕底部显示一系 “选项卡”,这些选项卡表示为图标和文本,用户触摸它们将在不同的场景间切换。和 UINavigationController 类似,UITabBarController 也可以用来控制多个页面导航,用户可以在多个视图控制器之间移动,并可以定制屏幕底部的选项卡栏。
UINavigationController
栈视图控制器,它必须设置一个 RootViewController 根控制器,页面跳转时,通过它将下一个子 ViewController 的视图添加到RootViewController 的视图中。
- 容器之间的关系图

1.删除 Main.StoryBoard
可以查看以下文档对 Main.StoryBoard 进行删除
2. 确定项目结构
先是创建一个 window,这个 window 的 rootViewController 是 UINavigationController,用于控制页面的跳转。UINavigationController 的 rootViewController 是一个 UITabBarController,用于控制首页各页面直接的切换。
项目目录结构如下:
.
├── AddressListViewController.h // 通讯录页
├── AddressListViewController.m
├── AppDelegate.h
├── AppDelegate.m
├── DiscoverViewController.h // 发现页
├── DiscoverViewController.m
├── Info.plist
├── MeViewController.h // 我
├── MeViewController.m
├── ViewController.h
├── ViewController.m
├── WeChatViewController.h // 微信页
├── WeChatViewController.m
└── main.m
AppDelegate 中的 didFinishLaunchingWithOptions 的方法
// 1.创建UIWindow
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// 设置UIWindow的背景颜色
self.window.backgroundColor = [UIColor whiteColor];
UITabBarController *tabBar = [[UITabBarController alloc] init];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:tabBar];
self.window.rootViewController = nav;
[[UITabBar appearance] setBackgroundColor:[UIColor systemGray5Color]];
UIViewController *c1 = [[WeChatViewController alloc] init];
UIViewController *c2 = [[AddressListViewController alloc] init];
c2.tabBarItem.title = @"通讯录";
c2.tabBarItem.image=[UIImage imageNamed:@"people.png"];
UIViewController *c3 = [[DiscoverViewController alloc]init];
c3.tabBarItem.title = @"发现";
c3.tabBarItem.image=[UIImage imageNamed:@"discover.png"];
UIViewController *c4 = [[MeViewController alloc]init];
c4.tabBarItem.title = @"我";
c4.tabBarItem.image = [UIImage imageNamed:@"me.png"];
// 将视图添加到tabBar上
tabBar.viewControllers = @[c1, c2, c3, c4];
// [tabBar addChildViewController:c1];
// [tabBar addChildViewController:c2];
// [tabBar addChildViewController:c3];
// [tabBar addChildViewController:c4];
[self.window makeKeyAndVisible];
AddressListViewController.m 文件
#import "AddressListViewController.h"
@interface AddressListViewController ()<UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, copy) NSArray *arr;
@end
@implementation AddressListViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.arr = @[@"科比", @"詹姆斯", @"欧文", @"乔丹", @"科比", @"詹姆斯", @"欧文", @"乔丹", @"科比", @"詹姆斯", @"欧文", @"乔丹", @"科比", @"詹姆斯", @"欧文", @"乔丹", @"科比", @"詹姆斯", @"欧文", @"乔丹", @"科比", @"詹姆斯", @"欧文", @"乔丹", @"乔丹", @"科比", @"詹姆斯", @"欧文", @"乔丹"];
// 创建UItableView,style选择Grouped或Plain,这里我们以Grouped为例
UITableView *tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 20) style:UITableViewStyleGrouped];
// 声明 tableView 的代理和数据源
tableView.delegate = self;
tableView.dataSource = self;
tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
tableView.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"people.png"]];
UISearchBar *search = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 40)];
search.searchBarStyle = UISearchBarStyleMinimal;
search.searchTextField.text = @"请输入要搜索的联系人";
// 添加到 view 上
[self.view addSubview:tableView];
[tableView addSubview:search];
}
// tableView 中 Section 的个数
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// 每个 Section 中的 Cell 个数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 22;
}
// 设置 cell 的高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 55;
}
// cell 的文字缩进
- (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath {
return 0;
}
// 选中了 cell 时触发
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"选中了第%li个cell", (long)indexPath.row);
UIViewController *detailView = [[UIViewController alloc]init];
NSString *title = self.arr[indexPath.row];
detailView.title = title;
detailView.view.backgroundColor = [UIColor systemGray3Color];
[self.navigationController pushViewController:detailView animated:YES];//跳转到下一界面
}
// 设置 cell 是否允许左滑
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return true;
}
// 设置默认的左滑按钮的title
- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath {
return @"删除";
}
// 点击左滑出现的按钮时触发
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"点击左滑出现的按钮时触发");
}
// 左滑结束时调用(只对默认的左滑按钮有效,自定义按钮时这个方法无效)
- (void)tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"左滑结束");
}
// 设置每个 Cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// 创建一个cellID,用于cell的重用
NSString *cellID = @"cellID";
// 从tableview的重用池里通过cellID取一个cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil) {
// 如果tableview的重用池中没有取到,就创建一个新的cell,style为Value2,并用cellID对其进行标记。
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
// 设置 cell 的标题
cell.textLabel.text = [NSString stringWithFormat:@"%@", self.arr[(long)indexPath.row]];
// cell右侧的效果
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.imageView.image = [UIImage imageNamed:@"me.png"];
return cell;
}
@end
3.查看页面布局
纯代码布局时,页面容器、控件直接的层级关系呈现的不直接,可以利用 Xcode 的自带功能查看
Debug -> View Debugging -> Capture View Hierarchy

4.遇到的问题:
tabBar 除第一个外其他的底部选项卡的图标和 title 没有加载出来。
如图所示:
原因:对于 viewDidLoad 方法具体执行时间不清楚。虽然 AppDelegate 里面调用了该标签栏的页面,生成了实例,但是 viewDidLoad 方法还没执行,所以在实例方法里面定义的 tabBar 属性在 App 第一次加载的时候还没开始执行,对应的页面也没有显示出来。
解决方法:将除第一个选项卡的 tabBar 属性写在 AppDelegate 里面