返回博客首页
← 所有文章

如何在 iOS 上匹配 NativeScript ActionBar 的颜色

2017 年 5 月 30 日 — 作者 TJ VanToll

更新:NativeScript 的 ActionBar 现在提供了一个 flat 属性——即 <ActionBar flat="true"></ActionBar>——它解决了本文中的问题,而无需深入到原生代码中。如果你正在努力使 ActionBar 的颜色匹配,请尝试使用它。

你是否曾经尝试过让你的 ActionBar 的背景颜色与页面上的其他部分匹配?如果是这样,你可能尝试过类似这样的操作。

<ActionBar backgroundColor="green"></ActionBar>
<GridLayout backgroundColor="green"></GridLayout>


结果却得到一个有着两种明显不同颜色的 UI。

before

到底发生了什么?

NativeScript 的 <ActionBar> UI 组件在 iOS 上呈现为 UINavigationBar,而这个 UINavigationBar 有一些奇特的内置行为。具体来说,当 iOS 渲染 UINavigationBar 时,它会 调整你应用的背景颜色,以给控件 一种“光滑”的外观。

上面图片中的两种颜色不匹配是因为 iOS 改变了你应用的绿色,因此它与 <GridLayout> 使用的真实绿色不匹配。

让颜色匹配

幸运的是,让颜色匹配起来相对简单。UINavigationBar 拥有一个 translucent 属性,它控制着 iOS 是否使用颜色调整算法。由于 NativeScript 允许你直接从 JavaScript/TypeScript 访问原生 API,因此更改此属性就像获取控件的引用并设置适当的布尔值一样简单。

例如,假设你的主页看起来像这样。

<Page navigatingTo="onNavigatingTo">

  <ActionBar
    backgroundColor="green"
    title="My App"></ActionBar>

  <GridLayout
    backgroundColor="green"></GridLayout>
</Page>


要使 UINavigationBar 半透明,你可以使用以下代码,它通过 NativeScript 框架模块 获取对 UINavigationBar 的引用,并将栏的 translucent 属性设置为 false

import { topmost } from "ui/frame";

export function navigatingTo() {
  if (topmost().ios) {
    var navigationBar = topmost().ios.controller.navigationBar;
    navigationBar.translucent = false;
  }
}

更改后,你将得到一个看起来像这样的 <ActionBar>

after1

如你所见,颜色现在匹配了,但是 UINavigationBar 控件下仍然存在一个像素边框。这个边框是 iOS 所谓的“阴影图像”,如果你也想要摆脱它,你需要两行额外的代码——一行用于调用 UINavigationBarsetBackgroundImageForBarMetrics() 方法,另一行用于设置控件的 shadowImage 属性。你可以传递一个空的图像,因为你实际上只需要让栏消失。以下代码展示了如何实现。

import { topmost } from "ui/frame";

// Declare these so the TypeScript compiler doesn’t complain about the references.
declare var UIImage: any;
declare var UIBarMetrics: any;

export function navigatingTo() {
  if (topmost().ios) {
    var navigationBar = topmost().ios.controller.navigationBar;
    navigationBar.translucent = false;
    navigationBar.setBackgroundImageForBarMetrics(UIImage.new(), UIBarMetrics.Default);
    navigationBar.shadowImage = UIImage.new();
  }
}

进行此更改后,<ActionBar> 下的边框现在消失了。

after2

这基本上就是全部了。你可能需要将这段代码放在你的第一个页面中,因为一旦你设置了这些属性,它们将对你的整个应用程序生效。

最后一点:如果你正在使用 Angular,你可能需要将这段代码放在你应用的第一个组件中的 ngOnInit() 处理程序中。以下是一个你可以参考的示例实现。

import { Component, OnInit } from "@angular/core";
import { topmost } from "ui/frame";

// Declare these so the TypeScript compiler doesn’t complain about these references.
declare var UIImage: any;
declare var UIBarMetrics: any;

@Component({
  selector: "ns-demo",
  moduleId: module.id,
  template: `
    <ActionBar backgroundColor="green"></ActionBar>
    <GridLayout backgroundColor="green"></GridLayout>
  `
})
export class MyComponent implements OnInit {
  ngOnInit(): void {
    if (topmost().ios) {
      var navigationBar = topmost().ios.controller.navigationBar;
      navigationBar.translucent = false;
      navigationBar.setBackgroundImageForBarMetrics(UIImage.new(), UIBarMetrics.Default);
      navigationBar.shadowImage = UIImage.new();
    }
  }
}

如果你仍然无法让颜色在自己的应用程序中匹配,请务必在评论中告知我们,我们会尽力帮助你。