为什么我的标签栏会破坏我的AndEngine活动?

问题描述:

我的Android应用程序有一个标签栏,使用Intent在每个标签中启动内容,如Android的API演示example。我已将AndEngine活动置于其中一个选项卡下。我的第一个问题是:这是一个合理的想法?或者如果我使用的是AndEngine,在AndEngine中实现我的应用程序的整个UI会更好吗?为什么我的标签栏会破坏我的AndEngine活动?

假设我还没有进入非首发,我碰到的具体问题如下。这个AndEngine活动 - 我在基于标签的应用中加入的活动 - 是AndEngine PinchZoom example的简化版本。它运作良好,直到您切换离开标签,然后再返回。此时,视图会再次出现,但您无法再滚动或缩放。

这是我的活动课。让我知道你是否也想看标签栏类。正如你所看到的,当用户离开标签页时,我试图关闭各种听众和检测器,并在返回时将它们重新打开。但是我已经使用断点建立了onSceneTouchEvent,当我在返回选项卡后触摸屏幕时不会调用它。是干预和捕捉我的触摸事件?还是有些东西变得不活跃,需要恢复生机?

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

编辑:

感谢您的建议,纪尧姆。当用户返回到选项卡时,您没有调用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); 
    } 
} 
+0

在您的代码的第一次运行中,enableTouchDetectors被调用两次,但不需要。 – 2012-02-14 15:21:14

+0

我刚刚在调试器中检查过,它只被调用一次。也许你的错误是假定onResume在onCreateScene之后被调用,事实上它之前被调用过。 – 2012-02-15 10:03:28

Tommy: 我在我自己的应用程序中有这个相同的场景,其中我需要三个选项卡,其中一个是andEngine。但是我发现TabActivity并没有像启动一个新的Intent一样重新初始化这些标签。如果您记录其他选项卡的生命周期,您将会看到这不仅仅是一个引擎开发的事情,而是一个TabActivity事物。 这里有关于这一问题的真正有用的线索: http://groups.google.com/group/android-developers/browse_thread/thread/d89f1d5f913bb6f7

包括将每个标签作为一个单一的活动中的观点的例子。链接在这里。我使用了来自commonsware myeslf的代码,发现它们的库和示例经过了良好测试和高质量。 https://github.com/commonsguy/cw-android/tree/master/Fancy/Tab/

在anycase,我无法找到一种方法,使一tabactivity工作,而无需重新编写Andengine的核心类,这是超出了我能在这个项目做的范围。

所以我做了一个解决方法是: 我自己构建标签作为三个活动共享一个页脚,让你在它们之间交换。我不得不在历史中徘徊一些,并在适当的时候覆盖后退按钮的行为以保持在标签内。 另外,我用的Android清单的意图标志:

android:launchMode="singleInstance" 

这有助于应用程序通过确保有有史以来Andengine标签永远只能一个实例运行平稳。

希望这会有所帮助。如果一个引擎可以与TabActivity兼容,那将是非常棒的,但我认为它现在不是完全的。

+0

非常感谢。坏消息,但一些有希望的线索。不幸的是,我有一些假期来临,所以我可能无法在赏金到期之前解决问题。我要做的就是明天晚上奖励赏金,如果这看起来仍然是最好的答案,但是等到我有了一个可行的解决方案后再接受它。 – 2012-02-16 12:26:48

+0

嗯,我昨天尝试使用LayoutGameActivity约一个小时。只要我不添加tabhost,它就可以正常工作。它编译,它启动,但它然后挂起。永远不会抛出错误或任何东西。只是冻结。 – 2012-02-16 19:16:52

+0

好的,非常感谢您的帮助。当我从我的旅行回来时,我会立刻奖赏你的赏金,然后进行适当的调查。 – 2012-02-17 15:22:27

当您使用断点进行调试时,您的onResumeGame方法是否被调用?

也许你需要设置初始化(具体setOnSceneTouchListener(this))在基本onResume?或者你也可以尝试在onCreateScene中添加它。

+0

感谢您的想法。我稍微前进一点,但问题依然存在。我已经用细节更新了这个问题。 – 2012-02-13 16:53:15