Icecream Sandwich 视图行为
Posted
技术标签:
【中文标题】Icecream Sandwich 视图行为【英文标题】:Icecream Sandwich View Behavior 【发布时间】:2012-01-20 22:38:06 【问题描述】:我有一个针对 SDK 3.0 构建的应用程序。
在这个应用程序中,有一个相对布局,它有一个全屏 VideoView,下面有一个按钮。视频视图上设置了一个 onTouchListener 来监听手势。
视频播放完毕后,VideoView
设置为 visibility(View.GONE)
在运行 Honeycomb(Toshiba Thrive 和 HTC Flyer)的设备上,此功能与我预期的一样。一旦VideoView
是GONE
,按钮就可以点击了。
但是,在运行 ICS(摩托罗拉 Xoom)的设备上,当我尝试按下按钮时,事件会转到 VideoView 触摸侦听器而不是按钮单击侦听器。
视图在这种情况下的行为方式是有意在 ICS 上改变的还是这是一个错误?
另外,我尝试解决这个问题的第一件事也给了我一些奇怪的结果。
我添加了这些行而不是 setVisibility(View.GONE);
Log.i(MainActivity.myTag, "vid is null ? " + (mVideoView == null));
Log.i(MainActivity.myTag, "lyt is null ? " + (vidLyt == null));
vidLyt.removeView(mVideoView); //This line throws null pointer
认为如果 VideoView
从我的父布局中删除,它肯定不再接受触摸事件。
但这会导致 removeView() 调用上出现空指针。即使它上面的日志语句表明这两个对象实际上都不为空。这是一个例外:
据我所知,它实际上并没有指向我活动中的任何行,但是这 3 个语句是目前唯一被调用的 3 个语句,并且两个 Log 语句都成功完成。
01-20 16:32:42.480: ERROR/androidRuntime(9416): java.lang.NullPointerException
01-20 16:32:42.480: ERROR/AndroidRuntime(9416): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2488)
01-20 16:32:42.480: ERROR/AndroidRuntime(9416): at android.view.View.getDisplayList(View.java:10415)
01-20 16:32:42.480: ERROR/AndroidRuntime(9416): at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:2597)
01-20 16:32:42.480: ERROR/AndroidRuntime(9416): at android.view.View.getDisplayList(View.java:10380)
01-20 16:32:42.480: ERROR/AndroidRuntime(9416): at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:2597)
01-20 16:32:42.480: ERROR/AndroidRuntime(9416): at android.view.View.getDisplayList(View.java:10380)
01-20 16:32:42.480: ERROR/AndroidRuntime(9416): at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:2597)
01-20 16:32:42.480: ERROR/AndroidRuntime(9416): at android.view.View.getDisplayList(View.java:10380)
01-20 16:32:42.480: ERROR/AndroidRuntime(9416): at android.view.HardwareRenderer$GlRenderer.draw(HardwareRenderer.java:840)
01-20 16:32:42.480: ERROR/AndroidRuntime(9416): at android.view.ViewRootImpl.draw(ViewRootImpl.java:1910)
01-20 16:32:42.480: ERROR/AndroidRuntime(9416): at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1634)
01-20 16:32:42.480: ERROR/AndroidRuntime(9416): at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2442)
01-20 16:32:42.480: ERROR/AndroidRuntime(9416): at android.os.Handler.dispatchMessage(Handler.java:99)
01-20 16:32:42.480: ERROR/AndroidRuntime(9416): at android.os.Looper.loop(Looper.java:137)
01-20 16:32:42.480: ERROR/AndroidRuntime(9416): at android.app.ActivityThread.main(ActivityThread.java:4424)
01-20 16:32:42.480: ERROR/AndroidRuntime(9416): at java.lang.reflect.Method.invokeNative(Native Method)
01-20 16:32:42.480: ERROR/AndroidRuntime(9416): at java.lang.reflect.Method.invoke(Method.java:511)
01-20 16:32:42.480: ERROR/AndroidRuntime(9416): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
01-20 16:32:42.480: ERROR/AndroidRuntime(9416): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
01-20 16:32:42.480: ERROR/AndroidRuntime(9416): at dalvik.system.NativeStart.main(Native Method)
编辑:这里是相关部分。
mVideoView.setOnTouchListener(new OnTouchListener()
public boolean onTouch(View v, MotionEvent me)
if(me.getAction() == MotionEvent.ACTION_DOWN)
touchY = me.getY();
//I am using the if statement below to fix the unexpected behavior currently.
//by returning false even though the VideoView receives the touch, this
//causes it to essentiall ignore it and pass it along to the button.
if(mVideoView.getVisibility() == View.GONE)
return false;
else if(me.getAction() == MotionEvent.ACTION_UP)
Log.i(MainActivity.myTag, "Old = " + touchY + " New = " + me.getY());
//Moved north a little is the gesture I am interested in.
if(me.getY() < (touchY - 100))
Thread t = new Thread()
public void run()
timeStamp = mVideoView.getCurrentPosition();
mVideoView.stopPlayback();
//Since we are in back thread use a handler to GONEify the VideoView
animVidHandler.sendEmptyMessage(0);
//There is some network stuff here that justifies the use of a
//different thread. But I am certain it isn't affecting the
//behavior of my views.
;
t.start();
return true;
);
处理程序回调内部只有一条语句:
mVideoView.startAnimation(flyOffAnim); //translate animation to "fly off" the screen.
我之前忘了提到动画。这可能与这种行为有关吗?
flyOffAnimation 上设置了一个只包含 1 条语句的 completionListener:
mVideoView.setVisibility(View.GONE);
【问题讨论】:
理论上这种行为不应该改变。即使在 ICS 中,ViewGroup
仍然检查每个孩子是否“能够”接收触摸,并且该能力由他们的视图掩码仅等于 VISIBLE
定义,因此应在父视图中跳过 GONE
视图dispatchTouchEvent()
。我将尝试抽出一些时间来实际测试这个示例。
它可能是特定于设备的,但我只是在 4.0.3 模拟器中运行了一个简单的示例,它按预期工作(附加到 VideoView
的侦听器在可见时获取触摸,然后传递给消失后下方的按钮),因此这不是平台范围的问题。也许发布一些代码?也许你的触摸监听器有什么东西?
我发现***.com/a/7445557/247013 很有用且相关。
【参考方案1】:
视图在这种情况下的行为方式是有意在 ICS 上改变的还是这是一个错误?
VideoView
真的是一个SurfaceView
,这真的不是一个普通的View
,虽然它在电视上播放。
据我所知,它实际上并没有指向我活动中的任何行,但是这 3 个语句是目前唯一被调用的 3 个语句,并且两个 Log 语句都成功完成。
您没有从这三个语句中得到NullPointerException
。您可能会在其他地方收到NullPointerException
作为这三个语句的副作用。在这种情况下,我不知道你为什么会这样做。
也许尝试切换到在 ViewFlipper
中让两者成为对等方,并以这种方式在模式之间切换。
【讨论】:
以上是关于Icecream Sandwich 视图行为的主要内容,如果未能解决你的问题,请参考以下文章
为啥 EditText 在 Ice Cream Sandwich 中保留其 Activity 的上下文
Android 4 ICS Ice Cream Sandwich - 包含表单的 iframe
在 Android 4.0.x Ice Cream Sandwich 中,WebView 不会在应用启动时呈现本地 HTML 页面