一、如何获取要模仿的APP素材。
当我想写新浪微博这个项目的时候,首先想到的就是如何获得他的UI,那么这是一个很简单的事情,我们可以在mac电脑的iTunes当中下载该ipa,然后打开获得其中的东西,当我们想做一个类似的软件的时候都可以这样做的。
下载方式如下详情:
如图所示,打开iTunes
然后点击获取,进行下载
下载完成以后如何找到该文件呢,如下图所示,前往个人,
然后按照以下的目录结构找到我们刚才下载的新浪微博ipa
上方显示的是还在下载过程当中所显示的文件,当下载完成的时候是这样的:
然后对该ipa进行解压操作:
打开后对里面的文件=》显示包内容,然后里面就是我们想要的UI图片等内容。如图所示:
二、工程搭建及注意事项
当我们新建好工程后,第一件事情就是环境的配置,然而
最开始就是设置bundle id
一般bundle id在创建项目的时候项目经理会告诉你这个值是什么。他的作用是什么呢?
(唯一标识符)bundle id作用:
首先、他在产品上线的时候回用到,
第二、就是在我们做推送的时候会用到这个值(通过该标示找到这个软件)
然后进行版本号(即上图的Version)的设置,版本号在上线的时候每一次都要比前一次的版本号大。
第四、我们deployment Info中设置我们的软件支持iOS几,即iOS6以上,下图就是支持iOS6以上,如果我们选择6.0的话。不过现在6.0已经淘汰了,我们选择的时候选择支持7.0以上就好了。
第五、我们要删掉main函数,(我们要纯代码实现,所以main interface为空就好了,如果我们要用storyboard实现,这个不要删掉)不删掉的话他的运行流程是,首先加载main函数,然后该函数给你创建一个uiapplicationdelegate的单例对象,然后开启一个主运行循环(如果不执行主运行循环,该函数一运行完程序就结束了, √为了保证程序不会马上结束,所以让他一直跑起来 √还能接通用户的事件,例如触摸事件等) 然后加载info.plist文件,判断info.plist文件里面有没有指定的main.storyboard,如果指定,就会去加载main.storyboard.
《我们要纯代码实现,所以main interface为空就行,还有就是工程中的main.storyboard和view controller也删除(因为view controller是默认和main.storyboard关联的),我们完全纯代码,无需这些》
//main.storyboard
//1、初始化窗口
//2、加载storyboard文件,并且创建箭头指向的控制器
//3、把新创建的控制器作为窗口的根控制器,让窗口显示。
代码实现加载该storyboard,并让其为箭头指向的控制器。
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"main" bundle:nil];
//instantiateInitialViewController:默认加载箭头指向的控制器
[storyboard instantiateInitialViewController];
第六、设置设备是否旋转,然后设置状态栏,设置状态栏可以看这:http://blog.csdn.net/liyunxiangrxm/article/details/50923088。
然后可以设置图标和启动屏:http://blog.csdn.net/liyunxiangrxm/article/details/50923307
我们上方没有设置主窗口,所以我们得在程序启动后代码创建:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
//创建窗口
self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
self.window.backgroundColor = [UIColor yellowColor];
//显示窗口
[self.window makeKeyAndVisible];
return YES;
}
接下来我们往里增加tabbar等,把winndow的根控制器用sabbatcontroller来充当。继而完成框架的搭建,具体看github的代码。
三、自定义普通的TabBarController
1、自定义TabBarController,创建文件的时候加前缀,方便我们识别工程。加前缀的地方如下图:Class Prefix 我加的前缀是HM
2、控制器的view详解:
√UITabBarController控制器的View在一创建控制器的时候就会加载view
√UIViewController的View才是懒加载(就是在用到的时候才会调用)。通过给viewDidLoad加断点然后调用即可试出来。
3、 封装思想:如果以后项目中,有相同的功能,抽取一个类,封装好
如何封装类:做到自己的事情全部交给自己管理。
抽方法:一般一个功能就抽一个方法,以后开发中如果有相同的功能,找到对应的类就能找到功能
4、在ios7之后,默认会把UITabBar上面的按钮图片渲染成蓝色,一般需要告诉图片保持最原始的图片,或者在image.xcassest里面设置render模式
1> 如下图所示,在Render As那儿下拉框中选择Original Image ,这样就好了,既然这里能够修改,那么代码肯定能够修改,所以我们最好用代码修改,因为代码我们可以封装成一个方法直接调用,这里修改的话每张图片都要设置,是特别麻烦的。
2>用代码修改,使其保持最原始的图片:
UIImage *selImage = [UIImage imageNamed:selImageName];
selImage = [selImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
5、设置tabbar下面的字体的颜色:导入框架,直接里面找,不用记。(字典) 全局的直接一句代码全部搞定《这行是我自己的概要,可以不看的》
1>修改字体颜色:
tabbarItem相关知识点:tabbarItem不是一个控件,用的时候我们可以用它里面的方法和它父类的方法进行修改它的属性。
@interface UITabBarItem : UIBarItem UIBarItem : NSObject <NSCoding, UIAppearance>
从这里我们可以看到继承关系,UITabBarItem不是一个控件,而是一个对象,所以我们调用他的属性的时候需要用到它里面的方法。
下面举例:
@property(nullable, nonatomic,strong) UIImage *landscapeImagePhone NS_AVAILABLE_IOS(5_0) __TVOS_PROHIBITED; // default is nil
@property(nonatomic) UIEdgeInsets imageInsets; // default is UIEdgeInsetsZero
@property(nonatomic) UIEdgeInsets landscapeImagePhoneInsets NS_AVAILABLE_IOS(5_0) __TVOS_PROHIBITED; // default is UIEdgeInsetsZero. These insets apply only when the landscapeImagePhone property is set.
@property(nonatomic) NSInteger tag; // default is 0
/* You may specify the font, text color, and shadow properties for the title in the text attributes dictionary, using the keys found in NSAttributedString.h.
*/
- (void)setTitleTextAttributes:(nullable NSDictionary<NSString *,id> *)attributes forState:(UIControlState)state NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR;
- (nullable NSDictionary<NSString *,id> *)titleTextAttributesForState:(UIControlState)state NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR;
当我们改变tabbarItem中字体的颜色的时候,需要用到上面的方法。改变字体的颜色具体方法如下:
NSMutableDictionary *att = [NSMutableDictionary dictionary];
att[NSForegroundColorAttributeName] = [UIColor orangeColor];
// [att setObject:[UIColor orangeColor] forKey:NSForegroundColorAttributeName];
[vc.tabBarItem setTitleTextAttributes:att forState:UIControlStateSelected];
当我们不知道KVC中的某个Key的时候,不要着急,这个也不用背下来,我们可以导入一个库,然后直接从库里面找到该Key,并且库中还告诉你应对该key应该填入的是什么类型的数据:如下图:按照图上把UIKIt加进去,然后打开第一个就可以知道里面的所有方法。
6、appearance方法。什么对象才能用appearance<这是协议中的一个方法,只要一个类遵守这个协议,就可以拿到这个外观>
当我们想改动item的字体颜色的时候我们可以在外部获取该对象,然后进行修改,这样所有的都能修改。
例如:
UITabBarItem *item = [UITabBarItem appearance];
NSMutableDictionary *att = [NSMutableDictionary dictionary];
att[NSForegroundColorAttributeName] = [UIColor orangeColor];
[item setTitleTextAttributes:att forState:UIControlStateNormal];
上方的appearance方法在某些时候是很好用的,但是在这个不严谨,所有的tabbaritem的这个属性都会改变,所以有时候不采取这个做法,例如我获取了view,然后进行设置:
UIView *view = [UIView appearance];
view.backgroundColor = [UIColor redColor];
最终出现了下方的景象,所以有时候不推荐使用:
7、模型设计思想 instancetype 最好用这个 id定义没有点语法 instancetype定义有点语法
就是用instancetype的话在对象访问成员变量的时候有点语法,而用id得花就没有。
8、形成最基本的自定义tabbar的代码如下:自定义TabBarController中的.m代码:
//
// HMTabBarController.m
// WeiBo
//
// Created by 李云祥 on 16/8/4.
// Copyright © 2016年 李云祥. All rights reserved.
//
#import "HMTabBarController.h"
@interface HMTabBarController ()
@end
@implementation HMTabBarController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor whiteColor];
[self setUpAllChildViewController];
}
-(void)setUpAllChildViewController
{
UIViewController *home = [[UIViewController alloc]init];
[self setUpChildViewController:home title:@"首页" imageName:@"tabbar_home" selImageName:@"tabbar_home_selected"];
UIViewController *message = [[UIViewController alloc]init];
[self setUpChildViewController:message title:@"消息" imageName:@"tabbar_message_center" selImageName:@"tabbar_message_center_selected"];
UIViewController *discover = [[UIViewController alloc]init];
[self setUpChildViewController:discover title:@"发现" imageName:@"tabbar_discover" selImageName:@"tabbar_discover_selected"];
UIViewController *profile = [[UIViewController alloc]init];
[self setUpChildViewController:profile title:@"我" imageName:@"tabbar_profile" selImageName:@"tabbar_profile_selected"];
}
-(void)setUpChildViewController:(UIViewController *)vc title:(NSString *)title imageName:(NSString *)imageName selImageName:(NSString *)selImageName
{
vc.title = title;
vc.tabBarItem.image = [[UIImage imageNamed:imageName] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
UIImage *selImage = [[UIImage imageNamed:selImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
NSMutableDictionary *att = [NSMutableDictionary dictionary];
att[NSForegroundColorAttributeName] = [UIColor orangeColor];
// [att setObject:[UIColor orangeColor] forKey:NSForegroundColorAttributeName];
[vc.tabBarItem setTitleTextAttributes:att forState:UIControlStateSelected];
vc.tabBarItem.selectedImage = selImage;
[self addChildViewController:vc];
}
@end
AppDelegate中直接用就行,如下:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
HMTabBarController *tabBarVc = [[HMTabBarController alloc]init];
self.window.rootViewController = tabBarVc;
[self.window makeKeyAndVisible];
return YES;
}
最终的效果图如下:
四、自定义微博的TabBarController (中间有一块儿加号)
用到的知识点:
1、当我在自定义tabbar后,我想把我自己的tabbar付给系统的tabbar,但是self.tabBar = tabbar;报错,因为
@property(nonatomic,readonly) UITabBar *tabBar 只读属性,如果想赋值的话需要用kvc kvc修改readonly属性
所以我用了
[selfsetValue:tabbar forKeyPath:@"tabBar"];
2、在做微博中间的那个按钮的时候,我想这个按钮的大小正好是给他的背景图片的大小,
self.plusButton.bounds = CGRectMake(0, 0, self.plusButton.currentImage.size.width, self.plusButton.currentImage.size.height);
但是这样写好麻烦,所以我就想到一个方法,直接在给按钮添加图片的地方进行设置:
[btn setBackgroundImage:[UIImage imageNamed:@"tabbar_compose_button_highlighted"] forState:UIControlStateHighlighted];
//默认按钮尺寸跟背景图片一样大
//sizeToFit :默认会根据按钮的背景图片或者image和文字计算出按钮最合适的尺寸。
[btn sizeToFit];
3、用字符串反射出一个类名
for (UIView *tabBarButton in self.subviews) {
//tabBarButton 这是一个私有api 所以得用反射机制进行 根据字符串反射出一个类名
if ([tabBarButton isKindOfClass:NSClassFromString(@"UITabBarButton")]) {
if (i == 2) {
i = 3;
}
btnX = i * btnW;
tabBarButton.frame = CGRectMake(btnX, btnY, btnW, btnH);
i++;
}
}
总结:
1、项目简介学习目的:
架构思想,封装思想,优化代码(重构)思想,代码维护思想,把代码
按照功能业务逻辑全部抽出来,保证每个功能处理一个业务逻辑。2、开发简介PPT
移动组:前端
服务器开发组:后端 供数据接口 通常开发中有需求文档产品需求组:产品的外观和功能通常开发中有原型图
3、环境配置(项目开发第一步)
1> 新建项目:Git管理:方便管理代码,查看当天改了哪些代码。2> 项目部署,支持ios7,ios8
3> 不支持横竖屏
4> 导入图标和启动图片
- 注意:
-
导入图标:pt表示点,2x对应的图标像素应该*2,60*2 =
120px,,3x对应的图标像素应该*3,图标不能随便放 ,要一
一对应,没有就不填。
-
启动图片:xcode6多LaunchScreen代替了之前默认加载
default.png图片,直接给你一个启动界面,可以展示更多的东
西,非常给力。
- 不能勾选掉LaunchScreen,会导致上下黑色条,LaunchScreen会自动设置好模拟器的尺寸。
- 想加载之前的启动图片,搞个UIImageView,设置图片,并且自动布局就好了,但是有问题不会自动识别当前是4inch,就加载[email protected]的图片
- 搞个自定义view,作为LaunchScreen.xib的View,会报错,系统不支持
- 直接添加Launch images Source就好了
-
5> 程序启动的时候,隐藏状态栏
6> 设置项目前缀:把项目名称里面的大写抽出来。
- 好处
- 区分和系统自带的类,相当于项目的标识。
-
4、搭建项目框架(项目开发第二步)
1> 分析项目框架,下面有个tabBar,上面有个navgationBar,而且navgationBar的标题都不一样。
2> 主框架:UITabBarController控制器,UITabBarController控制器里是导航控制器,导航控制器里应该是对应默认的控制器。
3> 自定义UITabBarController,把添加子控制器的操作封装起来:
好处:
• 自己的东西,自己管理,别人不需要知道,方便代码维护,
是代码结构清晰。
• 一创建某个东西,就有自己想要的,能直接使用,不需要设
置其他属性。封装思想:方便调用和以后项目开发。
4> 每个模块对应一个控制器,处理自己的业务。
5> 划分项目文件夹,把项目所有.m和.h放在文件夹里。目的:方便查找6>通常开发中项目文件夹按模块划分,特殊文件夹:Main:(主框架,自定义tab控制器),Other:存放其他头文件和.m文件(main,代理)
• 开发小技巧:控制器的名称不用自己想,英文不好照样开发,直接看美工 供的图片名称就OK了。
7> 导入pch文件
1.添加pch文件
• 解决方式:覆盖tabBar控制器自带的tabBar为自己的tabBar5、封装自定义UITabBarController,解决代码结构清晰问题
1> 添加自定义UITabBarController的子控制器。
-
在initWithNibName里添加,原因:子控制器只需要添加一次,并且
控制器不需要懒加载,视图才需要,在一创建的时候就拥有子控制
器。
-
写代码最好一个功能一个方法,是代码结构清晰,方便以后维护,
不要所有代码写在一起。
2> 设置自定义UITabBarController的tabBar上面的按钮内容,由对应子控制器的tabBarItem决定。
3> 重构初始化自定义UITabBarController的子控制器的代码
6、tabBar上按钮图片处理
1> 处理tabBar上按钮的选中图片,ios7默认会把tabBar上按钮的选中图片,渲染成蓝色。告诉图片保持最原始的图片,不要渲染。
2> 定义当前版本号的全局宏,在ios7才需要保持最原始的图片。
7、设置TabBar上按钮选中文字颜色。
1> tabBar上的按钮由tabBarItem决定,可以通过tabBarItem设置文字颜色,有相应的set方法,传入一个文字属性字典设置。
• tabBar的label文字的颜色,在iOS7以上默认是黑色,选中是蓝色。
• 微博效果:label的文字颜色,默认为黑色,选中为橘色.
2> 只需要设置一次,可以拿到项目中的所有tabBarItem设置,在Initial设置,并不需要每次都拿到一个tabBarItem设置。
8、调整TabBar上按钮的位置。
1> 自定义TabBar,继承TabBar
• 原因:系统自带的不好使,一个控制器对应一个tabBarButton,微博下边有5个按钮,需要弄个自己的tabBar。
2> 如何利用系统自带的tabBar上的按钮,就不需要自己创建tabBarButton?
• 解决方式:覆盖tabBar控制器自带的tabBar为自己的tabBar
3> 目的:覆盖tabBar控制器自带的tabBar属性为自己的tabBar,让系统把tabBar上的按钮添加到我们的tabBar上,调整系统自带tabBarButton的位
置。
4> 好处:利用系统自带的tabBarButton,如果只是把自定义TabBar加上系统的tabBar上,就拿不到系统自带的tabBarButton,去设置他的位置,必
3> 目的:覆盖tabBar控制器自带的tabBar属性为自己的tabBar,让系统把tabBar上的按钮添加到我们的tabBar上,调整系统自带tabBarButton的位 置。
4> 好处:利用系统自带的tabBarButton,如果只是把自定义TabBar加上系统的tabBar上,就拿不到系统自带的tabBarButton,去设置他的位置,必须自己自定义tabBar上的按钮,很麻烦。
5> 原理:tabBar上的按钮是在viewDidAppear的时候拿到self.tabBar调用addSubViews添加上去的,在viewDidAppear之前把控制器的tabBar换成我们自己的tabBar,就会把tabBar上的按钮添加到自己的tabBar上。
6> 如何覆盖系统自带的tabBar?tabBar控制器的tabBar属性,是readly只读的,不能直接赋值。
-
利用运行时机制发送消息:*导入#import<objc/message.h>,objc_msgSend(self,
@selector(setTabBar:),customTabBar);*参数1:谁发送这个消息(self)。参数2:发送什么消息(名字叫
setTabBar:),参数3:发送消息的参数。调用set方法,需要传一个
参数,给成员属性赋值,这里传自定义的tabBar。
-
利用KVC:[selfsetValue:customTabBarforKeyPath:@"tabBar"];
7> 重写layoutSubViews布局子控件。
- 判断是tabBarButton才需要调整位置
- 添加UIView的分类,快速设置尺寸和位置。
-
模仿苹果官方做法,苹果官方bounds,frame都是分类声明的,在分
类用@property只会生成方法的声明,不会生成成员属性,和方法
的实现。
- 好处:自动生成方法的声明,简便开发,不需要自己写方法声明。
-
注意点:获取frame,改变宽高,不要通过获取bounds,改变宽高,
单独设置bounds一个属性会影响到frame,使frame设置位置不准
确。
- 根据tabBar的items属性,计算出tabBarButton的宽度。•
-
从第3个按钮开始,需要多添加一个按钮宽度,给中间加号按钮空
出位置。
9、自定义TabBar上添加加号按钮,显示在最中间,懒加载。
1> layoutSubviews方法设置子控件尺寸准确,因为这时候父控件的尺寸确定了,才会去布局子控件。
• 注意点:用分类设置center位置的时候,先设置尺寸,要不然没有尺寸,都不知道控件的中心点在哪,无法准确定位。
10.badgeView的问题解决不了
未完待续。。。
https://github.com/guoyunsky/Markdown-Chinese-Demo#文字被些字符包围