上几节课我们完成了更改系统tabBar 到完全自定义tabBar的转变,也完美的解决了导航条的功能和内容。本节课程,将会讲解新特性界面的搭建。顾名思义,新特性界面就是在用户第一次下载使用或者更新程序后,给用户展示并介绍应用程序的新功能的界面。程序需要判断用户是否是第一次使用本程序,如果是就展示新特性界面,如果不是,就直接展示程序界面。
本节主要内容
- 新特性界面的搭建
- 构建业务逻辑
本节资料下载
5.1 创建并展示新特性界面
通过观察新特性界面,我们推测出UICollectionViewController就可以完成其功能。而且在新特性最后一页会需要其他控件,所以我们要自定义一个UICollectionViewCell供UICollectionViewController使用。
使用UICollectionViewController有几点注意事项,一个是,其CollectionView上的Cell尺寸需要一个布局对象决定,所以我们要在初始化函数中创建一个布局参数。第二点,要给CollectionView注册一个cell,这点不能忘记。
然后思考自定义cell怎么设置,首先我们需要给自定义cell设置图片,还要重写其布局方法。为了不让外部更改cell内的imageView,我们在cell接口文件中仅仅暴露一个UIImage属性,根据image再设置执行文件中的UIImageView。
YGNewFeatureCell代码如下:
@interface YGNewFeatureCell ()
@property (nonatomic, weak) UIImageView *imageView;
@end
@implementation YGNewFeatureCell
- (UIImageView *)imageView
{
if (_imageView == nil) {
UIImageView *imageV = [[UIImageView alloc] init];
_imageView = imageV;
// 注意:一定要加载contentView
[self.contentView addSubview:imageV];
}
return _imageView;
}
// 布局子控件的frame
- (void)layoutSubviews
{
[super layoutSubviews];
self.imageView.frame = self.bounds;
}
- (void)setImage:(UIImage *)image
{
_image = image;
self.imageView.image = image;
}
@end
代码说明:首先cell的imageView懒加载的时候一定要加到cell的content View里。在image的set方法里,把image传值给imageView,并在布局函数中,设置其frame。
然后上UICollectionViewController执行代码:
static NSString * const reuseIdentifier = @"Cell";
- (instancetype)init
{
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
// 设置cell的尺寸
layout.itemSize = [UIScreen mainScreen].bounds.size;
// 清空行距
layout.minimumLineSpacing = 0;
// 设置滚动的方向
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
return [super initWithCollectionViewLayout:layout];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = NO;
// Register cell classes
[self.collectionView registerClass:[YGNewFeatureCell class] forCellWithReuseIdentifier:reuseIdentifier];
// Do any additional setup after loading the view.
// 分页
self.collectionView.pagingEnabled = YES;
self.collectionView.bounces = NO;
self.collectionView.showsHorizontalScrollIndicator = NO;
}
#pragma mark <UICollectionViewDataSource>
// 返回有多少组
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
// 返回第section组有多少个cell
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 4;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
YGNewFeatureCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
CGFloat screenH = [UIScreen mainScreen].bounds.size.height;
NSString *imageName = [NSString stringWithFormat:@"new_feature_%ld",indexPath.row + 1];
NSLog(@"%@",imageName);
cell.image = [UIImage imageNamed:imageName];
return cell;
}
在初始化函数中,创建并设置controller的布局参数。在viewDidLoad中注册一个自定义cell,然后就是按部就班把collectionViewController的dataSource函数写完整。这里说明下dequeue的执行过程,首先是先从缓存池中取cell,如果缓存池里没有,就判断当前是否注册了cell,如果有就自己创建一个cell,没有注册,就会报错。
这里如果我们想验证新特性界面是否能正常显示,可以修改AppDelegate函数,把窗口的根控制器暂时替换为新特性界面,代码如下:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
NSLog(@"%s",__func__);
// 创建窗口
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
//判断当前是否有新的版本,如果有新特性,进入新特性界面
YGNewFeatureController *newFeature = [[YGNewFeatureController alloc]init];
//创建自定义tabbarcontroller
//YGTabBarController *tabBarVc = [[YGTabBarController alloc]init];
// 设置窗口的根控制器
self.window.rootViewController = newFeature;
// 显示窗口
[self.window makeKeyAndVisible];
return YES;
}
5.2 新特性界面的优化
这个小节需要完成两个任务,一是用红色的亮点去表示现在在第几个界面。二是在新特性界面最后一个页面内添加其他控件,包括一个分享按钮和一个直接开始微博按钮。
先从设置UIPageControl 开始,首先要添加一个UIPageControl的属性。
@property (nonatomic, weak) UIPageControl *control;
然后在viewDidLoad代码内添加[self setUpPageControl];
,把其单独抽取出来,代码如下:
// 添加pageController
- (void)setUpPageControl
{
// 添加pageController,只需要设置位置,不需要管理尺寸
UIPageControl *control = [[UIPageControl alloc] init];
control.numberOfPages = 4;
control.pageIndicatorTintColor = [UIColor blackColor];
control.currentPageIndicatorTintColor = [UIColor redColor];
// 设置center
control.center = CGPointMake(self.view.width * 0.5, self.view.height);
_control = control;
[self.view addSubview:control];
}
每当我们滑动图片的时候,其indicator都会改变,这就需要使用UIScrollView的代理方法:
#pragma mark - UIScrollView代理
// 只要一滚动就会调用
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
// 获取当前的偏移量,计算当前第几页
int page = scrollView.contentOffset.x / scrollView.bounds.size.width + 0.5;
// 设置页数
_control.currentPage = page;
}
现在运行项目,则会显示我们很完美的解决了PageControl的问题。
下面就讲解如何在最后一个界面内添加合适的按钮。
首先添加两个按钮属性:
@property (nonatomic, weak) UIButton *shareButton;
@property (nonatomic, weak) UIButton *startButton;
然后重写各自懒加载方法:
- (UIButton *)shareButton
{
if (_shareButton == nil) {
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
[btn setTitle:@"分享给大家" forState:UIControlStateNormal];
[btn setImage:[UIImage imageNamed:@"new_feature_share_false"] forState:UIControlStateNormal];
[btn setImage:[UIImage imageNamed:@"new_feature_share_true"] forState:UIControlStateSelected];
[btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[btn sizeToFit];
[self.contentView addSubview:btn];
_shareButton = btn;
}
return _shareButton;
}
- (UIButton *)startButton
{
if (_startButton == nil) {
UIButton *startBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[startBtn setTitle:@"开始微博" forState:UIControlStateNormal];
[startBtn setBackgroundImage:[UIImage imageNamed:@"new_feature_finish_button"] forState:UIControlStateNormal];
[startBtn setBackgroundImage:[UIImage imageNamed:@"new_feature_finish_button_highlighted"] forState:UIControlStateHighlighted];
[startBtn sizeToFit];
[startBtn addTarget:self action:@selector(start) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:startBtn];
_startButton = startBtn;
}
return _startButton;
}
这里我们只添加了点击打开微博按钮后的方法,没有设置分享按钮的功能,@selector(start) 的代码如下:
// 点击开始微博的时候调用
- (void)start
{
// 进入tabBarVc
YGTabBarController *tabBarVc = [[YGTabBarController alloc] init];
// 切换根控制器:可以直接把之前的根控制器清空
YGKeyWindow.rootViewController = tabBarVc;
}
然后我们为这两个按钮设置位置和大小,在layOutSubviews里添加如下代码:
// 分享按钮
self.shareButton.center = CGPointMake(self.width * 0.5, self.height * 0.8);
// 开始按钮
self.startButton.center = CGPointMake(self.width * 0.5, self.height * 0.9);
最后我们要给cell增加一个方法,用来判断是否到最后一页,如果到最后一页就显示按钮,不是的话就隐藏按钮,自定义cell增加的方法为:
// 判断当前cell是否是最后一页
- (void)setIndexPath:(NSIndexPath *)indexPath count:(int)count
{
if (indexPath.row == count - 1) { // 最后一页,显示分享和开始按钮
self.shareButton.hidden = NO;
self.startButton.hidden = NO;
}else{ // 非最后一页,隐藏分享和开始按钮
self.shareButton.hidden = YES;
self.startButton.hidden = YES;
}
}
别忘了在controller文件的代理方法内添加[cell setIndexPath:indexPath count:4];
用来每次检查是否是最后一页。
5.3 业务逻辑的处理
可以知道,新特性界面只需要展示一次即可。当用户更新版本之后就展示,没有更新就不展示。稍微思考下就知道,这个业务逻辑需要在AppDelegate去完成。业务逻辑可以分为以下几个步骤,首先要获取当前版本号,然后要用用户偏好设置去获取上一个版本号。用户偏好设置有两个优点,一个是不需要关心文件名,另一个是可以快速进行键值对存储。最后判断当前版本号和上一个存储的版本号是否相同。代码如下:
//1.获取当前版本号
NSString *currentVerison = [NSBundle mainBundle].infoDictionary[@"CFBundleVersion"];
//2.获取上一次版本号
NSString *lastVersion = [[NSUserDefaults standardUserDefaults] objectForKey:YGVersionKey];
//3.判断当前是否有新的版本,如果有新特性,进入新特性界面
if ([currentVerison isEqualToString:lastVersion]) {//没有最新版本号
//创建自定义tabbarcontroller
YGTabBarController *tabBarVc = [[YGTabBarController alloc]init];
// 设置窗口的根控制器
self.window.rootViewController = tabBarVc;
}else{//有最新版本号,进入新特性界面
YGNewFeatureController *newFeature = [[YGNewFeatureController alloc]init];
//保存当前版本
[[NSUserDefaults standardUserDefaults] setObject:currentVerison forKey:YGVersionKey];
// 设置窗口的根控制器
self.window.rootViewController = newFeature;
}
第一次运行程序的时候会显示新特性界面,再次按command+r运行程序就会直接显示微博界面。如果你想验证代码是否正确,可以打开info.plist文件,在BundleVersion里增加版本号如下图,
再次运行就会发现又进入新特性界面了。
至此我们就完成了新特性界面的搭建以及业务逻辑的实现,下节课我们将会讲解如何使用微博API接口获取微博数据,真正显示微博的时刻快要到来了,很兴奋吧。