一个让GONE动画有效的简单方法

时间:2011-04-08 07:10:54

标签: android animation

我有一个自定义搜索面板,它是主要布局的一部分。大多数时候面板都是隐藏的。我想在面板中添加出现/消失的动画。这是简化的布局摘录:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <RelativeLayout
        android:id="@+id/layoutSearch"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:visibility="gone" >
        <EditText
            android:id="@+id/editSearch"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />
        <<Other inner views to be animated>>
    </RelativeLayout>
    <<Other views, which should not be affected by the animation>>
</LinearLayout>

尝试1 :我添加了动画资源,并使用XML格式的这一行将它们附加到@ id / layoutSearch:

android:layoutAnimation="@anim/search_in_layout"

动画/ search_in.xml:

<translate
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/overshoot_interpolator"
    android:fromYDelta="-100%p"
    android:toYDelta="0"
    android:duration="@android:integer/config_longAnimTime" />

动画/ search_in_layout.xml:

<layoutAnimation
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/search_in" />

动画效果很好,但仅适用于出现的面板。当我隐藏它时,面板会在没有动画的情况下消失:

mSearchLayout.setVisibility(View.GONE);

尝试2 :我猜上面的解决方案不起作用,因为动画目标参数与当前面板位置匹配。好的,我创建了两个动画资源:anim / search_out.xml和anim / search_out_layout.xml。唯一的区别是交换“fromYDelta”和“toYDelta”值并更新“android:animation”值。然后我在代码中加载资源并将它们设置为@ id / layoutSearch,如下所示:

LayoutAnimationController controller =
    AnimationUtils.loadLayoutAnimation(this, R.anim.search_out_layout);
mSearchLayout.setLayoutAnimation(controller);

调用setLayoutAnimation()时触发“out”动画。在动画之后,搜索面板返回到它在“out”动画之前的屏幕上的原始位置。如果我尝试在setLayoutAnimation()之后调用mSearchLayout.setVisibility(View.GONE),我看不到动画,面板立即消失。

试试3 :我想我需要在代码中创建动画,然后在其上设置一个监听器。然后我应该在onAnimationEnd()处理程序中调用mSearchLayout.setVisibility(View.GONE)以在播放动画后隐藏面板。我还没试过这个。我认为这太复杂了。

我想我错过了重要的事情。有没有办法实现GONE动画有点容易?

4 个答案:

答案 0 :(得分:7)

继续上面的答案:这是我如何解决这个问题。

请注意,在动画中设置 setFillBefore setFillAfter 会导致以下错误! Issue 5272: View with visibility View.GONE still generates touch events http://code.google.com/p/android/issues/detail?id=5272

文件: MyWebViewActivity.java

private View mBottomOverlay;
private View mTopOverlay;
private boolean mControlsOverlayVisible;
private Animation mSlideBottomUpAnimation;
private Animation mSlideBottomDownAnimation;
private Animation mSlideTopDownAnimation;
private Animation mSlideTopUpAnimation;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.reader_layout);

    // load the overlay resources
    mTopOverlay = findViewById(R.id.reader_overlay_top_toolbar);
    mBottomOverlay = findViewById(R.id.reader_overlay_bottom_toolbar);

    initAnimations();
}

private void initAnimations() {

    final AnimationListener makeTopGone = new AnimationListener() {

        @Override
        public void onAnimationStart(Animation animation) {}

        @Override
        public void onAnimationRepeat(Animation animation) {}

        @Override
        public void onAnimationEnd(Animation animation) {
            Log.d(TAG, "onAnimationEnd - makeTopGone");
            mTopOverlay.setVisibility(View.GONE);
        }
    };

    final AnimationListener makeBottomGone = new AnimationListener() {

        @Override
        public void onAnimationStart(Animation animation) {}

        @Override
        public void onAnimationRepeat(Animation animation) {
        }

        @Override
        public void onAnimationEnd(Animation animation) {
            Log.d(TAG, "onAnimationEnd - makeBottomGone");
            mBottomOverlay.setVisibility(View.GONE);
        }
    };

    final AnimationListener makeTopVisible = new AnimationListener() {

        @Override
        public void onAnimationStart(Animation animation) {
            Log.d(TAG, "onAnimationStart - makeTopVisible");
            mTopOverlay.setVisibility(View.VISIBLE);
        }

        @Override
        public void onAnimationRepeat(Animation animation) {}

        @Override
        public void onAnimationEnd(Animation animation) {}
    };

    final AnimationListener makeBottomVisible = new AnimationListener() {

        @Override
        public void onAnimationStart(Animation animation) {
            Log.d(TAG, "onAnimationStart - makeBottomVisible");
            mBottomOverlay.setVisibility(View.VISIBLE);
        }

        @Override
        public void onAnimationRepeat(Animation animation) {}

        @Override
        public void onAnimationEnd(Animation animation) {}
    };

    mSlideTopUpAnimation = AnimationUtils.loadAnimation(this, R.anim.slide_top_up);
    mSlideBottomDownAnimation = AnimationUtils.loadAnimation(this, R.anim.slide_bottom_down);
    mSlideTopUpAnimation.setAnimationListener(makeTopGone);
    mSlideBottomDownAnimation.setAnimationListener(makeBottomGone);

    mSlideTopDownAnimation = AnimationUtils.loadAnimation(this, R.anim.slide_top_down);
    mSlideBottomUpAnimation = AnimationUtils.loadAnimation(this, R.anim.slide_bottom_up);
    mSlideTopDownAnimation.setAnimationListener(makeTopVisible);
    mSlideBottomUpAnimation.setAnimationListener(makeBottomVisible);
}

private void hideControlOverlays() {
    Log.d(TAG, "hideControlOverlays");
    mTopOverlay.startAnimation(mSlideTopUpAnimation);
    mBottomOverlay.startAnimation(mSlideBottomDownAnimation);
    mControlsOverlayVisible = false;
}

private void showControlOverlays() {
    Log.d(TAG, "showControlOverlays");
    mTopOverlay.startAnimation(mSlideTopDownAnimation);
    mBottomOverlay.startAnimation(mSlideBottomUpAnimation);
    mControlsOverlayVisible = true;
}

文件: /res/layout/reader_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/reader_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <WebView
        android:id="@+id/webview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/reader_overlay_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <LinearLayout
            android:id="@+id/reader_overlay_top_toolbar"
            android:layout_width="fill_parent"
            android:layout_height="140dp"
            android:background="#80000000" >

            <include layout="@layout/toolbar_top" />
        </LinearLayout>

        <LinearLayout
            android:id="@+id/reader_overlay_bottom_toolbar"
            android:layout_width="fill_parent"
            android:layout_height="140dp"
            android:layout_gravity="bottom"
            android:background="#80000000"
            android:orientation="horizontal" >

            <include layout="@layout/toolbar_bottom_left" />
        </LinearLayout>
    </FrameLayout>
</FrameLayout>

文件: /res/anim/slide_bottom_down.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillEnabled="true"
    android:interpolator="@android:anim/accelerate_interpolator" >
    <translate
        android:duration="@android:integer/config_shortAnimTime"
        android:fromYDelta="0"
        android:toYDelta="100%" />
</set>

文件: /res/anim/slide_bottom_up.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator" >
    <translate
        android:duration="@android:integer/config_shortAnimTime"
        android:fromYDelta="100%"
        android:toYDelta="0" />
</set>

文件: /res/anim/slide_top_down.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator" >
    <translate
        android:duration="@android:integer/config_shortAnimTime"
        android:fromYDelta="-100%"
        android:toYDelta="0" />
</set>

文件: /res/anim/slide_top_up.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillEnabled="true"
    android:interpolator="@android:anim/accelerate_interpolator" >
    <translate
        android:duration="@android:integer/config_shortAnimTime"
        android:fromYDelta="0"
        android:toYDelta="-100%" />
</set>

答案 1 :(得分:4)

  

尝试3:我想我需要在代码中创建动画,然后在其上设置一个监听器。然后我应该在onAnimationEnd()处理程序中调用mSearchLayout.setVisibility(View.GONE)以在播放动画后隐藏面板。我还没试过这个。我认为这太复杂了。

这就是你应该做的事情,实际上并不难实现。

示例代码:

public class YourClass extends Foo implements AnimationListener {

    //...

    @Override
    public void onAnimationEnd(Animation a) {
        // Do stuff.
    }

    @Override
    public void onAnimationRepeat(Animation a) {    
    }

    @Override
    public void onAnimationStart(Animation a) {
    }

}

答案 2 :(得分:4)

你需要调用动画类的 setFillAfter()来播放后保存动画。

RelativeLayout layout = (RelativeLayout) findViewById(R.id.layoutSearch);
Animation a = AnimationUtils.loadAnimation(this, R.anim.push_down);
a=setFillAfter(true); 
layout.setLayoutAnimation(new LayoutAnimationController(a));
layout.startLayoutAnimation();

答案 3 :(得分:2)

将视图设置为GONE会有效地将其从布局中删除。相反,您应该在动画完成后将其设置为INVISIBLE,然后再设置为GONE