如何在方向更改时使用不同的 XML 模板重新加载页面?

How to reload a page with a different XML template when orientation changes?

如何在设备方向改变时重新加载页面(使用新模板)? 我想要横向模式下的不同布局。这是在 NativeScript 中,而不是 Java.

如果我以横向方式到达页面,则会选择正确的 xml 文件,但如果我改变方向,则不会重新加载任何内容。

请注意,这不是刷新 CSS 的问题,而是需要一个不同的 XML 文件。

在你的activity中:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    setContentView(R.layout.my_layout);
}

确保布局 XML 的两个方向名称相同

res/layout/my_layout.xml
res/layout-land/my_layout.xml

使用正确的资源文件名 Android 系统会自动重新加载您的 Activities/Fragments 正确的资源。 您可以通过设置 android:configChanges 手动捕获和处理事件(但这种情况很少见)。

查看一些文档:

NativeScript解决方案:

首先你需要参加迎新活动。您可以通过多种方式参与该活动。

第一个也是最简单的方法是安装 nativescript-orientation 插件,它将全局绑定到事件中,然后它会自动 运行 每次在当前页面的每个名为 orientation 的导出函数方向改变。
安装:

tns plugin install nativescript-orientation

打开您的 app.js 文件并在文件顶部添加;

require('nativescript-orientation');

然后通过创建:

exports.orientation = function(args) {
  if (args.landscaped) { /* do landscape stuff */ }
  else { /* do port */
};

在您希望收到方向更改通知的任何页面上,它会在具有该功能的那些页面上调用,您可以按需要处理该事件。


但是,如果您不想使用插件,您可以通过以下方式自己直接绑定到方向事件:

var application = require('application');
exports.onNavigateTo = function() {
  application.on(application.orientationChangedEvent,myOrientationFunction);
}

exports.onNavigateFrom = function() {
  application.off(application.orientationChangedEvent, myOrientationFunction);

function myOrientationFunction(args) {
  // We have an orientation event
}

但是,您必须要求在您的页面首次打开时收到该事件的通知,并且您必须在页面关闭时将您自己从通知中删除。这是上面的插件为您处理的每页大量额外代码。请注意,当您自己执行此操作时,您还需要将 NavigateTo/NavigatedFrom 添加到 Declarative UI XML 文件中的 标记,否则这些函数将不会被调用。


好的,现在您已经有了自己喜欢的活动;让我们看看如何让您的想法发挥作用。

现在,您要求在每次页面更改时切换布局;这通常是最糟糕的事情;但我会先回答它,然后再给你我用来做复杂布局的替代方法,该布局几乎可以自动在纵向和横向模式下工作。

我的页面-Landscape.xml

<Page><StackLayout><Label text="Landscape"/></StackLayout></Page>

我的页面-Portrait.xml

<Page><StackLayout><Label text="Portrait"/></StackLayout></Page>

我的页面-Landscape.js

var commonPage = require("./MyPage.js");
var frame = require('ui/frame');
exports.orientation = function(args) {
  if (args.landscape === false) {
     frame.topmost().navigate('MyPage-Portrait');
  }
};

// Tie all the common page code into this pages exports
for (var key in commonPage) {
   if (commonPage.hasOwnProperty(key)) {
      exports[key] = commonPage[key];
   }
}

我的页面-Portrait.js

var commonPage = require("./MyPage.js");
var frame = require('ui/frame');
exports.orientation = function(args) {
  if (args.landscape === true) {
     frame.topmost().navigate('MyPage-Landscape');
  }
};

// Tie all the common page code into this pages exports
for (var key in commonPage) {
   if (commonPage.hasOwnProperty(key)) {
      exports[key] = commonPage[key];
   }
}

MyPage.js

exports.TapHandler = function() { /* Someone Tapped */ }
exports.someOtherLogic = function() { /* More logic */ }
exports.etc = function() { /* etc */ }

您将所有常用的页面逻辑放在 MyPage 文件中;但您专门导航到特定的横向或纵向页面;如果页面方向发生变化,他们每个人都负责导航到另一个版本。


关于上述解决方案的注释:

  1. 您需要从任何其他页面导航到该页面的正确版本; IE。如果您处于横向模式;当您导航到另一个页面时;您需要确保导航到页面的景观版本。
  2. NS-Orientation 插件确实为您提供了一个句柄辅助函数来找出当前的方向,从而使这更容易。
  3. 记得让MyPage.js拥有所有的公共代码;您想尝试消除特定页面版本上的任何自定义代码。
  4. 它们是您可以使用的框架重新加载命令;但是它完全清除了历史;这意味着你不能向后导航。即 Page1 -> Page2,frame.reloadPage() 意味着后退按钮不会返回到 Page1。如果这是可以接受的;你可以让上面的系统简单很多;而不是创建单独的 xml 和 js 文件,您只需要一个 myPage.landscape.xml 和 myPage.portrait.xml 并且您需要在每次方向更改时调用 frame.reloadPage();

现在对我来说,上面的内容对于您需要在页面之间完成的可能是一个简单的更改来说是一些严重的矫枉过正。所以我将描述我是如何在我的应用程序中做到这一点的;它有一些非常复杂的屏幕,但它们看起来非常好,并且在方向改变时完全改变功能。

这是编写 NativeScript-orientation 插件的部分原因。在页面方向更改将自动添加/删除 "landscape" class 名称到 XML 中的 <Page> 元素。这允许您在 CSS 中执行的操作是:

.myLabel {
  font-size: 12;
  background-color: blue;
  height: 20;
}

.landscape .myLabel {
  font-size: 16;
  background-color: green;
  height: 40;
}

如果你还没有弄清楚我的目标是什么;这允许您在横向模式和纵向模式下为页面自定义 CSS。此外,当您结合使用 exports.orientation 函数时,您还可以根据方向 运行 自定义代码。

所以就我而言;在 phone 上,我的滚动列表是一个上下滚动的项目列表,大小与屏幕完美匹配,看起来非常清晰。当你切换到横向模式时;它隐藏了操作栏,添加了一个 fab 按钮,调整了整个网格项目的大小以适应相同的比例,并将滚动模式切换到左右。整个外观变化的大部分是在纯 css 中完成的;其余的在 exports.orientation 函数中完成,该函数处理诸如切换滚动方向之类​​的事情。

免责声明:我是 NativeScript-orientation 插件的作者