Итак, я искал ответ на этот вопрос для своего проекта Xamarin, но я думаю, что это также должно относиться к Java.Я понял, что анимация LinearLayout ВСЕГДА имела одинаковую позицию (скажем, она была в x = 100, y == 100), и ваша анимация должна быть ОТНОСИТЕЛЬНОЙ к этой позиции.ObjectAnimator определенно был подходящим вариантом, и вот мое решение:
Во-первых, простая компоновка с некоторым текстом вверху и LinearLayout ниже того, что является целью для анимации ....
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:p1="http://schemas.android.com/apk/res/android"
p1:minWidth="25px"
p1:minHeight="25px"
p1:layout_width="match_parent"
p1:layout_height="match_parent"
p1:id="@+id/frameLayout1">
<TextView
p1:text="Some text at the top"
p1:textAppearance="?android:attr/textAppearanceLarge"
p1:id="@+id/txtSomeTextAtTheTop"
p1:layout_width="wrap_content"
p1:layout_height="wrap_content"
p1:layout_gravity="center_horizontal" />
<LinearLayout
p1:orientation="vertical"
p1:minWidth="25px"
p1:minHeight="25px"
p1:layout_width="wrap_content"
p1:layout_height="wrap_content"
p1:id="@+id/linMySlider"
p1:layout_gravity="center_horizontal|bottom">
<LinearLayout
p1:orientation="horizontal"
p1:minWidth="25px"
p1:minHeight="25px"
p1:layout_width="match_parent"
p1:layout_height="wrap_content"
p1:id="@+id/linAlwaysDisplay"
p1:layout_marginBottom="10px">
<TextView
p1:text="ALWAYS ON DISPLAY"
p1:textAppearance="?android:attr/textAppearanceLarge"
p1:id="@+id/txtAlwaysDisplay"
p1:layout_width="wrap_content"
p1:layout_height="wrap_content"
p1:layout_gravity="center_horizontal" />
</LinearLayout>
<LinearLayout
p1:orientation="horizontal"
p1:minWidth="25px"
p1:minHeight="25px"
p1:layout_width="match_parent"
p1:layout_height="wrap_content"
p1:id="@+id/linToHideLineOne">
<TextView
p1:text="To Hide Line One"
p1:textAppearance="?android:attr/textAppearanceLarge"
p1:id="@+id/txtHideLineOne"
p1:layout_width="wrap_content"
p1:layout_height="wrap_content"
p1:layout_gravity="center_horizontal" />
</LinearLayout>
<LinearLayout
p1:orientation="horizontal"
p1:minWidth="25px"
p1:minHeight="25px"
p1:layout_width="match_parent"
p1:layout_height="wrap_content"
p1:id="@+id/linHideLineTwo">
<TextView
p1:text="To Hide Line Two"
p1:textAppearance="?android:attr/textAppearanceLarge"
p1:id="@+id/txtHideLineTwo"
p1:layout_width="wrap_content"
p1:layout_height="match_parent" />
</LinearLayout>
</LinearLayout>
</FrameLayout>
Моя деятельность выглядела следующим образом:
using System;
using Android.App;
using Android.OS;
using Android.Views;
using Android.Widget;
using Android.Animation;
using Android.Views.Animations;
using Android.Util;
namespace MyNamespace
{
[Activity(Label = "testActivity")]
public class testActivity : Activity
{
public static string TAG = "M:testActivity";
//by default we want the slider to be closed, which is why
// _sliderOpen has been set to true and we animate it into position when
//the window gets first focus
private bool _sliderOpen = true;
private ViewGroup _linMySlider;
private LinearLayout _linAlwaysDisplays;
private int _distanceToTravel;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.testLayout);
_linMySlider = FindViewById<ViewGroup>(Resource.Id.linMySlider);
_linAlwaysDisplays = FindViewById<LinearLayout>(Resource.Id.linAlwaysDisplay);
TextView alwaysDisplayText = FindViewById<TextView>(Resource.Id.txtAlwaysDisplay);
alwaysDisplayText.Click += AlwaysDisplayText_Click;
}
private void AlwaysDisplayText_Click(object sender, EventArgs e)
{
DoAnimation(500);
}
public override void OnWindowFocusChanged(bool hasFocus)
{
base.OnWindowFocusChanged(hasFocus);
if (hasFocus)
{
if (_sliderOpen)
{
//we store this one time as it remains constant throught our sliding animations
_distanceToTravel = _linMySlider.Height - _linAlwaysDisplays.Height;
DoAnimation(1);
}
}
}
private void DoAnimation(long duration)
{
ObjectAnimator slideMe = null;
try
{
switch (_sliderOpen)
{
case true:
slideMe = ObjectAnimator.OfFloat(_linMySlider, "translationY", 0, _distanceToTravel);
_sliderOpen = false;
break;
case false:
slideMe = ObjectAnimator.OfFloat(_linMySlider, "translationY", _distanceToTravel, 0);
_sliderOpen = true;
break;
}
slideMe.SetInterpolator(new OvershootInterpolator());
slideMe.SetDuration(duration);
slideMe.Start();
}
catch (Exception e)
{
Log.Error(TAG, "DoAnimation: Exception - " + e.Message);
}
}
}
}
Наиболее важным моментом, который следует отметить, является то, что _distanceToTravel (в данном случае перевод по оси Y) относится к свойству Top объекта LinearLayout, который мы анимируем.Предположим, что каждый из LinearLayouts, который содержит текст (ВСЕГДА НА ОТОБРАЖЕНИИ, Чтобы скрыть строку 1, Чтобы скрыть строку 2), имеет высоту 20 (что делает общую высоту 60).Слайдер, скажем, имеет свойство Top 2100. Поскольку он расположен внизу, чтобы скрыть две линии, нам нужно переместить LinearLayout linMySlider вниз на 40, чтобы скрыть две строки, оставив только первую видимую.Если вы думаете, что LinearLayout ВСЕГДА равен 2100, то имеет смысл, что на слайде мы добавим к нему 40 (ну, не мы, Animator делает это за нас), что видно в первой строке OfFloat, где начальная позиция Yравно 0 (то есть 0 относительно 2100, то есть равно 2100), а его конечная позиция Y равна _distanceToTravel (которая равна 40, но опять-таки относительная, поэтому фактически равна 2140).В обратном направлении мы начинаем с _distanceToTravel для Y (снова 40, но на самом деле 2140) и заканчиваем 0 (вы угадали 0 от 2100 и, следовательно, 2100).
Надеюсь, что все этоимеет смысл - мне потребовалось немного времени, чтобы уронить пенни, но он работает очень хорошо, без мерцания и без возврата к исходному положению (которое всегда имело lol).Надеюсь, то же самое относится и к коду Java, как и в этом примере C #.