引子
之前曾经做过一个渣渣天气预报,链接,无论是UI搭建还是业务逻辑都非常感人……总结就是一个字:“丑”,不久前看到 ManoBoo大大的 壁纸天气,有种眼前一亮的感觉,再回想自己做第一个天气预报项目时候种种别出心裁 瞎搞 的设计方案,一瞬间羞愤欲死 (但是很快就缓过来了),决定临摹一个出来。
预览
懒癌发作……先不码字了,挖个坑先
初始界面
1 . 首先在进入App的时候进行判断,看是不是第一次加载App,如果是的话,需要从初始化一下热门城市的配置。
// 在AppDelegate中执行这段代码,判断并初始化热门城市列表
- (void)setInitData{
BOOL isFirstStart;
id obj = [[NSUserDefaults standardUserDefaults] objectForKey:IsFirstStartKey];
if (obj == nil) {
isFirstStart = YES;
}else {
isFirstStart = NO;
}
if (isFirstStart ) {
[[CKCityManager shareInstance] setupHotCities];//配置热门城市列表
isFirstStart = NO;
// 存储YES至 对应的Key
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:isFirstStart] forKey:IsFirstStartKey];
}
}
CKCityManager 是一个全局的单例类,用来储存及操作之后的城市选择
包含下面几个方法,基本能够囊括项目中的需求。
// 初始化
+ (instancetype)shareInstance;
/** 是否已有选择的城市 */
- (BOOL)hasSelectedCity;
/** 初始化热门城市(8个) */
- (void)setupHotCities;
/** 返回热门城市列表 */
- (NSArray *)getHotCities;
/** 存储选定的城市 */
- (void)saveCityWithModel:(CKCityModel *)model;
/** 返回已经选定的城市 */
- (NSArray *)savedCities;
代码相对来说都不算太复杂,都是一些根据设定好的key值,再使用NSUserDefaults 读取相关的Key值之类的操作。
2 . 根控制器 CKHomeWeatherController
这个页面用来展示全局 (已选择) 城市的天气概况,仿照ManoBoo大大的思想,隐藏掉NavigationBar (只是隐藏,实际上仍然存在),取消使用tabbar进行页面跳转操作,改用一个动画效果弹出的按钮来搞定基本的页面操作。
底部那4个一排就是按钮组,最后面蓝色的指纹按钮是basicOperationButton(BOB),另外三个是功能性按钮,正常为隐藏状态,BOB被点击时,其会弹出并呈扇形排布在BOB上方,再次点击后隐藏。
具体执行起来与普通的按钮状态取反很相似,动画效果一开始比较懵,理清楚思路后发现也不算很难。
- (void)showButtonsArray {
WeakSelf;
if (_showOperationButtons) {
_showOperationButtons = NO;
[weakSelf.operationBtnArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
UIButton *btn = (UIButton *)obj;
CGRect frame = weakSelf.operationButton.frame;
float duration = 0.0;
[UIView animateWithDuration:0.4 delay:duration options:UIViewAnimationOptionCurveEaseInOut animations:^{
btn.alpha = 0.0;
btn.frame = frame;
btn.transform = CGAffineTransformMakeRotation(M_PI);
} completion:^(BOOL finished) {
}];
}];
}else{
_showOperationButtons = YES;
[weakSelf.operationBtnArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
UIButton *button = (UIButton *)obj;
//更改后 frame
CGRect frame = button.frame;
frame.size.width = frame.size.height = 44;
//延时
float duration = 0.0;
switch (idx) {
case 0: {
frame.origin.x -= 50 * sqrt(2);
frame.origin.y -= 50 * sqrt(2);
}
break;
case 1: {
frame.origin.y -= 100;
duration = 0.1;
}
break;
case 2: {
frame.origin.x += 50 * sqrt(2);
frame.origin.y -= 50 * sqrt(2);
duration = 0.25;
}
break;
}
// 按延迟 将三个button 按顺序依次弹出
[UIView animateWithDuration:0.4 delay:duration options:UIViewAnimationOptionCurveEaseInOut animations:^{
button.alpha = 1.0;
button.frame = frame;
button.transform = CGAffineTransformMakeRotation(M_PI * 2);
} completion:nil];
}];
}
}
// 具体按钮点击的Push操作
- (void)aboutMe {
[self showButtonsArray]; // 也调用一次上面的方法,达到隐藏按钮队列的作用
AboutMeController *meVc = [[AboutMeController alloc] init];
[self.navigationController pushViewController:meVc
animated:YES];
}
// 老实说刚读源码的时候看着sqrt一脸懵逼,后来发现原始就是开平方……感叹一下早期学的都还给老师了
// 突然想到自己的Note3,手写笔抽出来的时候也会显示出一个类似的扇形操作界面。
因为只是一个将按钮显示出来的动画,不存在什么交叉target,相对来说比较独立。
3 . nullDataView
如果在进入根控制器后解析不到selectedCities,则加载nullDataView到界面。
// 设置无数据时显示的界面
- (void)setupNullDataView {
if (![[CKCityManager shareInstance] hasSelectedCity]) {
if (!_nullView) {
_nullView = [[NullDataView alloc] initWithFrame:[UIScreen mainScreen].bounds];
[self.view addSubview:_nullView];
}
_nullView.hidden = NO;
_tableView.hidden = YES;
} else { // 如果不是第一次进入App,显示tableView 并加载数据
_nullView.hidden = YES;
_tableView.hidden = NO;
[self loadNewData];
}
}
// 一开始思路有问题……导致选取了城市后pop页面回来仍然显示nullDataView
秉承的思想是 viewDidLoad和viewWillAppear 这俩方法,
viewDidLoad中只负责addSubView ,具体的setup loadNewData ,刷新页面都放在viewWillAppear 中解决 。
懒癌发作……睡一觉再说