Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

hardware accelerated webview slide-in animation flickering on ICS

Tags:

java

android

Our application makes heavy use of webviews. When testing on ICS, we noticed that we need to set the application property hardwareAccelerated="true". However, doing this caused a few other bugs in our application, most of which we have fixed. We are still having problems getting our 'slide-in' animation working. Without any code changes, the animation simply does a 'reveal' type animation rather than sliding. We have tries a few different things:

  1. Adding a small alpha transition (.99->1). This changes the 'reveal' to a 'slide' but causes some weird artifacts on the screen sometimes.
  2. using hardware layers during the animation. This doesn't work consistently.
  3. using software layers during the animation. This works, but causes a slow redraw after the slide-in animation completes for the first time.

Approach 3 is the most promising, but we have not figured out how to avoid the redraw. We have created a small test case using a sample project with a single activity:

activity class:

    int accelValue = View.LAYER_TYPE_NONE; //hack

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    addClickListenerAnimation(R.id.buttonhl, R.anim.to_left, View.VISIBLE, View.INVISIBLE);
    addClickListenerAnimation(R.id.buttonhr, R.anim.to_right, View.VISIBLE, View.INVISIBLE);
    addClickListenerAnimation(R.id.buttonsl, R.anim.from_left, View.INVISIBLE, View.VISIBLE);
    addClickListenerAnimation(R.id.buttonsr, R.anim.from_right, View.INVISIBLE, View.VISIBLE);

    final Button b = (Button) findViewById(R.id.accel);
    b.setOnClickListener(
                         new View.OnClickListener()
                        {
                            @Override
                            public void onClick(View v)
                            {
                                accelValue = ++accelValue % 3;
                                b.setText(accelValue == 0 ? "NONE" : accelValue == 1 ? "S/W" : "H/W");
                            }
                        });

}

private void addClickListenerAnimation(int buttonId, final int animId, final int startVis, final int endVis)
{
    Button b = (Button) findViewById(buttonId);
    b.setOnClickListener(
     new View.OnClickListener()
    {

        @Override
        public void onClick(View v)
        {
            final WebView wv = (WebView) findViewById(R.id.webview);
            final View layout = findViewById(R.id.frame);
            Animation a = AnimationUtils.loadAnimation(getApplicationContext(), animId);

            a.setDuration(500);

            a.setAnimationListener(new AnimationListener()
            {

                @Override
                public void onAnimationStart(Animation animation)
                {
                    Log.i("sb", "layer type was " + wv.getLayerType());
                    Log.i("sb", "llayout layer type was " + layout.getLayerType());
                    wv.setLayerType(accelValue, null);
                    Log.i("sb", "setting layer type " + accelValue);
                }

                @Override
                public void onAnimationRepeat(Animation animation)
                {
                }

                @Override
                public void onAnimationEnd(Animation animation)
                {
                    wv.setLayerType(View.LAYER_TYPE_NONE, null);
                    Log.i("sb", "restoring layout layer type " + layout.getLayerType());
                }
            });

            layout.setAnimation(a);
            layout.setVisibility(endVis);
        }
    });
}

@Override
protected void onStart()
{
    super.onStart();
    ((WebView)findViewById(R.id.webview)).loadUrl("http://www.wikipedia.org");
}

from_left.xml animation (other animation xmls are similar):

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="true">
    <translate  android:fromXDelta="-100%" 
                android:toXDelta="0%" 
                android:fromYDelta="0%"
                android:toYDelta="0%" 
                android:duration="600" 
                android:zAdjustment="bottom" 
                />
</set>

main.xml:

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

<FrameLayout 
            android:id="@+id/frame"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:visibility="invisible"
    >
        <WebView
            android:id="@+id/webview"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"/>
</FrameLayout>
    <View
        android:layout_width="fill_parent"
        android:layout_height="80dp"
        android:background="#FF000000" />

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="80dp"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/buttonsl"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:text="show L" />

        <Button
            android:id="@+id/buttonhl"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:text="hide L" />

        <Button
            android:id="@+id/buttonsr"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:text="show R" />

        <Button
            android:id="@+id/buttonhr"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:text="hide R" />

        <Button
            android:id="@+id/accel"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:text="NONE" />
    </LinearLayout>

</LinearLayout>

manifest:

<uses-sdk android:minSdkVersion="14" />
<uses-permission android:name="android.permission.INTERNET" />
like image 374
slushi Avatar asked Dec 28 '22 06:12

slushi


1 Answers

Well, if you are trying to support ICS and onward, you can use the new Animation APIs as they are much easier to use and I believe will be very smooth.

Here are two links to take a look into this API:

this and this

And if you want to use this API for older versions, try NineOldAndroids

Edit: Try setting the WebView's Layer to a Software one:

    web.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

It stopped the flickering but you lose hardware acceleration inside the view. I am not sure but I guess that for stuff like animation the view would still be considered as having hardware acceleration since its "container" still does. But I could be completely wrong too.

like image 86
Beowulf Bjornson Avatar answered Feb 01 '23 13:02

Beowulf Bjornson