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 进行删除

OC删除故事板进行纯代码布局

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

![image-20220715155133669](/Users/admin/Library/Application Support/typora-user-images/image-20220715155133669.png)

4.遇到的问题:

  1. tabBar 除第一个外其他的底部选项卡的图标和 title 没有加载出来。

    如图所示:

    原因:对于 viewDidLoad 方法具体执行时间不清楚。虽然 AppDelegate 里面调用了该标签栏的页面,生成了实例,但是 viewDidLoad 方法还没执行,所以在实例方法里面定义的 tabBar 属性在 App 第一次加载的时候还没开始执行,对应的页面也没有显示出来。

    解决方法:将除第一个选项卡的 tabBar 属性写在 AppDelegate 里面

------------- 本文结束 感谢阅读 -------------