百思不得姐框架

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 今天只是框架二 ,明天我将为大家讲解后面的部分,大家有什么问题,麻烦留言,谢谢!!!!

以上是关于百思不得姐框架的主要内容,如果未能解决你的问题,请参考以下文章

百思不得姐-笔记

微信小程序实战之百思不得姐精简版

python爬取百思不得姐视频

iOS百思不得姐ARKit旋转动画立体相册源码等

百思不得姐第4天:文本框占位文字颜色

百思不得姐(第二天)