Webview导致的对话框动画错乱:Android的bug?

3
我创建了一个带有进入和退出缓慢动画的对话框。但是该对话框包含一个名为myMsg的webview(加载本地文件,因此没有延迟),这会使动画出现问题。
使用以下代码(没有webview),对话框可以完美地工作,并在进入和退出时进行动画处理。但是,如果取消注释//builder.setView(myMsg)这一行,则退出动画仍然完美运行,但进入动画不会执行(或执行得太快)。有趣的是,如果我最小化应用程序并再次最大化它,则进入对话框动画就可以正常执行。
就像webview加载干扰了进入动画一样。我尝试在webview加载后显示对话框,但结果相同。
这不是很疯狂吗?有什么线索可以解释发生了什么以及如何解决它吗?任何帮助都将不胜感激。
以下是代码的相关部分:
    WebView myMsg = new WebView(context);
    myMsg.loadUrl("file:///android_asset/page.html");

    AlertDialog.Builder builder = new AlertDialog.Builder(context);
    builder.setIcon(R.drawable.ic_launcher);
    //builder.setView(myMsg);
    builder.setTitle("Some Title");
    final AlertDialog dialog = builder.create();

    WindowManager.LayoutParams lp = dialog.getWindow().getAttributes();
    lp.windowAnimations = R.style.AnimateDialog;

    dialog.show();
    dialog.getWindow().setAttributes(lp);

还有样式方面的内容,

<style name="AnimateDialog">
    <item name="android:windowEnterAnimation">@anim/in_left</item>
    <item name="android:windowExitAnimation">@anim/out_left</item>
</style>

编辑

我尝试使用setWebViewClient,但没有成功(如果没有dialog.getWindow().setLayout...这行代码,进入动画就无法正常工作):

    WebView myMsg = new WebView(context);
    myMsg.getSettings().setJavaScriptEnabled(true);
    myMsg.loadUrl("file:///android_asset/" + page);
    myMsg.setBackgroundColor(0);
    myMsg.setSoundEffectsEnabled(true);

    AlertDialog.Builder builder = new AlertDialog.Builder(context);
    builder.setIcon(R.drawable.ic_launcher);
    builder.setTitle("SomeTitle");
    builder.setView(myMsg);
    final AlertDialog dialog = builder.create();

    myMsg.setWebViewClient(new WebViewClient() {
        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            dialog.show();
            dialog.getWindow().setWindowAnimations(R.style.AnimateDialog);
            dialog.getWindow().setLayout(WindowManager.LayoutParams.FILL_PARENT, WindowManager.LayoutParams.FILL_PARENT);
        }
    }

编辑2

我还尝试了使用Dialog而不是AlertDialog,并使用xml布局,出现了相同的问题(也尝试过使用WebView.loadData而不是WebView.loadUrl,问题相同):

    final Dialog d = new Dialog(context);
    d.setContentView(R.layout.viewhtml);
    d.setTitle("SomeTitle");
    // Without this, Enter animation does not work
    d.getWindow().setLayout(WindowManager.LayoutParams.FILL_PARENT,
            WindowManager.LayoutParams.FILL_PARENT);
    WebView wv = (WebView) d.findViewById(R.id.webview);
    wv.loadUrl("file:///android_asset/" + page);
    wv.setBackgroundColor(0);
    d.getWindow().setWindowAnimations(R.style.AnimateDialog);
    wv.setWebViewClient(new WebViewClient() {
        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            d.show();
        }
    });

这是对话框的 XML 布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

<WebView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/webview"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:soundEffectsEnabled="true" >
</WebView>

</LinearLayout>

编辑3

我刚刚意识到,当使用TextView.setText(Html.fromHTML…)来代替WebView时,同样的问题也会发生在TextView上。此外,如果我在dialog.show()之后添加dialog.getWindow().setLayout(600,800),则动画将按预期执行。因此,问题似乎是没有提前知道对话框大小就无法执行动画?

2个回答

0
你的对话框动画看起来混乱的原因是WebView内容的异步加载性质。因此,即使内容来自本地文件或字符串,将loadUrlloadData甚至loadDataWithBaseURL放在dialog.show()之前也不能保证内容已经完全加载完成,仍然会有轻微延迟(通常不到一秒钟)。
如果你想要真正在WebView内容完全加载后才显示对话框,则必须在WebViewClientonPageFinished中显示对话框。我已经进行了测试,并在ICS上运行良好,但当用户激活对话框时,从可用的WebView内容到达还需要稍微的时间延迟。如果这种轻微延迟可以接受,那么这个解决方案可能适合你。
你可以按照以下方式修改代码(更新以包括setWebViewClient):
WebView myMsg = new WebView(context);

AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setIcon(R.drawable.ic_launcher);
builder.setView(myMsg);
builder.setTitle("Some Title");
final AlertDialog dialog = builder.create();

// hook a listener for page load complete
WebViewClient webviewclient = new WebViewClient() {
    @Override  
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
        dialog.show(); // show the dialog here
    }
};
myMsg.setWebViewClient(webviewclient);

myMsg.loadUrl("file:///android_asset/page.html");
WindowManager.LayoutParams lp = dialog.getWindow().getAttributes();
lp.windowAnimations = R.style.AnimateDialog;

//dialog.show(); // do not show until content is truly available
dialog.getWindow().setAttributes(lp);

我已经在我的 Android 4.3 版本的 Nexus 7 上测试过了,但是内容显示仍然受到系统动画时间的延迟,就像我在之前提出的建议中讨论的那样,所以您需要解决在 Android 4.3 上遇到的同样问题。


是的,我已经尝试了onPageFinished方法(你忘记将WebViewClient附加到WebView上了,对吧?)。但问题仍然存在。现在,即使使用WindowManager.LayoutParams.FILL_PARENT,Entry动画也根本不起作用,除非把它放在WebViewClient内部。请看一下我的原帖EDIT,看看唯一能让动画工作的东西(但仍然只能使用WindowManager.LayoutParams.FILL_PARENT并且仍然是异步的)。有没有办法先禁用默认动画呢? - Luis A. Florit
实际上,在执行对话框操作后,LogCat 在末尾显示两行:WebView(17458): onSizeChanged - w:582 h:0WebView(17458): onSizeChanged - w:582 h:708。那么为什么它的高度从 0 开始,但宽度不为零呢? - Luis A. Florit
啊,是的,我忘记复制将WebViewClient附加到WebView的代码了,因为我正在使用自己的代码。在我的代码中,我实际上是使用一个XML布局,其中WebView的layout_width设置为FILL_PARENT,height设置为WRAP_CONTENT,所以我不必在代码中设置它。你能试着做同样的事情吗?当你设置对话框动画时,应该会替换默认动画。 - user2647899
关于对话框宽度从非零开始而高度为零,我认为这是因为对话框随内容长度垂直增长的原因。 - user2647899
或者,在onPageFinished内部,如果您不想将布局放在XML文件中,则可以尝试在布局设置完成后调用show - user2647899
再次感谢您的时间和建议。我尝试了所有方法(请查看新的编辑内容):(1)使用XML仍然存在相同的问题,即使是对话框而不是AlertDialog。(2)我之前也尝试在onPageFinished中放置dialog.show,但是我得到了相同的错误行为,现在还增加了一个问题,即当方向改变时,对话框会崩溃,因为这个原因:https://dev59.com/inNA5IYBdhLWcg3wC5Th - Luis A. Florit

0

我有一个类似的问题,但与其加入动画,我想要禁用它,因为它正在干扰我的带有WebView的对话框的明显加载时间。实际上,我已经成功禁用了主窗口的进入/退出动画,因为它不再淡入/淡出,但问题在于WebView的内容大部分时间被对话框的滑动动画延迟,我也正在尝试禁用它(我真的以为如果你禁用了窗口动画,所有动画都应该被禁用)。

根据我的测试,这实际上是一个Jellybean(安卓 4.1-4.3版本)的bug,但在Android 4.3中最为明显,这个额外的动画正在破坏我的弹出窗口。虽然在ICS中没有问题。

如果您尝试通过Android设置->开发人员选项->窗口动画缩放来增加默认动画时间,比如说到5或者10,您会注意到内容现在更加延迟显示。但是如果您关闭动画,显示就会很快。我相信如果默认动画被禁用,您的动画也可以工作。

我认为这种行为是一个Jellybean(安卓 4.1-4.3版本)的bug,只有当您在对话框中使用WebView时才会出现。对话框在增加高度时即使应该已经禁用滑动,仍然会将WebView内容放置在动画时间之后。

我尝试的另一种解决方案是缓存对话框,以便可以重复使用。我的问题得到了解决,但有时它无法正确调整大小以适应实际的HTML内容。如果您的内容在显示时长度大致相同,那么您可能只需缓存对话框即可。

希望我给你提供了很多线索。


我在ICS和JB中遇到了同样的问题,所以这不是JB的问题。关于您的答案还有两个问题:如何禁用默认动画?如何缓存我的webview?我遇到的一些奇怪行为是,如果我设置dialog.getWindow().setLayout(WindowManager.LayoutParams.FILL_PARENT, WindowManager.LayoutParams.FILL_PARENT),那么动画就可以正常执行。但是使用WRAP_CONTENT则不行。非常感谢您抽出时间写下详细的答案。 - Luis A. Florit
我遇到的另一个问题是,即使使用WindowManager.LayoutParams.FILL_PARENT,WebView内容也会在动画结束后(0.15秒)加载,除非我要求长时间的动画时间(0.5秒)。 - Luis A. Florit
我已经在实际设备上进行了额外的测试,并发现我所讨论的行为仅存在于Android 4.3中(我以前对Jelly Bean旧版本的测试仅针对非常慢的模拟器)。如果您在ICS和JB中使用动画时也出现了这种行为,则可能是另一个问题。 - user2647899

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