我有一个线性布局,我想显示或隐藏与动画,推动布局向上或向下每当我改变其可见性。
我在那里看过一些样品,但没有一个适合我的需要。
我已经为动画创建了两个xml文件,但我不知道当我改变线性布局的可见性时如何启动它们。
我有一个线性布局,我想显示或隐藏与动画,推动布局向上或向下每当我改变其可见性。
我在那里看过一些样品,但没有一个适合我的需要。
我已经为动画创建了两个xml文件,但我不知道当我改变线性布局的可见性时如何启动它们。
当前回答
当LinearLayout的可见性改变时,你可以通过创建LinearLayout的一个新的子类并覆盖setVisibility()来启动动画来启动正确的动画。考虑一下这样的事情:
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);
}
}
其他回答
现在可见性改变动画应该通过过渡API来完成,该API在支持(androidx)包中可用。只需调用TransitionManager。beginDelayedTransition方法使用Slide过渡,然后改变视图的可见性。
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_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>
用另一个默认和自定义转换示例检查这个答案。
一个完整的答案,在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_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!--other views-->
<LinearLayout
android:id="@+id/Container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<FrameLayout
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/backgroundGray"
android:padding="16dp">
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/awaitingConfirmation"
android:textColor="@color/colorText"
android:textSize="16sp" />
<ImageView
android:id="@+id/arrow_image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center"
android:src="@drawable/ic_arrow" />
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
</LinearLayout>
</LinearLayout>
<!--other views-->
</LinearLayout>
然后在代码中首先添加这一行,这解决了animateLayoutChanges在大嵌套视图中不工作的问题,这基本上使其他视图在隐藏recyclerview时平滑地向上移动
subRootLinearView.layoutTransition.enableTransitionType(LayoutTransition.CHANGING)
你的父线性布局也应该包含这个属性
android:animateLayoutChanges="true"
然后用视图调用该方法
toggleRecyclerViewVisibility(
recycler,
header,
arrowImageView
)
最简单的解决方案:在持有视图的容器上设置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>
你可以在动画布局变化- Android开发者上找到更多细节
随着Android 3.0 (Honeycomb)引入的新动画API,创建这样的动画非常简单。
将视图向下滑动一段距离:
view.animate().translationY(distance);
你可以稍后将视图滑回原来的位置,如下所示:
view.animate().translationY(0);
您还可以轻松地组合多个动画。下面的动画会将一个视图按高度向下滑动,同时淡入:
// 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);
然后,您可以将视图淡出,并将其滑回原始位置。我们还设置了一个AnimatorListener,这样我们可以在动画完成后将视图的可见性设置为GONE:
view.animate()
.translationY(0)
.alpha(0.0f)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
view.setVisibility(View.GONE);
}
});
通过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