使用向上/向下滑动动画显示和隐藏视图
Posted
技术标签:
【中文标题】使用向上/向下滑动动画显示和隐藏视图【英文标题】:Show and hide a View with a slide up/down animation 【发布时间】:2013-11-14 23:11:32 【问题描述】:我有一个LinearLayout
,我想用Animation
显示或隐藏它,只要我改变它的可见性,它就会向上或向下推动布局。
我已经看过一些样品,但没有一个适合我的需要。
我已经为动画创建了两个 xml 文件,但是当我更改 LinearLayout
的可见性时,我不知道如何启动它们。
【问题讨论】:
【参考方案1】:使用 android 3.0 (Honeycomb) 中引入的新动画 API,创建此类动画非常简单。
将View
向下滑动一段距离:
view.animate().translationY(distance);
您可以稍后将View
滑回其原始位置,如下所示:
view.animate().translationY(0);
您还可以轻松组合多个动画。以下动画将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);
然后您可以淡出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);
);
【讨论】:
为什么视图消失后不可见? 我想在可见和消失时为视图设置动画。但如果我第一次去查看。它无法看到并且查看位置是空白的 @Ram 当View
的可见性设置为 View.GONE
时,你想通过动画实现什么?如果您将其可见性设置为除View.VISIBLE
之外的任何内容,则View
将不可见。我不明白你在问什么。如果您希望您的动画可见,请不要将 View
的可见性设置为 View.GONE
。
面临与 Ram 相同的问题,第一次它工作正常,但从下一次当我使该视图处于消失状态并尝试使该视图再次可见时,它不会出现。跨度>
@XaverKapeller 我认为很多人遇到的问题是每次多次出现的动画都会调用监听器onAnimationEnd
,这意味着在显示视图时也会调用onAnimationEnd
,这将其可见性设置为 Gone 等。【参考方案2】:
我在理解应用接受的答案时遇到了麻烦。我需要更多的上下文。现在我已经弄清楚了,这是一个完整的例子:
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;
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_
android:layout_
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_
android:layout_/>
<LinearLayout
android:id="@+id/my_view"
android:background="#a6e1aa"
android:orientation="vertical"
android:layout_alignParentBottom="true"
android:layout_
android:layout_>
</LinearLayout>
</RelativeLayout>
注意事项
感谢this article 为我指明了正确的方向。它比此页面上的其他答案更有帮助。 如果要从屏幕上的视图开始,请不要将其初始化为INVISIBLE
。
由于我们将动画完全移出屏幕,因此无需将其设置回INVISIBLE
。但是,如果您的动画没有完全脱离屏幕,那么您可以添加一个 alpha 动画并使用 AnimatorListenerAdapter
设置可见性。
Property Animation docs
【讨论】:
android:visibility="invisible" 将视图动画初始化为隐藏 我不推荐使用 animate.setFillAfter(true);如果您在滑动视图下有可点击的视图,它将不会接收事件 请注意,如果没有.setVisibility(View.INVISIBLE);
,上滑功能将无法按视觉预期工作。
Translate Animation
移动视图。如果您想像缩放本身一样为视图设置动画,请使用ScaleAnimation anim = new ScaleAnimation(1, 1, 0, 1)
请注意,TranslateAnimation
不会移动可点击对象,如果它们出现在您的视图中。它只会移动像素。在大多数情况下,这可能是意料之外的。参考这个来移动可点击的东西:***.com/a/34631361/5353128【参考方案3】:
现在可见性更改动画应通过支持 (androidx) 包中的Transition API
完成。只需使用Slide 转换调用TransitionManager.beginDelayedTransition 方法,然后更改视图的可见性。
import androidx.transition.Slide;
import androidx.transition.Transition;
import androidx.transition.TransitionManager;
private void toggle(boolean show)
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);
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_
android:layout_
android:orientation="vertical">
<Button
android:id="@+id/btn"
android:layout_
android:layout_
android:text="play" />
<LinearLayout
android:id="@+id/redLayout"
android:layout_
android:layout_
android:background="#5f00"
android:layout_alignParentBottom="true" />
</RelativeLayout>
检查this answer 与另一个默认和自定义转换示例。
【讨论】:
@akubi 是的,应该是 最好和最简单的答案之一!谢谢! 请注意,这需要minSdkVersion 21
@lasec0203 不,课程来自androidx
包。它在 pre 21 api 上运行良好。
:thumbs_up: 这消除了我遇到的方法歧义错误【参考方案4】:
最简单的解决方案:在保存视图的容器上设置android:animateLayoutChanges="true"
。
把它放到一些上下文中:如果你有一个像下面这样的布局,这个容器中视图的所有可见性变化都会自动动画。
<LinearLayout android:id="@+id/container"
android:layout_
android:layout_
android:animateLayoutChanges="true"
>
<Views_which_change_visibility>
</LinearLayout>
您可以在Animating Layout Changes - Android Developer找到更多详细信息
【讨论】:
这是最简单的,但它的行为因手机制造商和他的代码更改而异 这会为 alpha 设置动画,而不是位置。 是的,但如果我理解正确的话,这就是最初的问题。如果您想为位置设置动画,可以使用 RecyclerView,它使用具有稳定 ID 的 ViewHolders。 如果它在嵌套视图中不起作用,请参阅此答案***.com/a/59649918/6039240【参考方案5】:科特林
基于Suragch的answer,这里是一个使用视图扩展的优雅方式:
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)
然后无论你想在哪里使用它,你只需要myView.slideUp()
或myView.slideDown()
【讨论】:
唯一的错误是,它不需要“fillAfter=true”,因为它会阻止子视图点击可访问性 另外,您可能需要为 slideDown 动画添加一个侦听器,并使视图在动画结束时消失。【参考方案6】:当LinearLayout
的可见性发生变化时,您可以通过创建LinearLayout
的新子类并覆盖setVisibility()
以启动Animations
来启动正确的Animation
。考虑这样的事情:
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);
【讨论】:
我实际上更喜欢子类方法。非常感谢。 这是一个很棒的解决方案,我将在我的 BaseView 中实施。谢谢! 因为这在显示时有效,在隐藏时,视图会在动画可见之前消失。有什么解决方法吗? @BramVandenbussche 这是一个糟糕的解决方案。它使View
负责它自己的动画,这是您想要的NEVER。想象一下,您想在应用程序的另一部分以不同方式为 View
设置动画。那你怎么办呢?添加标志以不自动为可见性设置动画?继承View
并覆盖setVisibility()
以删除动画?或者更糟糕的是用另一个动画实现setVisibility()
?它只是从那里变得越来越丑陋。不要使用这种“解决方案”。
最好叫它AnimatedLinearLayout【参考方案7】:
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);
);
【讨论】:
这个答案的问题:1)糟糕的代码格式。 2)您使用代码 sn-p 发布实际上无法在浏览器中运行的代码。这不仅添加了两个无用的按钮,而且还破坏了语法高亮。 3)这只是一些随机代码转储,没有任何解释或目的。 4) 您在执行动画时正在更改可见性。除了这是明显的代码气味之外,这也将无法正常工作。改变可见性会开始一个新的布局过程,只有在完成之后,动画才真正具有可使用的值。名单还在继续…… 我已经编辑了您的答案以修复格式并将代码 sn-p 转换为实际的代码块。但是你必须填写其余的...... 对不起,伙计,我从你的代码中编写了代码,因为它对我来说效果不佳,我的这个代码有效。但我同意发布方式需要更改。 @AmeenMaheensetAlpha
是干什么用的?
@Igor Ganapolsky 它用于透明度,即产生褪色效果【参考方案8】:
您可以在 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));
【讨论】:
什么是 120?什么是 0?如果我想硬编码,setDuration 的单位是什么? 这里 120 和 0 是与 Y 轴相关的距离,如果您放置硬代码而不是在大屏幕或平板电脑中遇到问题,因此,您需要为所有不同的设备输入 string.xml 值中的值.持续时间是您要显示布局动画的时间....!!!对不起我的英语不好......! @varotariyavajsi 这实际上并没有显示/隐藏视图的可见性。 你好 igor ganapolsky 我知道这些......它只是在 y 方向上平移视图,如果用户需要像底部滑块一样上下显示它会正常工作。【参考方案9】:使用 ObjectAnimator
private fun slideDown(view: View)
val height = view.height
ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, 0f, height.toFloat()).apply
duration = 1000
start()
private fun slideUp(view: View)
val height = view.height
ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, height.toFloat(), 0f)).apply
duration = 1000
start()
【讨论】:
小改进:我们可以使用常量 View.TRANSLATION_Y 代替“translationY”,并且在上滑 ObjectAnimation 中我们可以执行 .apply doOnEnd view.visibility = View.GONE .... ....start()0.toFloat()
也可以是0f
【参考方案10】:
使用这个类:
public class ExpandCollapseExtention
public static void expand(View view)
view.setVisibility(View.VISIBLE);
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
view.measure(widthSpec, heightSpec);
ValueAnimator mAnimator = slideAnimator(view, 0, view.getMeasuredHeight());
mAnimator.start();
public static void collapse(final View view)
int finalHeight = view.getHeight();
ValueAnimator mAnimator = slideAnimator(view, finalHeight, 0);
mAnimator.addListener(new Animator.AnimatorListener()
@Override
public void onAnimationEnd(Animator animator)
view.setVisibility(View.GONE);
@Override
public void onAnimationStart(Animator animation)
@Override
public void onAnimationCancel(Animator animation)
@Override
public void onAnimationRepeat(Animator animation)
);
mAnimator.start();
private static ValueAnimator slideAnimator(final View v, int start, int end)
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator)
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
layoutParams.height = value;
v.setLayoutParams(layoutParams);
);
return animator;
【讨论】:
【参考方案11】:你可以用简单的三行代码来展示动画...
//getting the hiding view by animation
mbinding.butn.setOnClickListener
val SlideOutLeft = AnimationUtils.loadAnimation(this, R.anim.slide_out_left)
simplelayout.visibility = View.INVISIBLE
simplelayout.startAnimation(SlideOutLeft)
val SlideInRight = AnimationUtils.loadAnimation(applicationContext, R.anim.slide_in_right)
animation1.visibility = View.VISIBLE
animation1.startAnimation(SlideInRight)
//again unhide the view animation
mbinding.buttn.setOnClickListener
val SlideInLeft=AnimationUtils.loadAnimation(this,R.anim.slide_in_left)
//set the layout
simplelayout.visibility=View.VISIBLE
simplelayout.startAnimation(SlideInLeft)
val SlideOutRight=AnimationUtils.loadAnimation(this,R.anim.slide_out_right)
animation1.visibility=View.INVISIBLE
animation1.startAnimation(SlideOutRight)
【讨论】:
【参考方案12】:有了 Kotlin 扩展,你可以这样使用:
enum class SlideDirection
UP,
DOWN,
LEFT,
RIGHT
enum class SlideType
SHOW,
HIDE
fun View.slideAnimation(direction: SlideDirection, type: SlideType, duration: Long = 250)
val fromX: Float
val toX: Float
val fromY: Float
val toY: Float
val array = IntArray(2)
getLocationInWindow(array)
if((type == SlideType.HIDE && (direction == SlideDirection.RIGHT || direction == SlideDirection.DOWN)) ||
(type == SlideType.SHOW && (direction == SlideDirection.LEFT || direction == SlideDirection.UP)) )
val displayMetrics = DisplayMetrics()
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
windowManager.defaultDisplay.getMetrics(displayMetrics)
val deviceWidth = displayMetrics.widthPixels
val deviceHeight = displayMetrics.heightPixels
array[0] = deviceWidth
array[1] = deviceHeight
when (direction)
SlideDirection.UP ->
fromX = 0f
toX = 0f
fromY = if(type == SlideType.HIDE) 0f else (array[1] + height).toFloat()
toY = if(type == SlideType.HIDE) -1f * (array[1] + height) else 0f
SlideDirection.DOWN ->
fromX = 0f
toX = 0f
fromY = if(type == SlideType.HIDE) 0f else -1f * (array[1] + height)
toY = if(type == SlideType.HIDE) 1f * (array[1] + height) else 0f
SlideDirection.LEFT ->
fromX = if(type == SlideType.HIDE) 0f else 1f * (array[0] + width)
toX = if(type == SlideType.HIDE) -1f * (array[0] + width) else 0f
fromY = 0f
toY = 0f
SlideDirection.RIGHT ->
fromX = if(type == SlideType.HIDE) 0f else -1f * (array[0] + width)
toX = if(type == SlideType.HIDE) 1f * (array[0] + width) else 0f
fromY = 0f
toY = 0f
val animate = TranslateAnimation(
fromX,
toX,
fromY,
toY
)
animate.duration = duration
animate.setAnimationListener(object: Animation.AnimationListener
override fun onAnimationRepeat(animation: Animation?)
override fun onAnimationEnd(animation: Animation?)
if(type == SlideType.HIDE)
visibility = View.INVISIBLE
override fun onAnimationStart(animation: Animation?)
visibility = View.VISIBLE
)
startAnimation(animate)
扩展示例:
view.slideAnimation(SlideDirection.UP, SlideType.HIDE)//to make it disappear through top of the screen
view.slideAnimation(SlideDirection.DOWN, SlideType.SHOW)//to make it reappear from top of the screen
view.slideAnimation(SlideDirection.DOWN, SlideType.HIDE)//to make it disappear through bottom of the screen
view.slideAnimation(SlideDirection.UP, SlideType.SHOW)//to make it reappear from bottom of the screen
【讨论】:
【参考方案13】:我有一个极端情况,我的视图高度仍然是 zero
所以...
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.view.View;
public final class AnimationUtils
public static void slideDown(final View view)
view.animate()
.translationY(view.getHeight())
.alpha(0.f)
.setListener(new AnimatorListenerAdapter()
@Override
public void onAnimationEnd(Animator animation)
// superfluous restoration
view.setVisibility(View.GONE);
view.setAlpha(1.f);
view.setTranslationY(0.f);
);
public static void slideUp(final View view)
view.setVisibility(View.VISIBLE);
view.setAlpha(0.f);
if (view.getHeight() > 0)
slideUpNow(view);
else
// wait till height is measured
view.post(new Runnable()
@Override
public void run()
slideUpNow(view);
);
private static void slideUpNow(final View view)
view.setTranslationY(view.getHeight());
view.animate()
.translationY(0)
.alpha(1.f)
.setListener(new AnimatorListenerAdapter()
@Override
public void onAnimationEnd(Animator animation)
view.setVisibility(View.VISIBLE);
view.setAlpha(1.f);
);
【讨论】:
【参考方案14】:这是我的解决方案。只需获取对您的视图的引用并调用此方法:
public static void animateViewFromBottomToTop(final View view)
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
@Override
public void onGlobalLayout()
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
final int TRANSLATION_Y = view.getHeight();
view.setTranslationY(TRANSLATION_Y);
view.setVisibility(View.GONE);
view.animate()
.translationYBy(-TRANSLATION_Y)
.setDuration(500)
.setStartDelay(200)
.setListener(new AnimatorListenerAdapter()
@Override
public void onAnimationStart(final Animator animation)
view.setVisibility(View.VISIBLE);
)
.start();
);
不需要做任何其他事情 =)
【讨论】:
为什么需要 GlobalLayoutListener 来执行此操作?你为什么要以这种奇怪的方式设置可见性?为什么要在答案中包含与问题无关的启动延迟之类的内容?【参考方案15】:Suragch 在 Kotlin 中的回答。这对我有用。
class MainActivity : AppCompatActivity()
var isUp: Boolean = false
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var myView: View = findViewById(R.id.my_view)
var myButton: Button = findViewById(R.id.my_button)
//Initialize as invisible
myView.visibility = View.INVISIBLE
myButton.setText("Slide up")
isUp = false
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)
fun onSlideViewButtonClick(view: View)
if(isUp)
my_view.slideDown()
my_button.setText("Slide Up")
else
my_view.slideUp()
my_button.setText("Slide Down")
isUp = !isUp
【讨论】:
【参考方案16】:一种简单的方法:
containerView.setLayoutTransition(LayoutTransition())
containerView.layoutTransition.enableTransitionType(LayoutTransition.CHANGING)
【讨论】:
【参考方案17】:这是处理多个Button
(在本例中为ImageView
)的另一种方法
MainActivity.java
findViewById(R.id.arrowIV).setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
if (strokeWidthIV.getAlpha() == 0f)
findViewById(R.id.arrowIV).animate().rotationBy(180);
strokeWidthIV.animate().translationXBy(-120 * 4).alpha(1f);
findViewById(R.id.colorChooseIV).animate().translationXBy(-120 * 3).alpha(1f);
findViewById(R.id.saveIV).animate().translationXBy(-120 * 2).alpha(1f);
findViewById(R.id.clearAllIV).animate().translationXBy(-120).alpha(1f);
else
findViewById(R.id.arrowIV).animate().rotationBy(180);
strokeWidthIV.animate().translationXBy(120 * 4).alpha(0f);
findViewById(R.id.colorChooseIV).animate().translationXBy(120 * 3).alpha(0f);
findViewById(R.id.saveIV).animate().translationXBy(120 * 2).alpha(0f);
findViewById(R.id.clearAllIV).animate().translationXBy(120).alpha(0f);
);
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
tools:context=".activity.MainActivity">
<ImageView
android:id="@+id/strokeWidthIV"
android:layout_
android:layout_
android:layout_margin="8dp"
android:alpha="0"
android:contentDescription="Clear All"
android:padding="4dp"
android:scaleType="fitXY"
android:src="@drawable/ic_edit"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText" />
<ImageView
android:id="@+id/colorChooseIV"
android:layout_
android:layout_
android:layout_margin="8dp"
android:alpha="0"
android:contentDescription="Clear All"
android:padding="4dp"
android:scaleType="fitXY"
android:src="@drawable/ic_palette"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText" />
<ImageView
android:id="@+id/saveIV"
android:layout_
android:layout_
android:layout_margin="8dp"
android:alpha="0"
android:contentDescription="Clear All"
android:padding="4dp"
android:scaleType="fitXY"
android:src="@drawable/ic_save"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText" />
<ImageView
android:id="@+id/clearAllIV"
android:layout_
android:layout_
android:layout_margin="8dp"
android:alpha="0"
android:contentDescription="Clear All"
android:padding="4dp"
android:scaleType="fitXY"
android:src="@drawable/ic_clear_all"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText" />
<ImageView
android:id="@+id/arrowIV"
android:layout_
android:layout_
android:layout_margin="8dp"
android:contentDescription="Arrow"
android:padding="4dp"
android:scaleType="fitXY"
android:src="@drawable/ic_arrow"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout>
【讨论】:
【参考方案18】:一个完整的答案,它可以在 onClick 中切换视图可见性,也可以将箭头倒置,并且在隐藏组件时也可以平滑地向上移动其他视图。
private fun toggleRecyclerViewVisibility(
recyclerView: RecyclerView,
container: FrameLayout,
arrow: ImageView
)
//toggle arrow direction, also block user clicks until animation finishes.
arrow
.animate()
.rotation(
if (arrow.rotation == 0F)
180F
else 0F
)
.withStartAction container.isClickable = false
.withEndAction container.isClickable = true
.start()
//toggle recyclerview visibility with animation.
with(recyclerView)
var cof = -1
var vis = View.GONE
var alph = 0F
if (visibility == View.GONE)
cof = 0
vis = View.VISIBLE
alph = 1F
animate()
.translationY(height.toFloat() * cof)
.alpha(alph)
.withStartAction //in case showing the recyclerview show it at the beginning.
if (vis == View.VISIBLE)
visibility = View.VISIBLE
.withEndAction //in case hiding the recyclerview hide it at the end.
if (vis == View.GONE)
visibility = View.GONE
.start()
视图看起来像这样
<LinearLayout
android:id="@+id/subRootLinearView"
android:animateLayoutChanges="true"
android:layout_
android:layout_
android:orientation="vertical">
<!--other views-->
<LinearLayout
android:id="@+id/Container"
android:layout_
android:layout_
android:orientation="vertical">
<FrameLayout
android:id="@+id/header"
android:layout_
android:layout_
android:background="@color/backgroundGray"
android:padding="16dp">
<TextView
android:id="@+id/text_view"
android:layout_
android:layout_
android:text="@string/awaitingConfirmation"
android:textColor="@color/colorText"
android:textSize="16sp" />
<ImageView
android:id="@+id/arrow_image_view"
android:layout_
android:layout_
android:layout_gravity="end|center"
android:src="@drawable/ic_arrow" />
</FrameLayout>
<LinearLayout
android:layout_
android:layout_
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_
android:layout_
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
</LinearLayout>
</LinearLayout>
<!--other views-->
</LinearLayout>
然后在你的代码中你首先添加这一行,这解决了animateLayoutChanges
not working in big nested views,这基本上使其他视图在隐藏recyclerview时平滑向上移动
subRootLinearView.layoutTransition.enableTransitionType(LayoutTransition.CHANGING)
你的父线性布局也应该包含这个属性
android:animateLayoutChanges="true"
然后用你的观点调用方法
toggleRecyclerViewVisibility(
recycler,
header,
arrowImageView
)
【讨论】:
【参考方案19】:来自 Kotlin 用户的ashakirov 的回答
val transition: Transition = Slide(Gravity.BOTTOM)
transition.duration = 600
transition.addTarget(you_parent_layout_id)
TransitionManager.beginDelayedTransition(rootLayoutId, transition)
yourViewIdToHide.visibility = if (yourViewIdToHide.isShown) View.GONE else View.VISIBLE
【讨论】:
以上是关于使用向上/向下滑动动画显示和隐藏视图的主要内容,如果未能解决你的问题,请参考以下文章