黑莓中的触摸事件处理

3

我尝试在Blackberry 9550模拟器上实现简单的触摸事件处理,但它不起作用。实际上,touchEvent从未被调用,因为控制台中从未出现任何文本。此外,当触摸屏幕时,会出现令人讨厌的“完整菜单”。

以下是代码:

package mypackage;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.EventInjector.TouchEvent;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.VirtualKeyboard;
import net.rim.device.api.ui.container.MainScreen;

public class MyScreen extends MainScreen
{   
public MyScreen()
{    
    super(NO_SYSTEM_MENU_ITEMS);
    getScreen().getVirtualKeyboard().setVisibility(VirtualKeyboard.HIDE_FORCE);      
    add(new HandleTouch());

}

class HandleTouch extends Field {

    protected void layout(int width, int height) {
        setExtent(width, height);
    }

    public void paint(Graphics graphics) {
        graphics.drawBitmap(0, 0, this.getWidth(), this.getHeight(), Bitmap.getBitmapResource("bg.png"), 0, 0);
    }

    public boolean isFocusable() { return true;}

    protected boolean touchEvent(TouchEvent message) {
        switch( message.getEvent() ) {
        case TouchEvent.CLICK:
            System.out.println("----------------------------->CLICK");
            return true;
        case TouchEvent.DOWN:
            System.out.println("----------------------------->DOWN");
            return true;    
        case TouchEvent.MOVE:
            System.out.println("----------------------------->MOVE");
            return true;    
        }
        System.out.println("PRINT ME SOMETHING IN ANY CASE");
        return false;
    }

    public HandleTouch() {

    }
}

}

2个回答

6

首先,使用下面的代码:

protected void layout(int width, int height) {
    setExtent(width, height);
}

您实际上正在设置一个非常大的字段大小。这是因为BB UI框架将最大可用/可能的尺寸传递给layout(int width, int height),因此字段应该在传递的值范围内使用一些部分。在这种特殊情况下,宽度将是显示器的宽度(360像素),而高度是VerticalFieldManager的最大可能高度(您向其中添加屏幕字段的那个,它隐含地存在于屏幕的内部)(1073741823像素)。因此,最终结果可能会导致需要非常大的Bitmap对象与字段一起绘制,并且您可能会收到未捕获的错误"Bitmap is too large"(我在Storm 9530上遇到了这个错误)。
因此,layout()应该使用一些相对较小的值,例如:
protected void layout(int width, int height) {
    setExtent(Math.min(width, 360), Math.min(height, 480));
}

2).

实际上,touchEvent从未被调用

其实它确实被调用了。要看到这一点,您只需触摸即可(而不是点击)。鼠标的左按钮模拟点击(一系列TouchEvent.DOWN > TouchEvent.CLICK > TouchEvent.UNCLICK > TouchEvent.UP),右按钮模拟触摸(一系列TouchEvent.DOWN > TouchEvent.UP)。

3).

此外,每次触摸屏幕时都会出现一个烦人的“全菜单”。

这是因为您的字段没有消耗TouchEvent.UNCLICK事件。例如,使用此代码,您的字段将不会显示弹出窗口:

protected boolean touchEvent(TouchEvent message) {
    return true;
}

但是,这对于弹出窗口来说是一个不好的解决方案。更好的方法是了解导致弹出窗口的真正原因。如果未消耗 TouchEvent.UNCLICK 事件,则 BB UI 框架将调用字段的 getContextMenu(int instance)makeContextMenu(ContextMenu contextMenu, int instance) 方法。因此,为了禁用弹出窗口(实际上是由 getContextMenu(int instance) 创建的 ContextMenu),您应该重写 getContextMenu(int instance),使其像这样:

public ContextMenu getContextMenu(int instance) {
    // just in case check if a context menu is requested
    // in order not to disable other types of menu
    boolean isContextMenu = (Menu.INSTANCE_CONTEXT == instance);
    return isContextMenu ? null : super.getContextMenu(instance);
}

4). 最后,我建议不要更改touchEvent(TouchEvent message)方法的本地/默认行为。你可以观察/记录它,但不要更改(始终调用其超级版本)。这是因为触摸事件处理比看起来更加复杂。在这里很容易出现棘手的错误。我相信大多数程序员不应该更改touchEvent(TouchEvent message)的本地行为,除非他们真的想创建一些自定义UI组件来处理触摸手势。通常他们只想对点击做出反应(表现得像一个ButtonField),但是为此您可以简单地重写navigationClick(int status, int time)navigationUnclick(int status, int time)。当用户在触摸屏幕上点击您的字段时,BB UI框架将调用这些方法。


我在哪里可以找到TouchEvent.CLICK的确切含义,以及何时适合捕获它们?我发现BB文档非常没有帮助。 - Mike D
@Mike D:一个起点是API(一如既往)。请查看http://www.blackberry.com/developers/docs/6.0.0api/net/rim/device/api/ui/TouchEvent.html。至于“何时适合捕获它们”-这取决于你做什么。在大多数情况下,您不需要担心这种低级别的处理(请参见我上面的帖子)。 - Vit Khudenko
嗨。我正在使用Blackberry Touch Event,并且需要处理MOVE,UP,DOWN以移动图像旋转木马,以及TouchEvent.CLICK以生成某些特定操作。我的问题是touchEvent被多次调用。我该如何防止这种情况发生?因为行为变得混乱了。例如:当我只想要CLICK事件时,UP,DOWN,MOVE和CLICK会一个接一个地触发。 - mariomunera
@mariomunera:请在Stack Overflow上提一个单独的问题。 - Vit Khudenko
@Arhimed:谢谢,这是链接 http://stackoverflow.com/questions/16818850/touch-event-blackberry-triggered-multiple-times - mariomunera

3
我想为Arhimed的回答添加额外的信息,因为这似乎是谷歌触摸事件着陆页...
我的经验不是要与他相矛盾,而是要为未来的读者添加可能的解决方案。我正在使用BB OS 5.0。我的经验是使用Storm模拟器和Torch设备。我的应用最初是为OS 4.5编写的,因此它可能在某种兼容模式下运行。
1) 如他所述,如果 touchEvent(TouchEvent)返回false,则Touch Event会传递给Navigation Click事件。如果 navigationClick(int, int)返回false,则这会促使系统显示一个 ContextMenu
2) 在我的系统中,我找不到getContextMenu(int)方法。所以我无法测试他的第3点。我认为这是在BB6或更高版本中添加的。
3) 我发现了getContextMenu() - 即它不带参数。我尝试重写该方法以返回null。
奇怪的是,这个方法只在初始上下文菜单弹出后才被调用!初始上下文菜单弹出(?),上面有一个“完整菜单”按钮。当按下该按钮时,将调用此方法,并可以用于填充出现的MainMenu。...奇怪...
然而,这意味着覆盖该方法未解决我的问题。
4) 我无法通过在 touchEvent(TouchEvent)中返回true来获得解决方案。我同意这将是不好的形式(hack),但我已经学会了在BB平台上进行很多黑客攻击。但是,滚动列表字段需要传递触摸事件,以便滚动起作用。
5) 最终,我找到了类似于OP问题的 TouchEvent.UNCLICK 的东西。花了我18个月的时间才发现 navigationUnClick(int, int)方法。与我以上提到的第1点类似,未处理的 UNCLICK 成为 navigationUnClick(int, int)调用,这也可能导致显示上下文菜单。
因此,通过向 navigationClick(int, int) navigationUnClick(int, int)添加类似的逻辑,我能够使我的列表和触摸相互交互。
这只是补充信息,可能会增加接受的回答。

感谢您的帖子。关于“我找不到一个方法getContextMenu(int)” - 很可能是我在Storm 9530 4.7模拟器上学习的时候。然而,了解RIM能够做什么之后,我不会惊讶他们在OS 5中以后悄悄地改变了API。因此,看起来我调查了某种边角情况,而实际上应该有更好的方法来管理上下文菜单。 - Vit Khudenko
我不确定哪个更好...对于BB,我认为我们可以同意存在很多"边角案例" - 这就是为什么我想添加到这个页面的原因。关于这种奇怪问题的更多信息越多越好。 - Richard Le Mesurier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接