【问题标题】:An easy way to make GONE animation work制作 GONE 动画的简单方法
【发布时间】:2014-08-14 02:06:41
【问题描述】:

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

<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:我添加了动画资源并将它们附加到 @id/layoutSearch 中,使用 XML 中的这一行:

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 动画有点简单?

【问题讨论】:

    标签: android animation


    【解决方案1】:

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

    请注意,在动画中设置 setFillBeforesetFillAfter 会导致以下错误! 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>
    

    【讨论】:

    • 您能告诉我您何时/何时调用函数 hideControlOverlays() 和 showControlOverlays() 吗?我正在尝试开发类似的东西。您的回答将非常有帮助。谢谢
    • 您可以从视图上的 onTouch 或 onClick 侦听器调用 showControlsOverlay() 方法。 hideControlsOverlay() 方法可以从另一个 onTouch 或 onClick 处理程序中调用,或者您可以设置一个延迟的可运行对象以在几秒钟后调用它以自动关闭覆盖,而无需用户交互。
    【解决方案2】:

    尝试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) {
        }
    
    }
    

    【讨论】:

    • 似乎没有更简单的方法可以使“出”动画工作。谢谢。
    • 我想知道您是否找到了一种方法来避免动画结束时出现烦人的闪光灯,因为视图已经消失了,视图再次显示出来。
    • 向 this 添加构造函数以将 View 作为参数是一种不必重复代码一百万次的好方法。然后你可以用 a.setAnimationListener(new MyAnimationListener(v)); 将它应用到你想要的任何东西上。 ,当然,只要每个动画只绑定到一个视图。
    【解决方案3】:

    播放后需要调用Animation Class的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();
    

    【讨论】:

      【解决方案4】:

      将视图设置为GONE 可以有效地将其从布局中移除。相反,您应该将其设置为INVISIBLE,然后根据需要在动画完成后设置GONE

      【讨论】:

      • 感谢您的回答。我试图设置 INVISIBLE。看来,这样做是没有意义的。仍然需要在代码中设置布局动画和监听器。动画从 setLayoutAnimation() 开始,无需设置 INVISIBLE。这对我来说很奇怪,因为“in”动画不需要一行代码......
      • 这种方式适用于 View 显示或隐藏,我认为 ViewGroup 效果不佳,但感谢 Joseph-Earl 提供。
      猜你喜欢
      • 1970-01-01
      • 2022-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多