How to animate a slide in notification view that p

2019-01-06 23:18发布

问题:

I have two views on the screen

one sits at the top of the screen and on sits directly below it

I need the green view to slide out the top - and make the blue view take up the entire screen as a result

this is what i am trying to do:

-- the problem is , when the animation is finished, the blue view just "jumps" up - and i want it to ease up with the disappearing green view, how do i do that?

slide_in_animation.xml

<?xml version="1.0" encoding="utf-8"?>

<set xmlns:android="http://schemas.android.com/apk/res/android">

    <translate
            android:duration="1000"
            android:fromYDelta="-100%"
            android:toYDelta="0%" />
</set>

slide_out_animation.xml

<?xml version="1.0" encoding="utf-8"?>

<set xmlns:android="http://schemas.android.com/apk/res/android">

    <translate
            android:duration="1000"
            android:fromYDelta="0%"
            android:toYDelta="-100%" />
</set>

MainActivity.java

slideInAnimation = AnimationUtils.loadAnimation(mActivity, R.anim.slide_in_animation);
slideOutAnimation = AnimationUtils.loadAnimation(mActivity,R.anim.slide_out_animation);


    slideInAnimation.setAnimationListener(new AnimationListener() {

        @Override
        public void onAnimationStart(Animation animation) {
            mGreenView.setVisibility(View.VISIBLE);

        }

        @Override
        public void onAnimationRepeat(Animation animation) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onAnimationEnd(Animation animation) {

        }
    });

    slideOutAnimation.setAnimationListener(new AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {


        }

        @Override
        public void onAnimationEnd(Animation animation) {
            mGreenView.setVisibility(View.GONE);

        }

        @Override
        public void onAnimationRepeat(Animation animation) {
            // To change body of implemented methods use File | Settings
            // | File Templates.
        }
    });

回答1:

This worked for me

First you must import this library: http://nineoldandroids.com/

The import is done by importing existing android project into your workspace, afterwards right click your Poject -> Properties -> Android. Here you will see a library section, click the Add button and add the nineoldandroids library.

First off, here is the layout xml used for this to work:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/parentLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >

<FrameLayout
    android:id="@+id/frameLayout"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1" >

    <ListView
        android:id="@+id/listView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/transparent"
        android:divider="@android:color/transparent"
        android:fastScrollEnabled="false"
        android:listSelector="@android:color/transparent"
        android:scrollbars="vertical"
        android:smoothScrollbar="true" />

    <View
        android:id="@+id/greenView"
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:background="#ff00ff00"
        android:alpha="0"/>
</FrameLayout>

<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >

    <Button
        android:id="@+id/animate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="clickHandler"
        android:text="animate" />

    <Button
        android:id="@+id/close"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="clickHandler"
        android:text="close" />
</LinearLayout>

Notice: Both the ListView and the green View could be layouts of any types with any kind of content.

And next a proof of concept Activity.

public class TestActivity extends Activity {

private View greenView;
private ListView listView;
private int greenHeight;

private boolean isShowingBox;

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

    // The animated view 
    greenView = (View)findViewById(R.id.greenView);
    listView = (ListView)findViewById(R.id.listView1);


    // Instanciating an array list (you don't need to do this, you already have yours)
    ArrayList<String> your_array_list = new ArrayList<String>();
    your_array_list.add("1");
    your_array_list.add("2");
    your_array_list.add("3");
    your_array_list.add("4");
    your_array_list.add("5");
    your_array_list.add("6");
    your_array_list.add("7");
    your_array_list.add("8");
    your_array_list.add("9");
    your_array_list.add("10");
    your_array_list.add("11");
    your_array_list.add("12");
    your_array_list.add("13");
    your_array_list.add("14");
    your_array_list.add("15");
    // This is the array adapter, it takes the context of the activity as a first // parameter, the type of list view as a second parameter and your array as a third parameter
    ArrayAdapter<String> arrayAdapter =      
    new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, your_array_list);
    listView.setAdapter(arrayAdapter);

    final LinearLayout layout = (LinearLayout)findViewById(R.id.parentLayout);

       final ViewTreeObserver vto = layout.getViewTreeObserver();
        vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {

                if (Build.VERSION.SDK_INT < 16) {
                    layout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                } else {
                    layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                }

                greenHeight = greenView.getHeight();

            }
        });
}

public void clickHandler(View v) {
    if (isShowingBox) {
        isShowingBox = false;
        slideOut(1500, 0);
    } else {
        isShowingBox = true;
        slideIn(1500, 0);
    }
}

private void slideIn(int duration, int delay) { 
    AnimatorSet set = new AnimatorSet();
    set.playTogether(
        // animate from off-screen in to screen 
        ObjectAnimator.ofFloat(greenView, "translationY",  -greenHeight, 0),
        ObjectAnimator.ofFloat(listView, "translationY",  0, greenHeight),
        ObjectAnimator.ofFloat(greenView, "alpha", 0, 0.25f, 1)
        // add other animations if you wish
    );
    set.setStartDelay(delay);
    set.setDuration(duration).start();
}

private void slideOut(int duration, int delay) {
    AnimatorSet set = new AnimatorSet();
    set.playTogether(
        // animate from on-screen and out
        ObjectAnimator.ofFloat(greenView, "translationY", 0, -greenHeight),
        ObjectAnimator.ofFloat(listView, "translationY", greenHeight, 0),
        ObjectAnimator.ofFloat(greenView, "alpha", 1, 1, 1)
        // add other animations if you wish
    );
    set.setStartDelay(delay);
    set.setDuration(duration).start();
}

}

Important note: Remember to import the AnimatorSet and ObjectAnimator from nineoldandroids in your class and not the Android SDK ones!!!



回答2:

One potential solution that makes a nice and fluid exit is using the weight attribute of LinearLayout with a ValueAnimator. Assuming you're using LinearLayout as your parent view for your green and blue blocks, your code would look something like this.

layout.xml

<LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">


    <!--Let's assume this is the view you wish you disappear-->
    <View
        android:id="@+id/view1"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:orientation="vertical"/>

    <View
        android:id="@+id/view2"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="2"/>
</LinearLayout>

Now with this, in your code you can use the ValueAnimator as follows:

public class MainActivity extends Activity implements AnimatorUpdateListener
{
    View view1;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        view1 = (View)findViewById(R.id.view1);
    }

    public void someAction()
    {
        //This is the important part, because it is FROM the first value TO 
        //the second.  Notice that it must be a float type
        ValueAnimator anim = ValueAnimator.ofFloat(1f, 0f);
        anim.setDuration(200);
        anim.addUpdateListener(this);
        anim.start();
    }

    @Override
    public void onAnimationUpdate(ValueAnimator animation)
    {
        view1.setLayoutParams(new LinearLayout.LayoutParams(0, 
                                    LayoutParams.MATCH_PARENT,
                        (Float) animation.getAnimatedValue()));
    }
}

The ValueAnimator will automatically calculate the increments and execute them to get the smooth transition you want with the added benefit of keeping your view running.

You may also need to handle some strange UI occurrences as a result of shrinking the view (i.e., TextViews may act funny on the transition out), but I didn't run into too much trouble patching those up and keeping it neat.

Good luck! Hope this helps.



回答3:

Use following code.

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true">

    <scale
        android:duration="500"
        android:fromXScale="1.0"
        android:fromYScale="0.0"
        android:interpolator="@android:anim/linear_interpolator"
        android:toXScale="1.0"
        android:toYScale="1.0" />

</set>