美文网首页
iOS15.0 Navigation Bars笔记

iOS15.0 Navigation Bars笔记

作者: 启发禅悟 | 来源:发表于2021-11-21 18:30 被阅读0次

一直觉得UINavigationBar很难搞,Apple每年的改动几乎都有他,从iOS 7, 11, 13, 到今年的15,年年都动刀,年年都得适配。

基于iOS15的UINavigationBar的测试结果令我感到很意外,感觉很多东西和自己想的完全
不一样,很诡异。

一组简单的测试:

  1. 初始化一个以UIViewController为RootViewController的UINavigationController
  2. 设置standardAppearance的背景为红色
  3. 设置scrollEdgeAppearance的背景为绿色

测试结果:


截屏2021-11-21 下午4.41.06.png

结论:

iOS 14.8.1的行为符合预期,而iOS15.0的结果完全不正确。貌似scrollEdgeAppearance同样影响着不带scroll view视图的Navigation Bar。这和文档的描述还是有出入的。

个人觉得,这是一个Bug,今后可能会Fix。就目前来看,最好的方案是:

  • 一律使用UINavigationBar(或者UINavigationItem)的Appearance(standardAppearance / compactAppearance / scrollEdgeAppearance / compactScrollEdgeAppearance)属性来进行外观设置
  • standardAppearance / scrollEdgeAppearance这两项必须被设置,且如果没有特殊需求,建议两个设置成一致的值,以保证向之前的版本兼容。

我的需求:

看众多App的个人页面的设计,一般都是隐藏导航栏背景和标题,随着向上滚动,导航栏和标题逐渐显示,例如下面这种效果:

图像.GIF
方案一

最先考虑到的方案是NavigationBar的alpha值随着ScrollView的contentOffsetY进行修正,但这种情况就是左右两边的BarButtonItem也会受到影响,所以是不符合的。

方案二

考虑背景View和标题View的alpha值随着ScrollView的contentOffsetY进行修正,但很遗憾的是UINavigationBar并没有公开它的具体的视图结构,所以我们不能直接获取背景View和标题View。

所以黑科技,就是在Debug的时候,通过Capture View Hierarchy来获取具体的视图结构,然后通过遍历UINavigationBar的子视图,查找对应的背景View和标题View来进行修改。

例如


截屏2021-11-21 下午6.03.20.png

我们可以猜想到_UIBarBackground是背景视图,以及UILabel-Title是标题视图,通过遍历,查找到他们,并修改他们的alpha值,就可以完成需求。

这样做的一个问题就是,如果Apple修改了UINavigationBar的内部结构,那么后果不可预计。

方案三:
通过修改Appearance/titleTextAttributes来实现

    CGFloat offsetY = self.tableView.contentOffset.y;

    // offsetY 偏移0-200,逐渐显示导航栏,超过200,一直显示
    if (offsetY > 200) {
        offsetY = 200;
    }

    CGFloat offsetYPercentage = offsetY / 200;
    
    CGFloat red = 0;
    CGFloat blue = 0;
    CGFloat green = 0;
    CGFloat alpha = 0;
    
    UIColor *finalbackgroundColor = [UIColor systemBackgroundColor];
    [finalbackgroundColor getRed:&red green:&green blue:&blue alpha:&alpha];
    UIColor *backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:offsetYPercentage];
    
    UIColor *finalShadowColor = [UIColor separatorColor];
    [finalShadowColor getRed:&red green:&green blue:&blue alpha:&alpha];
    UIColor *shadowColor = [UIColor colorWithRed:red green:green blue:blue alpha:offsetYPercentage];
    
    UIColor *finalLabelColor = [UIColor labelColor];
    [finalLabelColor getRed:&red green:&green blue:&blue alpha:&alpha];
    UIColor *labelColor = [UIColor colorWithRed:red green:green blue:blue alpha:offsetYPercentage];

    UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];
    // 注意,一定得是Opaque,不能使用configureWithDefaultBackground。
    // 通过backgroundColor的alpha来决定视图的透明度
    [appearance configureWithOpaqueBackground];
    appearance.backgroundColor = backgroundColor;
    appearance.shadowColor = shadowColor;
    appearance.titleTextAttributes = @{NSForegroundColorAttributeName:labelColor};
    
    self.navigationItem.standardAppearance = appearance;
    self.navigationItem.scrollEdgeAppearance = appearance;

要点就是必须是configureWithOpaqueBackground类型的appearance,通过修改背景颜色的alpha,来实现从透明到不透明的过程。

这种方案也有一个问题,就是最终的UINavigationBar没有了系统默认的半透明的效果。

参考资料:

UINavigationBar
Customizing Your App’s Navigation Bar
Sample Code

相关文章

网友评论

      本文标题:iOS15.0 Navigation Bars笔记

      本文链接:https://www.haomeiwen.com/subject/bpastrtx.html