百思不得姐框架
Posted 萧家大公子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了百思不得姐框架相关的知识,希望对你有一定的参考价值。
一 该部分框架效果图和实现思路
框架二的效果图:
实现思路:
—- 1> 先完善tabBar(主要是自定义)
—- 2> 再完善导航条
—- 3> 其次完善屏幕侧滑(主要是全屏侧滑功能)
二 抽取分类(设置到插件中)
1 抽取分类的思想: 实现复用
—-> 1.1 上部分代码中,我们需要设置tabBar中图片成未被渲染的格式,因此我们抽取了一个分类,用分类里面的方法实现了效果.
—-> 分类代码:
//传入一张图片的名称返回一张未被渲染的图片
+ (UIImage *)originalWithImage:(NSString *)imageName
{
UIImage *image = [UIImage imageNamed:imageName];
return [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
}
2 问题:虽然抽取了分类,但是我们是不是想在用分类设置图片的时候,也能有插件提示功能呢?
设置插件功能图:(图一)
具体的设置思路:<—>见下图
2.1 按住option,点击桌面的左上角,找到前往,点击资源库
图一:
图二:
图三:
图四:
图五:
图六:
图七:
最后:找到插件的位置,具体做法就是先command + c 然后command + v 赋值个item,然后将图七中的改为自己的分类方法就可以.
三 问题一
1 问题: 选中的图片中,配图的文字被渲染了(图片不被渲染我们用分类解决了)
2 实现思路:
—-> 1> 通过获取到全局的tabBar
—-> 2> 再通过字典来包装设置字体颜色和字体的大小
3 在自定义的tabBarController控制器中设置选中字体的颜色不被渲染(全程序只需要设置一次)–>选中状态
4 通过拿到全局的tabBarItem去设置按钮的字体大小(由整个app的效果图知道,字体需要加粗)
具体代码:
#pragma mark - 设置标题的字体不被渲染(该方法全程序只会来一次)
+ (void)load
{
//获取全局的tabBar
UITabBarItem *tabBar = [UITabBarItem appearance];
//创建可变字典
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
//设置文字的颜色
dict[NSegroundColorAttributeName] = [UIColor blackColor];
//设置字体
[tabBar setTitleTextAttributes:dict forState:UIControlStateSelected];
NSMutableDictionary *dict1 = [NSMutableDictionary dictionary];
//设置文字的大小
dict1[NSFontAttributeName] = [UIFont boldSystemFontOfSize:13];
//设置字体大小
[tabBar setTitleTextAttributes:dict1 forState:UIControlStateNormal];
}
5 发布按钮显示不出来—>发布按钮的图片比较大,显示出来就会有问题
—-> 5.1 让正常状态下的图片也不被渲染(能达到效果)
nav2.tabBarItem.image = [UIImage originalWithImage:@"tabBar_publish_icon"];
—-> 5.2 设置对应的控制器的tabBarItem,通过设置图片的内边距来实现(通过测试也不符合条件:原因是选中时候高亮,但是不选中的时候就会恢复状态)–>很明显是高亮状态
publish.tabBarItem.imageInsets = UIEdgeInsetsMake(7, 0, -7, 0);
四 自定义tabBar
1 为了解决tabBar的问题,我们自定义tabBar(继承系统的UITabBar)
见图:
2 修改tabBar内部子控件位置
3 把系统的tabBar替换为自己的tabBar(只需要创建一次)–(KVC)
具体实现代码:
#pragma mark - 运用自定义的tabBar
- (void)setUpTabBar
{
//创建自定义tabBar
XFJTabBar *tabBar = [[XFJTabBar alloc] init];
//KVC赋值
[self setValue:tabBar forKey:@"tabBar"];
}
4 重写layoutSubViews(布局tabBar中的子控件)
4.1 调整内部子控件的位置(遍历所有的子控件,然后判断子控件的类型,将中间的按钮位置空出来)
注意部分: 通过打印tabBar的子控件的类型,我们知道了按钮的类型是—> UITabBarButton这种类型的
代码详见:
#pragma mark - 布局子控件
- (void)layoutSubviews
{
[super layoutSubviews];
//获取子控件的总数
NSInteger count = self.items.count + 1;
//设置按钮的尺寸的属性
CGFloat buttonX = 0;
CGFloat buttonY = 0;
CGFloat buttonW = self.XFJ_Width / count;
CGFloat buttonH = self.XFJ_height;
NSInteger i= 0;
//遍历
for (UIView *button in self.subviews) {
//判断为该种类型的时候才进行下面
if ([button isKindOfClass:NSClassFromString(@"UITabBarButton")]) {
if (i == 2) {
i = i + 1;
}
//按钮的X值
buttonX = i * buttonW;
//按钮的尺寸
button.frame = CGRectMake(buttonX, buttonY, buttonW, buttonH);
i ++;
}
}
//设置发布按钮的饿摆放位置
self.plusButton.center = CGPointMake(self.XFJ_Width * 0.5, self.XFJ_height * 0.5);
}
4.2 懒加载(通过懒加载创建发布按钮,然后在内部设置属性)—>由于只需要创建一次,所以用懒加载实现
#pragma mark - 懒加载
- (UIButton *)plusButton
{
if (_plusButton == nil) {
//创建按钮
UIButton *plusButton = [UIButton buttonWithType:UIButtonTypeCustom];
//设置按钮的图片(平常状态)
[plusButton setImage:[UIImage imageNamed:@"tabBar_publish_icon"] forState:UIControlStateNormal];
//高亮状态
[plusButton setImage:[UIImage imageNamed:@"tabBar_publish_click_icon"] forState:UIControlStateHighlighted];
//赋值
self.plusButton = plusButton;
//自适应
[plusButton sizeToFit];
[self addSubview:plusButton];
}
return _plusButton;
}
五 问题二
问题: 我们很多时候需要在外界直接修改控件的尺寸,但是传统的写法太麻烦.
解决办法:创建分类,在外界直接修改X,Y,width,Height的时候,能直接点出来
代码块一 :
@property CGFloat XFJ_x;
@property CGFloat XFJ_y;
@property CGFloat XFJ_Width;
@property CGFloat XFJ_height;
代码块二(在分类的内部实现了尺寸的修改,外面直接就可以点出来用):
- (void)setXFJ_x:(CGFloat)XFJ_x
{
CGRect frame = self.frame;
frame.origin.x = XFJ_x;
self.frame = frame;
}
- (CGFloat)XFJ_x
{
return self.frame.origin.x;
}
六 PCH文件
1 创建一个PCH文件(注意命名方式:和工程名一样),将全程序都需要的用到的文件都放到里面–>prefix
—-> PCH文件的实现思路:将pch文件中的代码,全部都拷贝一个到每个文件中,然后编译.
2 具体PCH配置:
详见图一:
详见图二:(注意文件的路径)
七 精华模块导航条的内容
1 导航条左边的按钮图片(封装一个分类)—->封装原因:我们想直接通过传入两张图,直接返回一个设置好的UIBarButtonItem对象.
—-> 写在分类中的代码:
+ (UIBarButtonItem *)itemWithImage:(UIImage *)image heightImage:(UIImage *)heighImage target:(id)target action:(SEL)action
{
//创建按钮
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
//设置按钮图片
[button setImage:image forState:UIControlStateNormal];
//高亮状态
[button setImage:heighImage forState:UIControlStateHighlighted];
//设置按钮的尺寸
[button sizeToFit];
//按钮的点击事件
[button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
//返回一个设置好的按钮
return [[UIBarButtonItem alloc ]initWithCustomView:button];
}
—-> 设置左边图片:
- (void)setUpNavBar
{
//左边的样式
UIBarButtonItem *item = [UIBarButtonItem itemWithImage:[UIImage imageNamed:@"nav_item_game_icon"] heightImage:[UIImage imageNamed:@"nav_item_game_click_icon"] target:self action:@selector(game)];
—-> 设置右边的图片:
//右边的样式
UIBarButtonItem *item1 = [UIBarButtonItem itemWithImage:[UIImage imageNamed:@"navigationButtonRandom"] heightImage:[UIImage imageNamed:@"navigationButtonRandomClick"] target:self action:@selector(task)];
self.navigationItem.rightBarButtonItem = item1;
—-> 设置标题(注意:导航条的标题是一张图片)
#pragma mark - 设置导航条标题
- (void)setUpNavTitle
{
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"MainTitle"]];
self.navigationItem.titleView = imageView;
}
2 是不是所有的类都能拿到全局的外观?
解答: 不是,只有遵守了UIAppearance协议就可以通过appearance获取全局外观.
3 设置全局导航条的背景图片和显示的字体
具体代码:
//获取全局的导航条
UINavigationBar *navBar = [UINavigationBar appearance];
//设置背景图片
[navBar setBackgroundImage:[UIImage imageNamed:@"navigationbarBackgroundWhite"] forBarMetrics:UIBarMetricsDefault];
//设置字体
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[NSFontAttributeName] = [UIFont boldSystemFontOfSize:20];
[navBar setTitleTextAttributes:dict];
八 bug
ios8会出现的bug:把短信界面导航条改了,联系人界面会出现黑的.
九 跳转设置
1 自定义设置控制器(UITableViewController)
2 控制器”我”导航条右侧的图片
#pragma mark - 添加控制器我的右边的图片
- (void)setImageWithRight
{
//控制器右边的图片
UIBarButtonItem *item1 = [UIBarButtonItem itemWithImage:[UIImage imageNamed:@"mine-moon-icon"] heightImage:[UIImage imageNamed:@"mine-moon-icon-click"] target:self action:@selector(moon)];
UIBarButtonItem *item2 = [UIBarButtonItem itemWithImage:[UIImage imageNamed:@"mine-setting-icon"] heightImage:[UIImage imageNamed:@"mine-setting-icon-click"] target:self action:@selector(setting)];
//设置右边的图片
self.navigationItem.rightBarButtonItems = @[item2,item1];
}
3 跳转到设置界面
#pragma mark - 点击事件的实现(setting)
- (void)setting
{
NSLog(@"setting");
//创建跳转控制器
XFJSettingViewController *setting = [[XFJSettingViewController alloc] init];
//在push之前隐藏底部的tabBar
setting.hidesBottomBarWhenPushed = YES;
//跳转控制器
[self.navigationController pushViewController:setting animated:YES];
}
4 跳转后出现的问题:
—-> 4.1 底部条没有隐藏
//在push之前隐藏底部的tabBar
setting.hidesBottomBarWhenPushed = YES;
—-> 4.2 返回按钮样式(一定要在有内容的前提下,才能设置内边距)
5 设置全局返回按钮(重写push方法)
#pragma mark - 重写push方法
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
NSLog(@"%@",self.interactivePopGestureRecognizer);
//判断,只有是分根控制器才能返回
if (self.childViewControllers.count > 0) {
//创建按钮
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
//设置按钮没有点击的图片
[button setImage:[UIImage imageNamed:@"navigationButtonReturn"] forState:UIControlStateNormal];
//设置按钮点击后的图片
[button setImage:[UIImage imageNamed:@"navigationButtonReturnClick"] forState:UIControlStateHighlighted];
//设置返回按钮字样
[button setTitle:@"返回" forState:UIControlStateNormal];
//设置返回按钮的标题的正常样式
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
//设置返回按钮的标题的点击样式
[button setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];
//设置按钮的尺寸
[button sizeToFit];
//设置按钮的监听方法
[button addTarget:self action:@selector(backBtn) forControlEvents:UIControlEventTouchUpInside];
//设置返回按钮与左边的距离
button.contentEdgeInsets = UIEdgeInsetsMake(0, -10, 0, 0);
//添加按钮
viewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button];
}
[super pushViewController:viewController animated:animated];
}
十 重写push方法出现的bug—>系统的滑动返回功能失效了
1 解决办法: 清空代理—->会出现bug(假死状态:程序一直在跑,但是界面死了)
2 假死原因:在根控制器下,滑动返回,不应该在根控制器的view上滑动返回
3 解决办法:把自己设置为手势的代理,实现代理方法,判断,如果是根控制器,让手势没有效果(是否触发手势的代理方法)
代码块一:
self.interactivePopGestureRecognizer.delegate = self;
代码块二:
#pragma mark - 代理方法
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
//只有当导航控制器的子控制器的数量大于1的时候,才能侧滑
return self.childViewControllers.count > 1;
}
十一 全屏滑动
1 分析:为什么导航控制器的滑动手势只能边缘滑动?
2 通过打印出代理的类型和action的方法,我们可以添加一个全屏滑动的功能,但是需要设置手势的代理,否则在根控制器的时候,又会出现假死的状态.
—->打印出系统侧滑功能的代理(红色部分是代理需要调用的方法)
<UIScreenEdgePanGestureRecognizer: 0x7fe5b2493980; state = Possible; delaysTouchesBegan = YES; view = <UILayoutContainerView 0x7fe5b24920d0>; target= <(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7fe5b2493860>)>>
—-> 代码块一:
#pragma mark - 添加全屏侧滑功能
- (void)setWithScreenPan
{
//创建手势
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self.interactivePopGestureRecognizer.delegate action:@selector(handleNavigationTransition:)];
//添加手势
[self.view addGestureRecognizer:pan];
//设置代理为自己
pan.delegate = self;
}
代码块二:
//添加手势
[self setWithScreenPan];
//清空代理,但是必须是在添加手势之后
self.interactivePopGestureRecognizer.enabled = NO;
十二 总结
1 该部分是有关tabBar和导航条的设置,里面涉及到自定义.设置好了系统的返回功能,但是由于重写而产生的一系列问题.里面已经涉及到了所有情况的解决思路,可能有一些不是很完整.后期我将一一解决.
2 今天只是框架二 ,明天我将为大家讲解后面的部分,大家有什么问题,麻烦留言,谢谢!!!!
以上是关于百思不得姐框架的主要内容,如果未能解决你的问题,请参考以下文章