使用向上/向下滑动动画显示和隐藏视图

Mic*_*eap 287 animation android android-animation

我有一个LinearLayout我希望显示或隐藏的内容Animation,只要我改变其可见性,就会向上或向下推动布局.

我在那里看到了一些样品,但它们都不适合我的需要.

我为动画创建了两个xml文件,但是当我更改a的可见性时,我不知道如何启动它们LinearLayout.

Xav*_*ler 609

使用Android 3.0(Honeycomb)中引入的新动画API,创建此类动画非常简单.

View向下滑动一段距离:

view.animate().translationY(distance);
Run Code Online (Sandbox Code Playgroud)

您可以稍后将View其滑回原位,如下所示:

view.animate().translationY(0);
Run Code Online (Sandbox Code Playgroud)

您还可以轻松组合多个动画.以下动画将View向下滑动其高度并同时淡入其中:

// Prepare the View for the animation
view.setVisibility(View.VISIBLE);
view.setAlpha(0.0f);

// Start the animation
view.animate()
    .translationY(view.getHeight())
    .alpha(1.0f)
    .setListener(null);
Run Code Online (Sandbox Code Playgroud)

然后,您可以淡出View后退并将其滑回原始位置.我们还设置了一个动画完成后AnimatorListener我们可以设置View背面的可见性GONE:

view.animate()
    .translationY(0)
    .alpha(0.0f)
    .setListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            super.onAnimationEnd(animation);
            view.setVisibility(View.GONE);
        }
    });
Run Code Online (Sandbox Code Playgroud)

  • @XaverKapeller我认为很多问题是每次为多次出现的动画调用监听器`onAnimationEnd`,这意味着当显示视图时也会调用`onAnimationEnd`,这会将其可见性设置为Gone等. (11认同)
  • @Ram当你的可见性设置为`View.GONE`时,你想通过动画"View"来实现什么?如果将其可见性设置为除"View.VISIBLE"之外的任何内容,则"视图"将不可见.我不明白你在问什么.如果您希望动画可见,则不要将"View"的可见性设置为"View.GONE". (3认同)
  • 为什么视图消失后不可见? (2认同)
  • 面对相同的问题,Ram面临的问题是,第一次工作正常,但是从下一次开始,当我使该视图处于消失状态并尝试再次使该视图可见时,它就不会出现。 (2认同)

Sur*_*gch 109

我在理解应用已接受的答案时遇到了麻烦.我需要更多的背景.现在我已经弄明白了,这是一个完整的例子:

在此输入图像描述

MainActivity.java

public class MainActivity extends AppCompatActivity {

    Button myButton;
    View myView;
    boolean isUp;

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

        myView = findViewById(R.id.my_view);
        myButton = findViewById(R.id.my_button);

        // initialize as invisible (could also do in xml)
        myView.setVisibility(View.INVISIBLE);
        myButton.setText("Slide up");
        isUp = false;
    }

    // slide the view from below itself to the current position
    public void slideUp(View view){
        view.setVisibility(View.VISIBLE);
        TranslateAnimation animate = new TranslateAnimation(
                0,                 // fromXDelta
                0,                 // toXDelta
                view.getHeight(),  // fromYDelta
                0);                // toYDelta
        animate.setDuration(500);
        animate.setFillAfter(true);
        view.startAnimation(animate);
    }

    // slide the view from its current position to below itself
    public void slideDown(View view){
        TranslateAnimation animate = new TranslateAnimation(
                0,                 // fromXDelta
                0,                 // toXDelta
                0,                 // fromYDelta
                view.getHeight()); // toYDelta
        animate.setDuration(500);
        animate.setFillAfter(true);
        view.startAnimation(animate);
    }

    public void onSlideViewButtonClick(View view) {
        if (isUp) {
            slideDown(myView);
            myButton.setText("Slide up");
        } else {
            slideUp(myView);
            myButton.setText("Slide down");
        }
        isUp = !isUp;
    }
}
Run Code Online (Sandbox Code Playgroud)

activity_mail.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.slideview.MainActivity">

    <Button
        android:id="@+id/my_button"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="100dp"
        android:onClick="onSlideViewButtonClick"
        android:layout_width="150dp"
        android:layout_height="wrap_content"/>

    <LinearLayout
        android:id="@+id/my_view"
        android:background="#a6e1aa"
        android:orientation="vertical"
        android:layout_alignParentBottom="true"
        android:layout_width="match_parent"
        android:layout_height="200dp">

    </LinearLayout>

</RelativeLayout>
Run Code Online (Sandbox Code Playgroud)

笔记

  • 感谢这篇文章指出我正确的方向.它比本页面上的其他答案更有帮助.
  • 如果要从屏幕上的视图开始,则不要将其初始化为INVISIBLE.
  • 由于我们完全在屏幕上制作动画,因此无需将其设置为INVISIBLE.但是,如果您没有完全关闭屏幕动画,则可以添加Alpha动画并使用AnimatorListenerAdapter.
  • 属性动画文档

  • 我不建议使用animate.setFillAfter(true); 如果在滑动视图下有可单击的视图,则不会接收事件 (2认同)
  • 请注意,没有`.setVisibility(View.INVISIBLE);`滑动功能将无法按预期工作. (2认同)

Ste*_*ack 23

最简单的解决方案:设置android:animateLayoutChanges="true"容器上的视图.

将其置于某些上下文中:如果您具有如下所示的布局,则将自动为此容器中的视图的所有可见性更改进行动画处理.

<LinearLayout android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:animateLayoutChanges="true"
    >

    <Views_which_change_visibility>

</LinearLayout>
Run Code Online (Sandbox Code Playgroud)

您可以在Animating Layout Changes - Android Developer上找到有关此内容的更多详细信息


小智 11

通过创建新的子类并重写以启动更改Animation,可以在LinearLayout更改的可见性时启动正确的.考虑这样的事情:LinearLayoutsetVisibility()Animations

public class SimpleViewAnimator extends LinearLayout
{
    private Animation inAnimation;
    private Animation outAnimation;

    public SimpleViewAnimator(Context context)
    {
        super(context);
    }

    public void setInAnimation(Animation inAnimation)
    {
        this.inAnimation = inAnimation;
    }

    public void setOutAnimation(Animation outAnimation)
    {
        this.outAnimation = outAnimation;
    }

    @Override
    public void setVisibility(int visibility)
    {
        if (getVisibility() != visibility)
        {
            if (visibility == VISIBLE)
            {
                if (inAnimation != null) startAnimation(inAnimation);
            }
            else if ((visibility == INVISIBLE) || (visibility == GONE))
            {
                if (outAnimation != null) startAnimation(outAnimation);
            }
        }

        super.setVisibility(visibility);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @BramVandenbussche这是一个糟糕的解决方案.它使`View`负责自己的动画,这绝不是你想要的**.想象一下,你想在应用程序的另一部分以不同的方式为"视图"设置动画.那你怎么办呢?添加标志不会自动为可见性设置动画?子类`View`并覆盖`setVisibility()`来删除动画?或者更糟糕的是用另一个动画实现`setVisibility()`?它从那里变得更加丑陋和丑陋.不要使用这个"解决方案". (12认同)
  • 最好称之为AnimatedLinearLayout (3认同)

ash*_*rov 11

现在,应该通过Transition API支持(androidx)包中的可用动画来完成可见性更改动画。只需使用Slide transition 调用TransitionManager.beginDelayedTransition方法,然后更改视图的可见性即可。

在此处输入图片说明

import androidx.transition.Slide;
import androidx.transition.Transition;
import androidx.transition.TransitionManager;

private void toggle() {
    View redLayout = findViewById(R.id.redLayout);
    ViewGroup parent = findViewById(R.id.parent);

    Transition transition = new Slide(Gravity.BOTTOM);
    transition.setDuration(600);
    transition.addTarget(R.id.redLayout);

    TransitionManager.beginDelayedTransition(parent, transition);
    redLayout.setVisibility(show ? View.VISIBLE : View.GONE);
}
Run Code Online (Sandbox Code Playgroud)

activity_main.xml

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

    <Button
        android:id="@+id/btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="play" />

    <LinearLayout
        android:id="@+id/redLayout"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:background="#5f00"
        android:layout_alignParentBottom="true" />
</RelativeLayout>
Run Code Online (Sandbox Code Playgroud)

使用另一个默认和自定义过渡示例来检查此答案

  • 最好、最简单的答案之一!谢谢! (2认同)
  • @lasec0203 不,类来自“androidx”包。它在 21 之前的 api 上运行良好。 (2认同)

Ame*_*een 9

if (filter_section.getVisibility() == View.GONE) {
    filter_section.animate()
            .translationY(filter_section.getHeight()).alpha(1.0f)
            .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationStart(Animator animation) {
                    super.onAnimationStart(animation);
                    filter_section.setVisibility(View.VISIBLE);
                    filter_section.setAlpha(0.0f);
                }
            });
} else {
    filter_section.animate()
            .translationY(0).alpha(0.0f)
            .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    filter_section.setVisibility(View.GONE);
                }
            });
}
Run Code Online (Sandbox Code Playgroud)

  • 这个答案的问题:1)可怕的代码格式.2)您使用代码段发布实际上无法在浏览器中运行的代码.这不只是添加两个无用的按钮,但它也会破坏语法高亮.3)这只是一些随机代码转储,没有任何解释或目的.4)您正在执行动画时更改可见性.除了这是明显的代码味道这一事实也将无法正常工作.更改可见性会启动新的布局过程,只有在完成后,动画才会实际具有要使用的值.名单不断...... (10认同)

Đor*_*vić 8

科特林

根据Suragch回答,这是一种使用View扩展的优雅方式:

fun View.slideUp(duration: Int = 500) {
    visibility = View.VISIBLE
    val animate = TranslateAnimation(0f, 0f, this.height.toFloat(), 0f)
    animate.duration = duration.toLong()
    animate.fillAfter = true
    this.startAnimation(animate)
}

fun View.slideDown(duration: Int = 500) {
    visibility = View.VISIBLE
    val animate = TranslateAnimation(0f, 0f, 0f, this.height.toFloat())
    animate.duration = duration.toLong()
    animate.fillAfter = true
    this.startAnimation(animate)
}
Run Code Online (Sandbox Code Playgroud)

然后,无论你想在哪里使用它,你只需要myView.slideUp()myView.slideDown()


var*_*jsi 5

您可以在 android 应用程序中使用波纹管代码上下滑动任何视图或布局

boolean isClicked = false;
LinearLayout mLayoutTab = (LinearLayout) findViewById(R.id.linearlayout);

if(isClicked) {
    isClicked = false;
    mLayoutTab.animate()
        .translationYBy(120)
        .translationY(0)     
        .setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime));
} else {
    isClicked = true;
    mLayoutTab.animate()
         .translationYBy(0)
         .translationY(120)
         .setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime));
}
Run Code Online (Sandbox Code Playgroud)


Vih*_*rma 5

使用 ObjectAnimator

private fun slideDown(view: View) {
    val height = view.height
    ObjectAnimator.ofFloat(view, "translationY", 0.toFloat(), height.toFloat()).apply {
        duration = 1000
        start()
    }
}

private fun slideUp(view: View) {
    val height = view.height
    ObjectAnimator.ofFloat(view, "translationY", height.toFloat(),0.toFloat()).apply {
        duration = 1000
        start()
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 小改进:我们可以使用常量 View.TRANSLATION_Y 代替“translationY”,并且在向上滑动的 ObjectAnimation 中我们可以执行 .apply { doOnEnd { view.visibility = View.GONE } .......}.start() (4认同)