0

我正在使用适用于 iOS 和 Android 的 VS2015 TACO 开发适用于 iOS、Android 和 Windows 商店的 JavaScript 应用程序。我刚刚安装了 Ace 插件,并且正在研究Javascript/Ace 代码示例。对于 iOS 和 Android,我想将本机 UI 用于:1)底部标签栏和 2)带有图标和文本的滚动选择器列表(基本上是 WinJS.UI ListView)。Ace Intro YouTube Video在 XAML 标记中显示了一个示例选项卡栏,但我不熟悉 XAML。谁能指出我的 Ace Plugin Javascript 示例,用于 iOS 和 Android 的标签栏 UI 和表格视图 UI?我将不胜感激。

更新 #1 感谢亚当·内森。使用他的代码,我在我的 Mac iPad 模拟器中获得了一个停靠的标签栏。它在纵向和横向视图中都能很好地捕捉。我正在使用此代码打开和关闭它:

TEST_ACE.dockTabs = function () {
    if (TEST_ACE.pageTabBar == null) {
        // Surround the WebView with native UI
        TEST_ACE.pageTabBar = TEST_ACE.buildDockedTabsWithoutXaml();

        // Replace the WebView with the loaded native page
        // (For the title setting in XAML to work on Android, ShowTitle must be
        //  set to true in the Android section of config.xml.)
        ace.getHostPage().setContent(TEST_ACE.pageTabBar);

        // Reparent the WebView inside the native page
        TEST_ACE.pageTabBar.setContent(ace.getHostWebView());

        // Save the native page so we can set its title as tabs are clicked
        _nativePage = TEST_ACE.pageTabBar;
    }
    else {
        ace.getHostPage().setContent(ace.getHostWebView());
        TEST_ACE.pageTabBar = null;
    }
}

当我关闭标签栏时,我仍然看到图标曾经所在的底部块 - 但它现在是空的。也就是说,当我尝试同时关闭上部标题栏和底部标签栏时,我只关闭上部标题栏,但底部块(现在为空白)仍然存在。如果我改变方向(纵向/横向),那么底部块将消失。在将其重置为 HostWebView 之前,是否有更好的方法使用标签栏清除 HostPage?

对于 Android,我更新了 config.xml 文件以将 ShowTitle 设置为 true:

<name>AcePluginTester</name>
<description>A blank project that uses Apache Cordova to help you build an app that targets multiple mobile platforms: Android, iOS, Windows, and Windows Phone.</description>
<author href="http://cordova.io" email="dev@cordova.apache.org">Apache Cordova Team </author>
<content src="index.html" />
<access origin="*" />
<vs:features />
<preference name="SplashScreen" value="screen" />
<preference name="windows-target-version" value="8.1" />
<!-- Support for Cordova 5.0.0 plugin system -->
<plugin name="cordova-plugin-whitelist" version="1" />
<allow-intent href="http://*/*" />
<allow-intent href="https://*/*" />
<allow-intent href="tel:*" />
<allow-intent href="sms:*" />
<allow-intent href="mailto:*" />
<allow-intent href="geo:*" />
  <platform name="android">
  <allow-intent href="market:*" />
        <preference name="ShowTitle" value="true"/>
  </platform>
<platform name="ios">
<allow-intent href="itms:*" />
<allow-intent href="itms-apps:*" />
<preference name="orientation" value="all" />
</platform>
<!--blah blah blah-->

但是当我在 VS Android Emulator 中运行该应用程序时,我仍然收到此错误:

Uncaught Error: Native error: java.lang.RuntimeException: Error setting FrameLayout's UserControl.Content to Windows.UI.Xaml.Controls.Page{6b1647a V.E...... ......I. 0,0-0,0}
at run.ace.IncomingMessages.set(IncomingMessages.java:206)
at run.ace.NativeHost$2.run(NativeHost.java:239)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.RuntimeException: Cannot set title on the main page in Android unless you set <preference name="ShowTitle" value="true"/> in config.xml.
at run.ace.TabBar.setTitle(TabBar.java:39)
at Windows.UI.Xaml.Controls.Page.updateTitle(Page.java:63)
at Windows.UI.Xaml.Controls.Page.processBars(Page.java:71)
at Windows.UI.Xaml.Controls.ViewGroupHelper.setProperty(ViewGroupHelper.java:51)
at run.ace.IncomingMessages.set(IncomingMessages.java:191)
... 8 more


See http://ace.run/docs/errors for help.
cordova.js (314,13)

我错过了Android的东西吗?

再次感谢您。这会很棒!

更新#2

我将 ShowTitle 首选项移动到小部件根目录,但仍然出现错误。我得到了 value="True"(大写 True)和 value="true" 的错误。这是我的 config.xml 文件的全部内容:

<?xml version="1.0" encoding="utf-8"?>
<widget xmlns:cdv="http://cordova.apache.org/ns/1.0" xmlns:vs="http://schemas.microsoft.com/appx/2014/htmlapps" id="io.cordova.myapp740bed" version="1.0.1" xmlns="http://www.w3.org/ns/widgets" defaultlocale="en-US">
  <name>AcePluginTester</name>
  <description>A blank project that uses Apache Cordova to help you build an app that targets multiple mobile platforms: Android, iOS, Windows, and Windows Phone.</description>
  <author href="http://cordova.io" email="dev@cordova.apache.org">Apache Cordova Team </author>
  <content src="index.html" />
  <access origin="*" />
  <vs:features />
  <preference name="SplashScreen" value="screen" />
  <preference name="windows-target-version" value="8.1" />
  <!-- Support for Cordova 5.0.0 plugin system -->
  <plugin name="cordova-plugin-whitelist" version="1" />
  <allow-intent href="http://*/*" />
  <allow-intent href="https://*/*" />
  <allow-intent href="tel:*" />
  <allow-intent href="sms:*" />
  <allow-intent href="mailto:*" />
  <allow-intent href="geo:*" />
  <platform name="android">
    <allow-intent href="market:*" />
  </platform>
  <platform name="ios">
    <allow-intent href="itms:*" />
    <allow-intent href="itms-apps:*" />
    <preference name="orientation" value="all" />
  </platform>
  <platform name="android">
    <icon src="res/icons/android/icon-36-ldpi.png" density="ldpi" />
    <icon src="res/icons/android/icon-48-mdpi.png" density="mdpi" />
    <icon src="res/icons/android/icon-72-hdpi.png" density="hdpi" />
    <icon src="res/icons/android/icon-96-xhdpi.png" density="xhdpi" />
  </platform>
  <platform name="ios">
    <!-- iOS 8.0+ -->
    <!-- iPhone 6 Plus  -->
    <icon src="res/icons/ios/icon-60-3x.png" width="180" height="180" />
    <!-- iOS 7.0+ -->
    <!-- iPhone / iPod Touch  -->
    <icon src="res/icons/ios/icon-60.png" width="60" height="60" />
    <icon src="res/icons/ios/icon-60-2x.png" width="120" height="120" />
    <!-- iPad -->
    <icon src="res/icons/ios/icon-76.png" width="76" height="76" />
    <icon src="res/icons/ios/icon-76-2x.png" width="152" height="152" />
    <!-- iOS 6.1 -->
    <!-- Spotlight Icon -->
    <icon src="res/icons/ios/icon-40.png" width="40" height="40" />
    <icon src="res/icons/ios/icon-40-2x.png" width="80" height="80" />
    <!-- iPhone / iPod Touch -->
    <icon src="res/icons/ios/icon-57.png" width="57" height="57" />
    <icon src="res/icons/ios/icon-57-2x.png" width="114" height="114" />
    <!-- iPad -->
    <icon src="res/icons/ios/icon-72.png" width="72" height="72" />
    <icon src="res/icons/ios/icon-72-2x.png" width="144" height="144" />
    <!-- iPhone Spotlight and Settings Icon -->
    <icon src="res/icons/ios/icon-small.png" width="29" height="29" />
    <icon src="res/icons/ios/icon-small-2x.png" width="58" height="58" />
    <!-- iPad Spotlight and Settings Icon -->
    <icon src="res/icons/ios/icon-50.png" width="50" height="50" />
    <icon src="res/icons/ios/icon-50-2x.png" width="100" height="100" />
  </platform>
  <platform name="windows">
    <icon src="res/icons/windows/Square150x150Logo.scale-100.png" width="150" height="150" />
    <icon src="res/icons/windows/Square150x150Logo.scale-240.png" width="360" height="360" />
    <icon src="res/icons/windows/Square30x30Logo.scale-100.png" width="30" height="30" />
    <icon src="res/icons/windows/Square310x310Logo.scale-100.png" width="310" height="310" />
    <icon src="res/icons/windows/Square44x44Logo.scale-100.png" width="44" height="44" />
    <icon src="res/icons/windows/Square44x44Logo.scale-240.png" width="106" height="106" />
    <icon src="res/icons/windows/Square70x70Logo.scale-100.png" width="70" height="70" />
    <icon src="res/icons/windows/Square71x71Logo.scale-100.png" width="71" height="71" />
    <icon src="res/icons/windows/Square71x71Logo.scale-240.png" width="170" height="170" />
    <icon src="res/icons/windows/StoreLogo.scale-100.png" width="50" height="50" />
    <icon src="res/icons/windows/StoreLogo.scale-240.png" width="120" height="120" />
    <icon src="res/icons/windows/Wide310x150Logo.scale-100.png" width="310" height="150" />
    <icon src="res/icons/windows/Wide310x150Logo.scale-240.png" width="744" height="360" />
  </platform>
  <platform name="wp8">
    <icon src="res/icons/wp8/ApplicationIcon.png" width="62" height="62" />
    <icon src="res/icons/wp8/Background.png" width="173" height="173" />
  </platform>
  <platform name="android">
    <splash src="res/screens/android/screen-hdpi-landscape.png" density="land-hdpi" />
    <splash src="res/screens/android/screen-ldpi-landscape.png" density="land-ldpi" />
    <splash src="res/screens/android/screen-mdpi-landscape.png" density="land-mdpi" />
    <splash src="res/screens/android/screen-xhdpi-landscape.png" density="land-xhdpi" />
    <splash src="res/screens/android/screen-hdpi-portrait.png" density="port-hdpi" />
    <splash src="res/screens/android/screen-ldpi-portrait.png" density="port-ldpi" />
    <splash src="res/screens/android/screen-mdpi-portrait.png" density="port-mdpi" />
    <splash src="res/screens/android/screen-xhdpi-portrait.png" density="port-xhdpi" />
  </platform>
  <platform name="ios">
    <splash src="res/screens/ios/screen-iphone-portrait.png" width="320" height="480" />
    <splash src="res/screens/ios/screen-iphone-portrait-2x.png" width="640" height="960" />
    <splash src="res/screens/ios/screen-ipad-portrait.png" width="768" height="1024" />
    <splash src="res/screens/ios/screen-ipad-portrait-2x.png" width="1536" height="2048" />
    <splash src="res/screens/ios/screen-ipad-landscape.png" width="1024" height="768" />
    <splash src="res/screens/ios/screen-ipad-landscape-2x.png" width="2048" height="1536" />
    <splash src="res/screens/ios/screen-iphone-568h-2x.png" width="640" height="1136" />
    <splash src="res/screens/ios/screen-iphone-portrait-667h.png" width="750" height="1334" />
    <splash src="res/screens/ios/screen-iphone-portrait-736h.png" width="1242" height="2208" />
    <splash src="res/screens/ios/screen-iphone-landscape-736h.png" width="2208" height="1242" />
  </platform>
  <platform name="windows">
    <splash src="res/screens/windows/SplashScreen.scale-100.png" width="620" height="300" />
    <splash src="res/screens/windows/SplashScreen.scale-240.png" width="1152" height="1920" />
    <splash src="res/screens/windows/SplashScreenPhone.scale-240.png" width="1152" height="1920" />
  </platform>
  <platform name="wp8">
    <splash src="res/screens/wp8/SplashScreenImage.jpg" width="480" height="800" />
  </platform>
  <plugin name="cordova-plugin-crosswalk-webview" version="1.5.0" src="https://github.com/crosswalk-project/cordova-plugin-crosswalk-webview" />
  <plugin name="cordova-plugin-ace" version="0.0.12" src="https://github.com/Microsoft/ace" />
  <engine name="ios" spec="~3.9.2" />
  <engine name="android" spec="~4.1.1" />
  <plugin name="cordova-plugin-ace" spec="https://github.com/microsoft/ace.git" />
  <preference name="ShowTitle" value="true" />
</widget>

即使在运行“清洁解决方案”和“清除 Cordova 缓存”后,我也会收到错误消息。

我将在单独的更新中发布标签条码。

更新#3 我的应用程序内容是一个 WebGL 画布。当我的 Mac iPad2 模拟器(纵向)第一次绘制时,窗口大小为 768(宽度)x 1004(高度),如下面的 JavaScript 控制台日志输出所示:

Window size: 768 x 1004
debug.js (29,24)
Window size: 768 x 960
debug.js (29,24)
Window size: 768 x 960
debug.js (29,24)

当我打开标签栏时,它会调整到 960 的高度。当我关闭标签栏(保持纵向)时,窗口高度不会返回到 1004。所以看起来窗口在标签时没有调整大小栏切换关闭。一旦我将设备旋转到横向,整个窗口就会重新绘制并且底部栏消失,同样,当我旋转回纵向时,整个窗口大小会恢复到 768 x 1004 并且空白底部栏也不存在。这是我的测试代码(正在进行中):

在 index.js 中,当 onDeviceReady 触发时,我的代码调用 GAME.initialize():

    function onDeviceReady() {
    // Handle the Cordova pause and resume events
    document.addEventListener( 'pause', onPause.bind( this ), false );
    document.addEventListener( 'resume', onResume.bind( this ), false );

    // TODO: Cordova has been loaded. Perform any initialization that requires Cordova here.
    GAME.initialize();
};

这是game.js中的代码:

//game.js

var GAME = { NAME: "hiio", VERMAJOR: 0, VERMINOR: 9, DEBUG: true, BUILD: 1, CLASSNAME: "GAME" };

GAME.initialize = function () {
    "use strict";
    //log if debug
    loginit();
    log(GAME.NAME + " " + GAME.VERMAJOR + "." + GAME.VERMINOR + (GAME.DEBUG ? " (Debug)" : " (Release)"));

    //renderer
    var testcanvas = document.getElementById("idcanvas");
    if (!GAME.renderer) GAME.renderer = new THREE.WebGLRenderer( { canvas: testcanvas } );

    //scene
    if (!GAME.scene) GAME.scene = new THREE.Scene();

    //camera
    GAME.setcamera();

    //orbitcontrols
    GAME.orbctls = new THREE.OrbitControls(GAME.camera);

    // ambient
    var al = new THREE.AmbientLight(0x222222, 0.5);
    GAME.scene.add(al);

    // light
    var dl = new THREE.DirectionalLight(0xffffff, 1.0);
    dl.position.set(2000, 2000, 500);
    GAME.scene.add(dl);

    // axes
    GAME.scene.add(new THREE.AxisHelper(4000));

    // Sphere
    var geometry = new THREE.SphereGeometry(500, 24, 8);
    var material = new THREE.MeshPhongMaterial({
        color: 0x00ffff,
        transparent: true,
        opacity: 0.7,
    });
    var mesh = new THREE.Mesh(geometry, material);
    GAME.scene.add(mesh);

    //FPS
    GAME.stats = initStats();

    //events
    window.addEventListener("resize", GAME.setcamera, false);

    //Ace
    TEST_ACE.initialize();

    animate(); //run
}

//camera
GAME.setcamera = function () {
    "use strict";
    var c = document.getElementById("idcanvas");
    var h = window.innerHeight;
    var w = window.innerWidth;

    if (!GAME.camera) { //new
        GAME.camera = new THREE.PerspectiveCamera(45, w / h, 1, 16000);
        GAME.camera.position.set(50, 100, 3000);
        GAME.scene.add(GAME.camera);
    }
    else { //change
        GAME.camera.aspect = (w / h);
    }

    if (GAME.renderer) { //onsize
        GAME.renderer.setSize(w, h); //this sets the height of the canvas.
        log("Window size: " + window.innerWidth + " x " + window.innerHeight);
    }

    if (GAME.orbctls) {
        GAME.target = new THREE.Vector3(0, 0, 0);
        GAME.orbctls.target0 = GAME.target.clone();
        GAME.orbctls.reset();
    }

    GAME.camera.updateProjectionMatrix();
}

function initStats() {
    "use strict";
    var stats = new Stats();
    stats.setMode(0);
    stats.domElement.style.position = 'absolute';
    stats.domElement.style.left = '0px';
    stats.domElement.style.top = '0px';
    document.getElementById("Stats-output").appendChild(stats.domElement);
    return stats;
}

//animate loop
var banimate = false;
function animate() {
    "use strict";
    requestAnimationFrame(animate);
    if (banimate) { loge("animate re-entry."); return; }
    banimate = true;

    GAME.renderer.render(GAME.scene, GAME.camera);
    GAME.stats.update();

    banimate = false;
};

//end

这是 test_act.js 代码(有点混乱抱歉):

//test_ace.js

var TEST_ACE = { CLASSNAME: "TEST_ACE" };
TEST_ACE.popupSegCtrl = null;
TEST_ACE.pageTabBar = null;

TEST_ACE.initialize = function () {
    "use strict";


    var abutton1 = document.getElementById("idbutton1");  //Tab Bar
    abutton1.addEventListener("click", TEST_ACE.dockTabs, false);

    return;
}

TEST_ACE.buildDockedTabsWithoutXaml = function () {
    var page = new ace.Page();
    page.setTitle("Docked");

    var tabBar = new ace.TabBar();
    var b1 = new ace.AppBarButton();
    var b2 = new ace.AppBarButton();
    var b3 = new ace.AppBarButton();
    var b4 = new ace.AppBarButton();
    var b5 = new ace.AppBarButton();

    b1.setLabel("Docked");
    b1.setIcon("www/images/info-{platform}.png");
    b1.addEventListener("click", function () { onTabClick(b1, 0); });

    b2.setLabel("Overlay");
    b2.setIcon("www/images/info-{platform}.png");
    b2.addEventListener("click", function () { onTabClick(b2, 1); });

    b3.setLabel("Fullscreen");
    b3.setIcon("www/images/info-{platform}.png");
    b3.addEventListener("click", function () { onTabClick(b3, 2); });

    b4.setLabel("Code");
    b4.setIcon("www/images/info-{platform}.png");
    b4.addEventListener("click", function () { onTabClick(b4, 3); });

    b5.setLabel("Plat-Specific UI");
    b5.setIcon("www/images/info-{platform}.png");
    b5.addEventListener("click", function () { onTabClick(b5, 4); });

    // TabBar's "content property" maps to a PrimaryCommands property.
    // Therefore, to add children, we get the PrimaryCommands collection:
    tabBar.getPrimaryCommands().add(b1);
    tabBar.getPrimaryCommands().add(b2);
    tabBar.getPrimaryCommands().add(b3);
    tabBar.getPrimaryCommands().add(b4);
    tabBar.getPrimaryCommands().add(b5);

    page.setBottomAppBar(tabBar);

    return page;
}

function onTabClick(a, b) {
    return;
}

TEST_ACE.dockTabs = function () {
    if (TEST_ACE.pageTabBar == null) {
        // Surround the WebView with native UI
        TEST_ACE.pageTabBar = TEST_ACE.buildDockedTabsWithoutXaml();

        // Replace the WebView with the loaded native page
        // (For the title setting in XAML to work on Android, ShowTitle must be
        //  set to true in the Android section of config.xml.)
        ace.getHostPage().setContent(TEST_ACE.pageTabBar);

        // Reparent the WebView inside the native page
        TEST_ACE.pageTabBar.setContent(ace.getHostWebView());

        // Save the native page so we can set its title as tabs are clicked
        _nativePage = TEST_ACE.pageTabBar;
    }
    else {
        ace.getHostPage().setContent(ace.getHostWebView());
        TEST_ACE.pageTabBar = null;
        GAME.setcamera();
    }
}

//end
4

2 回答 2

1

您引用的示例确实包含一个底部标签栏示例(请注意,它在 Android 中呈现在顶部)。单击第一个链接后,它就会出现在示例中。

更新:这是您在 JavaScript 中执行标签栏示例的方法,没有标记:

function buildDockedTabsWithoutXaml() {
    var page = new ace.Page();
    page.setTitle("Docked");

    var tabBar = new ace.TabBar();
    var b1 = new ace.AppBarButton();
    var b2 = new ace.AppBarButton();
    var b3 = new ace.AppBarButton();
    var b4 = new ace.AppBarButton();
    var b5 = new ace.AppBarButton();

    b1.setLabel("Docked");
    b1.setIcon("www/images/info-{platform}.png");
    b1.addEventListener("click", function() { onTabClick(b1, 0); });

    b2.setLabel("Overlay");
    b2.setIcon("www/images/info-{platform}.png");
    b2.addEventListener("click", function() { onTabClick(b2, 1); });

    b3.setLabel("Fullscreen");
    b3.setIcon("www/images/info-{platform}.png");
    b3.addEventListener("click", function() { onTabClick(b3, 2); });

    b4.setLabel("Code");
    b4.setIcon("www/images/info-{platform}.png");
    b4.addEventListener("click", function() { onTabClick(b4, 3); });

    b5.setLabel("Plat-Specific UI");
    b5.setIcon("www/images/info-{platform}.png");
    b5.addEventListener("click", function () { onTabClick(b5, 4); });

    // TabBar's "content property" maps to a PrimaryCommands property.
    // Therefore, to add children, we get the PrimaryCommands collection:
    tabBar.getPrimaryCommands().add(b1);
    tabBar.getPrimaryCommands().add(b2);
    tabBar.getPrimaryCommands().add(b3);
    tabBar.getPrimaryCommands().add(b4);
    tabBar.getPrimaryCommands().add(b5);

    page.setBottomAppBar(tabBar);

    return page;
}

function dockTabs() {
    // Surround the WebView with native UI
    var page = buildDockedTabsWithoutXaml();

    // Replace the WebView with the loaded native page
    // (For the title setting in XAML to work on Android, ShowTitle must be
    //  set to true in the Android section of config.xml.)
    ace.getHostPage().setContent(page);

    // Reparent the WebView inside the native page
    page.setContent(ace.getHostWebView());

    // Save the native page so we can set its title as tabs are clicked
    _nativePage = page;
}

然而,在 Ace 中可能需要做更多的工作才能为您提供跨平台的 Table View 体验。有一个 ListBox 控件,但目前它的功能很少。有一次,我曾尝试过一个跨平台的 TableView 控件。我会考虑将其添加到 Ace 以帮助满足您的需求。如果您有任何其他问题/要求,请告诉我!

于 2016-02-29T18:25:13.823 回答
0

对于 Android 问题,我相信这是因为您的 ShowTitle 首选项元素需要是根小部件元素的直接子元素。您可以在https://github.com/Microsoft/ace/blob/master/examples/AceExamples/config.xml的底部看到一个示例。如果是这样,那么 AceExamples 中的注释确实是错误的,我们应该修复它!对于那个很抱歉。

对于 iOS 问题,我只是尝试在所有 5 个 iPad 模拟器上使用类似的 AceExamples 代码重现它,但不能。你能分享你的代码吗?

于 2016-03-01T00:38:52.590 回答