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)的设备上,此功能与我预期的一样。一旦VideoViewGONE,按钮就可以点击了。

但是,在运行 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 视图行为的主要内容,如果未能解决你的问题,请参考以下文章

icecream 调试代码

Icecream:比 print 更好用的调试工具

svn 命令行怎么解决冲突

为啥 EditText 在 Ice Cream Sandwich 中保留其 Activity 的上下文

Android 4 ICS Ice Cream Sandwich - 包含表单的 iframe

在 Android 4.0.x Ice Cream Sandwich 中,WebView 不会在应用启动时呈现本地 HTML 页面