【问题标题】:Why does my tab bar break my AndEngine activity?为什么我的标签栏会破坏我的 AndEngine 活动?
【发布时间】:2012-02-11 14:43:47
【问题描述】:

我的 Android 应用有一个标签栏,它使用 Intent 来启动每个标签中的内容,如 Android 的 API Demos example 中所示。我在其中一个选项卡下放置了一个 AndEngine 活动。我的第一个问题是:这是一个合理的想法吗?或者,如果我使用的是 AndEngine,在 AndEngine 中实现我的应用的整个 UI 是否更好?

假设我还没有入门,我遇到的具体问题如下。这个 AndEngine 活动——我在我的基于标签的应用程序中加入的活动——是 AndEngine PinchZoom example 的简化版本。在您切换离开选项卡然后再返回之前,它运行良好。此时,视图会重新出现,但您无法再滚动或缩放。

这是我的活动课。如果您也想查看标签栏类,请告诉我。如您所见,我尝试在用户离开选项卡时关闭各种侦听器和检测器,并在它们返回时重新打开它们。但是我已经使用断点建立了 onSceneTouchEvent 在返回选项卡后触摸屏幕时不会被调用。有什么东西在干预和捕捉我的触摸事件吗?还是有什么东西变得不活跃,需要恢复活力?

我也在 AndEngine 论坛上posted了这个问题。

编辑:

感谢您的建议,纪尧姆。没错,当用户返回选项卡时,不会调用 onResumeGame。我以为我已经检查过了,但我一定是把可滚动图形一次放在两个选项卡下弄糊涂了。此时会调用 onResume 方法,而不会调用 onCreateGame。因此,我更改了代码,以便在onResume 中打开触摸检测器。这个方法肯定会在我想要的时候被调用,所以我想这是一个进步,但是当我返回标签后触摸屏幕时,onSceneTouchEvent 仍然没有被触发。更新后的代码如下,更改标记为// NEW

public class HomeActivity extends SimpleBaseGameActivity implements IOnSceneTouchListener,
    IScrollDetectorListener, IPinchZoomDetectorListener {
    private static final int CAMERA_WIDTH = 480;
    private static final int CAMERA_HEIGHT = 628;

    private boolean mInitialised = false; // NEW
    private Scene mScene;
    private ZoomCamera mZoomCamera;
    private ITexture mTexture;
    private ITextureRegion mGrassTextureRegion;
    private SurfaceScrollDetector mScrollDetector;
    private PinchZoomDetector mPinchZoomDetector;
    private float mPinchZoomStartedCameraZoomFactor;

    @Override
    public EngineOptions onCreateEngineOptions() {
        this.mZoomCamera = new ZoomCamera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
        final EngineOptions engineOptions = new EngineOptions(true,
            ScreenOrientation.PORTRAIT_FIXED,
            new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), this.mZoomCamera);

        if (MultiTouch.isSupported(this)) {
            if (MultiTouch.isSupportedDistinct(this)) {
                Toast.makeText(this, "MultiTouch detected.", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(
                    this,
                    "MultiTouch detected, but your device has problems distinguishing between "
                        + "fingers.", Toast.LENGTH_LONG).show();
            }
        } else {
            Toast.makeText(this, "Sorry your device does NOT support MultiTouch!",
                Toast.LENGTH_LONG).show();
        }

        return engineOptions;
    }

    @Override
    public void onCreateResources() {
        try {
            this.mTexture = new BitmapTexture() {
                @Override
                protected InputStream onGetInputStream() throws IOException {
                    return getAssets().open("gfx/background_grass.png");
                }
            }.load(this.getTextureManager());
            this.mGrassTextureRegion = TextureRegionFactory.extractFromTexture(mTexture);
        } catch (IOException e) {
            Debug.e(e);
        }
    }

    @Override
    public Scene onCreateScene() {
        this.mEngine.registerUpdateHandler(new FPSLogger());
        this.mScene = new Scene();
        this.mScene.setOnAreaTouchTraversalFrontToBack();
        this.mScene.setBackground(new Background(0.09804f, 0.6274f, 0.8784f));

        // Calculate the coordinates for the sprite, so it's centered on the
        // camera.
        final float centerX = (CAMERA_WIDTH - this.mGrassTextureRegion.getWidth()) / 2;
        final float centerY = (CAMERA_HEIGHT - this.mGrassTextureRegion.getHeight()) / 2;

        // Create the sprite and add it to the scene.
        final Sprite grass = new Sprite(centerX, centerY, this.mGrassTextureRegion,
            this.getVertexBufferObjectManager());
        this.mScene.attachChild(grass);

        enableTouchDetectors(); // NEW
        mInitialised = true; // NEW

        return this.mScene;
    }

    @Override
    public void onPause() {
        this.mScene.setTouchAreaBindingOnActionDownEnabled(false);
        this.mScene.setOnSceneTouchListener(null);
        this.mPinchZoomDetector = null;
        this.mScrollDetector = null;
        super.onPause();
    }

    // NEW method
    @Override
    public void onResume() {
        super.onResume();
        // If returning to the tab, switch the touch detectors back on.
        if (mInitialised) {
            enableTouchDetectors();
        }
    }

    // This method has been removed since Guillaume's answer.
//    @Override
//    public void onResumeGame() {
//        super.onResumeGame();
//        this.mScrollDetector = new SurfaceScrollDetector(this);
//        this.mPinchZoomDetector = new PinchZoomDetector(this);
//        this.mScene.setOnSceneTouchListener(this);
//        this.mScene.setTouchAreaBindingOnActionDownEnabled(true);
//    }

    @Override
    public void onScrollStarted(final ScrollDetector pScollDetector, final int pPointerID,
        final float pDistanceX, final float pDistanceY) {
    }

    @Override
    public void onScroll(final ScrollDetector pScollDetector, final int pPointerID,
        final float pDistanceX, final float pDistanceY) {
        final float zoomFactor = this.mZoomCamera.getZoomFactor();
        this.mZoomCamera.offsetCenter(-pDistanceX / zoomFactor, -pDistanceY / zoomFactor);
    }

    @Override
    public void onScrollFinished(final ScrollDetector pScollDetector, final int pPointerID,
        final float pDistanceX, final float pDistanceY) {
    }

    @Override
    public void onPinchZoomStarted(final PinchZoomDetector pPinchZoomDetector,
        final TouchEvent pTouchEvent) {
        this.mPinchZoomStartedCameraZoomFactor = this.mZoomCamera.getZoomFactor();
    }

    @Override
    public void onPinchZoom(final PinchZoomDetector pPinchZoomDetector,
        final TouchEvent pTouchEvent, final float pZoomFactor) {
        this.mZoomCamera.setZoomFactor(this.mPinchZoomStartedCameraZoomFactor * pZoomFactor);
    }

    @Override
    public void onPinchZoomFinished(final PinchZoomDetector pPinchZoomDetector,
        final TouchEvent pTouchEvent, final float pZoomFactor) {
    }

    @Override
    public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) {
        this.mPinchZoomDetector.onTouchEvent(pSceneTouchEvent);

        if (this.mPinchZoomDetector.isZooming()) {
            this.mScrollDetector.setEnabled(false);
        } else {
            if (pSceneTouchEvent.isActionDown()) {
                this.mScrollDetector.setEnabled(true);
            }
            this.mScrollDetector.onTouchEvent(pSceneTouchEvent);
        }

        return true;
    }

    // NEW method
    private void enableTouchDetectors() {
        this.mScrollDetector = new SurfaceScrollDetector(this);
        this.mPinchZoomDetector = new PinchZoomDetector(this);
        this.mScene.setOnSceneTouchListener(this);
        this.mScene.setTouchAreaBindingOnActionDownEnabled(true);
    }
}

【问题讨论】:

  • 在您的代码第一次运行时,enableTouchDetectors 被调用了两次,但不需要。
  • 我刚刚签入了调试器,它只被调用了一次。也许你的错误是假设 onResume 是在 onCreateScene 之后调用的,而实际上它是在之前调用的。

标签: android andengine


【解决方案1】:

汤米: 我在自己的应用程序中遇到了同样的情况,其中我需要三个选项卡,其中一个是 andEngine。但我发现 TabActivity 并没有以与触发新 Intent 相同的方式重新初始化选项卡。如果您记录其他选项卡之一的生命周期,您会发现这不仅仅是一个andengine 的东西,而是一个TabActivity 的东西。 这里有一个关于这个问题的非常有用的线程: http://groups.google.com/group/android-developers/browse_thread/thread/d89f1d5f913bb6f7

包括将每个选项卡设置为单个活动中的视图的示例。链接在这里。我使用了来自 commonsware myeslf 的代码,发现他们的库和示例经过了良好的测试和高质量。 https://github.com/commonsguy/cw-android/tree/master/Fancy/Tab/

无论如何,如果不重新编写 Andengine 的核心类,我就无法找到让 tabactivity 工作的方法,这超出了我在项目中可以做的范围。

所以我做的一个解决方法是: 我自己将标签构建为三个共享页脚的活动,让您可以在它们之间进行交换。我不得不对历史进行一些修改,并在适当的时候覆盖后退按钮的行为以保留在选项卡中。 此外,我在 Android 清单中使用了一个意图标志:

android:launchMode="singleInstance"

通过确保只创建了一个 Andengine 选项卡实例,从而帮助应用顺利运行。

希望这会有所帮助。如果andengine可以与TabActivity兼容就好了,但我认为目前还没有完全兼容。

【讨论】:

  • 非常感谢。坏消息,但有一些有希望的线索。不幸的是,我有一些假期即将到来,所以我可能无法在赏金到期之前解决这个问题。如果这看起来仍然是最佳答案,我将在明天晚上奖励赏金,但请等到我找到可行的解决方案后再接受它。
  • 我昨天尝试使用 LayoutGameActivity 大约一个小时。只要我不添加标签主机,它就可以正常工作。它编译,启动,但随后挂起。从不抛出错误或任何东西。只是冻结。
  • 好的,感谢您的帮助。我现在会奖励你赏金,然后在我旅行回来时进行适当的调查。
  • 谢谢,我希望我能找到解决方案。昨晚我再次尝试使用 LayoutGameActivity,但又一次,Andengine 的初始化方式与 TabHost 发生了冲突。如果您找到解决方案,请在此处发布。
  • GLES2。 (使评论有效的填充物。)
【解决方案2】:

当你使用断点调试时,你的onResumeGame方法被调用了吗?

也许您需要在基本的onResume 中设置您的初始化(特别是setOnSceneTouchListener(this))?或者您也可以尝试将其添加到onCreateScene

【讨论】:

  • 感谢您的想法。我走得更远了,但问题仍然存在。我已经用详细信息更新了问题。
猜你喜欢
  • 1970-01-01
  • 2019-04-08
  • 2015-08-19
  • 2013-06-25
  • 2013-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-07
相关资源
最近更新 更多