Android dodaje proste animacje przy ustawianiu widoczności (widok. Odszedł)

237

Zaprojektowałem prosty układ. Skończyłem projekt bez animacji, ale teraz chcę dodawać animacje po zdarzeniu kliknięcia widoku tekstu i nie wiem, jak go używać. Czy mój projekt xml wygląda dobrze, czy nie? Wszelkie sugestie będą mile widziane.

Mój XML

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:longClickable="false"
    android:orientation="vertical"
    android:weightSum="16" >

<LinearLayout 
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:orientation="vertical"
    android:background="#00DDA0"
    android:layout_weight="3" >
</LinearLayout>
 <TextView
        android:id="@+id/Information1"
        android:layout_width="match_parent"
        android:layout_height="1dp" 
        android:text="Child Information" 
        android:background="#0390BE"
        android:layout_weight="0.75"
        android:textColor="#FFFFFF"
        android:layout_gravity="center|fill_horizontal"/>

 <LinearLayout
     android:id="@+id/layout1"
     android:layout_width="fill_parent"
     android:layout_height="0dp"
     android:layout_weight="8.5"
     android:background="#BBBBBB"
     android:orientation="vertical" >

     <TextView
         android:id="@+id/textView1"
         android:layout_width="match_parent"
         android:layout_height="match_parent"        
         android:text="TextView" />
 </LinearLayout>

  <TextView
        android:id="@+id/Information2"
        android:layout_width="match_parent"
        android:layout_height="0dp" 
        android:text="Parent Information" 
        android:background="#0390BE"
        android:layout_weight="0.75"
        android:textColor="#FFFFFF"
        android:layout_gravity="center|fill_horizontal"/>
  <LinearLayout 
          android:id="@+id/layout2"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:orientation="vertical"
    android:background="#BBBBBB"
    android:layout_weight="8.5" >
     <TextView
         android:id="@+id/textView2"
         android:layout_width="match_parent"
         android:layout_height="match_parent"        
         android:text="TextView" />
      </LinearLayout>
   <TextView
        android:id="@+id/Information3"
        android:layout_width="match_parent"
        android:layout_height="0dp" 
        android:text="Siblings" 
        android:background="#0390BE"
        android:layout_weight="0.75"
        android:textColor="#FFFFFF"
        android:layout_gravity="center|fill_horizontal"/>
   <LinearLayout 
          android:id="@+id/layout3"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:orientation="vertical"
    android:background="#BBBBBB"
    android:layout_weight="8.5" >
     <TextView
         android:id="@+id/textView3"
         android:layout_width="match_parent"
         android:layout_height="match_parent"        
         android:text="TextView" />
      </LinearLayout>
    <TextView
        android:id="@+id/Information4"
        android:layout_width="match_parent"
        android:layout_height="0dp" 
        android:text="Teacher Information" 
        android:background="#0390BE"
        android:layout_weight="0.75"
        android:textColor="#FFFFFF"
        android:layout_gravity="center|fill_horizontal"/>
    <LinearLayout 
          android:id="@+id/layout4"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:orientation="vertical"
    android:background="#BBBBBB"
    android:layout_weight="8.5" >
     <TextView
         android:id="@+id/textView4"
         android:layout_width="match_parent"
         android:layout_height="match_parent"        
         android:text="TextView" />
      </LinearLayout>
     <TextView
        android:id="@+id/Information5"
        android:layout_width="match_parent"
        android:layout_height="0dp" 
        android:text="Grade Information" 
        android:background="#0390BE"
        android:layout_weight="0.75"
        android:textColor="#FFFFFF"
        android:layout_gravity="center|fill_horizontal"/>
     <LinearLayout 
          android:id="@+id/layout5"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:orientation="vertical"
    android:background="#BBBBBB"
    android:layout_weight="8.5" >
     <TextView
         android:id="@+id/textView5"
         android:layout_width="match_parent"
         android:layout_height="match_parent"        
         android:text="TextView" />
      </LinearLayout>
      <TextView
        android:id="@+id/Information6"
        android:layout_width="match_parent"
        android:layout_height="0dp" 
        android:text="Health Information" 
        android:background="#0390BE"
        android:layout_weight="0.75"
        android:textColor="#FFFFFF"
        android:layout_gravity="center|fill_horizontal"/>
      <LinearLayout 
          android:id="@+id/layout6"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:orientation="vertical"
    android:background="#BBBBBB"
    android:layout_weight="8.5" >
    <TextView
         android:id="@+id/textView5"
         android:layout_width="match_parent"
         android:layout_height="match_parent"        
         android:text="TextView" 
         android:layout_weight="8.5" />
      </LinearLayout>

</LinearLayout>

Moja java

public class Certify_Info extends Activity {

    private static TextView tv2,tv3,tv5,tv6,tv4,tv1;
    private static LinearLayout l1,l2,l3,l4,l5,l6;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_certify__info);

        tv1=(TextView) findViewById(R.id.Information1);
        tv2=(TextView) findViewById(R.id.Information2);
        tv3=(TextView) findViewById(R.id.Information3);
        tv4=(TextView) findViewById(R.id.Information4);
        tv5=(TextView) findViewById(R.id.Information5);
        tv6=(TextView) findViewById(R.id.Information6); 

        l1=(LinearLayout) findViewById(R.id.layout1);
        l2=(LinearLayout) findViewById(R.id.layout2);
        l3=(LinearLayout) findViewById(R.id.layout3);
        l4=(LinearLayout) findViewById(R.id.layout4);
        l5=(LinearLayout) findViewById(R.id.layout5);
        l6=(LinearLayout) findViewById(R.id.layout6); 

        l2.setVisibility(View.GONE);
        l3.setVisibility(View.GONE); 
        l4.setVisibility(View.GONE); 
        l5.setVisibility(View.GONE);
        l6.setVisibility(View.GONE);

        tv1.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                l2.setVisibility(View.GONE);
                l3.setVisibility(View.GONE); 
                l4.setVisibility(View.GONE); 
                l5.setVisibility(View.GONE);
                l6.setVisibility(View.GONE);
                l1.setVisibility(View.VISIBLE);
            }
        });
        tv2.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                l1.setVisibility(View.GONE);
                l3.setVisibility(View.GONE); 
                l4.setVisibility(View.GONE); 
                l5.setVisibility(View.GONE);
                l6.setVisibility(View.GONE);
                l2.setVisibility(View.VISIBLE);
            }
        });
        tv3.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                l1.setVisibility(View.GONE);
                l2.setVisibility(View.GONE);
                l4.setVisibility(View.GONE); 
                l5.setVisibility(View.GONE);
                l6.setVisibility(View.GONE);
                l3.setVisibility(View.VISIBLE);

            }
        });
        tv4.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                l1.setVisibility(View.GONE);
                l2.setVisibility(View.GONE);
                l3.setVisibility(View.GONE); 
                l4.setVisibility(View.GONE); 
                l5.setVisibility(View.GONE);
                l6.setVisibility(View.GONE);
                l4.setVisibility(View.VISIBLE); 
            }
        });
        tv5.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                l1.setVisibility(View.GONE);
                l2.setVisibility(View.GONE);
                l3.setVisibility(View.GONE); 
                l4.setVisibility(View.GONE); 
                l6.setVisibility(View.GONE);
                l5.setVisibility(View.VISIBLE); 
            }
        });
        tv6.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                l1.setVisibility(View.GONE);
                l2.setVisibility(View.GONE);
                l3.setVisibility(View.GONE); 
                l4.setVisibility(View.GONE); 
                l5.setVisibility(View.GONE);
                l6.setVisibility(View.VISIBLE);
            }
        });

    }
}
bieg
źródło

Odpowiedzi:

706

Możesz zrobić dwie rzeczy, aby dodać animacje, najpierw możesz pozwolić Androidowi animować zmiany układu dla Ciebie. W ten sposób za każdym razem, gdy zmienisz coś w układzie, takie jak zmiana widoczności widoku lub pozycji widoku, Android automatycznie utworzy animacje przenikania / przejścia. Aby użyć tego zestawu

android:animateLayoutChanges="true"

w węźle głównym w twoim układzie.

Drugą opcją byłoby ręczne dodawanie animacji. W tym celu sugeruję skorzystanie z nowego API animacji wprowadzonego w systemie Android 3.0 (Honeycomb). Mogę podać kilka przykładów:

To zanika View:

view.animate().alpha(0.0f);

Powoduje to zanikanie:

view.animate().alpha(1.0f);

To przesuwa się w Viewdół o jego wysokość:

view.animate().translationY(view.getHeight());

Spowoduje to powrót Viewdo pozycji początkowej po przeniesieniu w inne miejsce:

view.animate().translationY(0);

Możesz także użyć setDuration()do ustawienia czasu trwania animacji. Na przykład zanika to Vieww ciągu 2 sekund:

view.animate().alpha(0.0f).setDuration(2000);

Możesz łączyć tyle animacji, ile chcesz, na przykład Viewpowoduje to wyciszenie a i przesunięcie go jednocześnie w dół o 0,3 sekundy:

view.animate()
        .translationY(view.getHeight())
        .alpha(0.0f)
        .setDuration(300);

Możesz także przypisać słuchacza do animacji i reagować na wszelkiego rodzaju zdarzenia. Podobnie jak w przypadku rozpoczęcia animacji, jej zakończenia lub powtórzenia itp. Używając klasy abstrakcyjnej AnimatorListenerAdapter, nie musisz implementować wszystkich wywołań zwrotnych AnimatorListenernaraz, a tylko tych, których potrzebujesz. Dzięki temu kod jest bardziej czytelny. Na przykład poniższy kod wycisza Viewruch przesuwa go w dół o wysokość w ciągu 0,3 sekundy (300 milisekund), a po zakończeniu animacji jego widoczność jest ustawiona na View.GONE.

view.animate()
        .translationY(view.getHeight())
        .alpha(0.0f)
        .setDuration(300)
        .setListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                view.setVisibility(View.GONE);
            }
        });
Xaver Kapeller
źródło
6
@Natix Nie nazwałbym tego super połączenia redundantnym. Nie rób powierzchownych zmian, nie ma nic złego.
Xaver Kapeller
5
Jest dobrze, ale odwrotność nie działa poprawnie, dlaczego? view.setVisibility (View.VISIBLE); Alfa (1.0f), pojawiają się z 100 dopełnienia górze ...
Dosta
15
Należy wyczyścić animację przed ustawieniem widoczności >> w view.clearAnimation(); view.setVisibility(View.GONE);przeciwnym razie układ pozostanie niewidoczny i nie zniknie.
Eftekhari
2
@Eftekhari W ogóle nie wymagają dużych zasobów. A jeśli masz aktualną wersję Androida, ale nadal masz opóźnienie, prawdopodobnie masz starszy telefon z niską pamięcią lub złym układem graficznym. I nie mówię o nowej bibliotece. Animatorzy są rodzimi. Są częścią systemu Android. Zostały wydane 5 lat temu i dziś obsługuje je 97,9% wszystkich urządzeń. Nie ma powodu, aby nie używać Animatorów, a przynajmniej ViewCompat.animate()który jest częścią biblioteki obsługi i używa Animatorów w nowszych wersjach i Wyświetl animacje w systemie Android 3.0 i niższych.
Xaver Kapeller,
1
Ale gdy 97,9% wszystkich urządzeń to Android 4.0 i nowsze, nie ma już zbyt wiele zastosowań ViewCompat.animate().
Xaver Kapeller,
70

Najłatwiejszym sposobem animowania Visibilityzmian jest użycie Transition APIpakietu dostępnego w pakiecie wsparcia (Androidx). Wystarczy wywołać TransitionManager.beginDelayedTransitionmetodę, a następnie zmienić widoczność widoku. Istnieje kilka domyślnych Przejścia jak Fade, Slide.

import androidx.transition.TransitionManager;
import androidx.transition.Transition;
import androidx.transition.Fade;

private void toggle() {
    Transition transition = new Fade();
    transition.setDuration(600);
    transition.addTarget(R.id.image);

    TransitionManager.beginDelayedTransition(parent, transition);
    image.setVisibility(show ? View.VISIBLE : View.GONE);
}

Gdzie parentjest rodzicem ViewGroupwidoku animowanego. Wynik:

wprowadź opis zdjęcia tutaj

Oto wynik Slideprzejścia:

import androidx.transition.Slide;

Transition transition = new Slide(Gravity.BOTTOM);

wprowadź opis zdjęcia tutaj

Łatwo jest napisać niestandardowe przejście, jeśli potrzebujesz czegoś innego. Oto przykład, z CircularRevealTransitionktórym napisałem w innej odpowiedzi . Pokazuje i ukrywa widok z animacją CircularReveal.

Transition transition = new CircularRevealTransition();

wprowadź opis zdjęcia tutaj

android:animateLayoutChanges="true"opcja robi to samo, po prostu używa AutoTransition jako przejścia.

Ashakirov
źródło
@TouhidulIslam no. Te klasy są dostępne w pakiecie Androidx. Wszystko jest kompatybilne wstecz
ashakirov
2
Co powiesz na rozwijanie / zwijanie grupy widoków?
TheRealChx101
Czy możesz zrobić wiele beginDelayedTransitions?
Jeongbebs
26

Sprawdź ten link. Który pozwoli na animacje takie jak L2R, R2L, T2B, B2T.

Ten kod pokazuje animację od lewej do prawej

TranslateAnimation animate = new TranslateAnimation(0,view.getWidth(),0,0);
animate.setDuration(500);
animate.setFillAfter(true);
view.startAnimation(animate);
view.setVisibility(View.GONE);

jeśli chcesz to zrobić z R2L, użyj

TranslateAnimation animate = new TranslateAnimation(0,-view.getWidth(),0,0);

od góry do dołu jako

TranslateAnimation animate = new TranslateAnimation(0,0,0,view.getHeight());

i vice versa ..

NullPointerException
źródło
8
To przesuwa widok z pierwotnej pozycji.
Relm
24

Spróbuj dodać tę linię do układu nadrzędnego xml

 android:animateLayoutChanges="true"

Twój układ będzie wyglądał następująco

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:animateLayoutChanges="true"
    android:longClickable="false"
    android:orientation="vertical"
    android:weightSum="16">

    .......other code here

    </LinearLayout>
Ricardo Romo
źródło
to działało dla mnie. Moja konfiguracja używa układu ograniczenia jako widoku głównego. Gdy widok jest ustawiony na View.VISIBLE, wyświetlana jest animacja
EdgeDev
bardzo proste i eleganckie rozwiązanie
Naveed Ahmad
11

Na podstawie odpowiedzi @Xaver Kapeller wymyśliłem sposób tworzenia animacji przewijania, gdy na ekranie pojawiają się nowe widoki (a także animacja, aby je ukryć).

Wynika z tego stanu:

  • Przycisk
  • Ostatni przycisk

do

  • Przycisk
  • Przycisk 1
  • Przycisk 2
  • Przycisk 3
  • Przycisk 4
  • Ostatni przycisk

i wzajemnie.

Tak więc, gdy użytkownik kliknie pierwszy przycisk, elementy „Przycisk 1”, „Przycisk 2”, „Przycisk 3” i „Przycisk 4” pojawią się przy użyciu animacji zanikania, a element „Ostatni przycisk” przesunie się w dół do końca. Zmieni się również wysokość układu, umożliwiając prawidłowe korzystanie z widoku przewijania.

Oto kod pokazujący elementy z animacją:

private void showElements() {
    // Precondition
    if (areElementsVisible()) {
        Log.w(TAG, "The view is already visible. Nothing to do here");
        return;
    }

    // Animate the hidden linear layout as visible and set
    // the alpha as 0.0. Otherwise the animation won't be shown
    mHiddenLinearLayout.setVisibility(View.VISIBLE);
    mHiddenLinearLayout.setAlpha(0.0f);
    mHiddenLinearLayout
            .animate()
            .setDuration(ANIMATION_TRANSITION_TIME)
            .alpha(1.0f)
            .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    updateShowElementsButton();
                    mHiddenLinearLayout.animate().setListener(null);
                }
            })
    ;

    mLastButton
            .animate()
            .setDuration(ANIMATION_TRANSITION_TIME)
            .translationY(mHiddenLinearLayoutHeight);

    // Update the high of all the elements relativeLayout
    LayoutParams layoutParams = mAllElementsRelativeLayout.getLayoutParams();

    // TODO: Add vertical margins
    layoutParams.height = mLastButton.getHeight() + mHiddenLinearLayoutHeight;
}

i to jest kod, aby ukryć elementy animacji:

private void hideElements() {
    // Precondition
    if (!areElementsVisible()) {
        Log.w(TAG, "The view is already non-visible. Nothing to do here");
        return;
    }

    // Animate the hidden linear layout as visible and set
    mHiddenLinearLayout
            .animate()
            .setDuration(ANIMATION_TRANSITION_TIME)
            .alpha(0.0f)
            .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    Log.v(TAG, "Animation ended. Set the view as gone");
                    super.onAnimationEnd(animation);
                    mHiddenLinearLayout.setVisibility(View.GONE);
                    // Hack: Remove the listener. So it won't be executed when
                    // any other animation on this view is executed
                    mHiddenLinearLayout.animate().setListener(null);
                    updateShowElementsButton();
                }
            })
    ;

    mLastButton
            .animate()
            .setDuration(ANIMATION_TRANSITION_TIME)
            .translationY(0);

    // Update the high of all the elements relativeLayout
    LayoutParams layoutParams = mAllElementsRelativeLayout.getLayoutParams();

    // TODO: Add vertical margins
    layoutParams.height = mLastButton.getHeight();
}

Zauważ, że metoda ukrywania animacji jest prosta. W detektorze animacji mHiddenLinearLayout musiałem usunąć sam detektor za pomocą:

mHiddenLinearLayout.animate().setListener(null);

Dzieje się tak, ponieważ po dołączeniu detektora animacji do widoku, następnym razem, gdy jakakolwiek animacja zostanie wykonana w tym widoku, detektor również zostanie wykonany. Może to być błąd w detektorze animacji.

Kod źródłowy projektu znajduje się na GitHub: https://github.com/jiahaoliuliu/ViewsAnimated

Miłego kodowania!

Aktualizacja : dla każdego detektora dołączonego do widoków należy go usunąć po zakończeniu animacji. Odbywa się to za pomocą

view.animate().setListener(null);
Jiahao
źródło
To najlepsza odpowiedź
Naveen Kumar M
1
view.animate().setListener(null);Oświadczenie zapisany mój dzień. To zdecydowanie wydaje się być błędem.
Michał Vician
@MichalVician Cieszę się, że tak!
jiahao
8

Byłem w stanie pokazać / ukryć menu w ten sposób:

MenuView.java (rozszerza FrameLayout)

private final int ANIMATION_DURATION = 500;

public void showMenu()
{
    setVisibility(View.VISIBLE);
    animate()
            .alpha(1f)
            .setDuration(ANIMATION_DURATION)
            .setListener(null);
}

private void hideMenu()
{
    animate()
            .alpha(0f)
            .setDuration(ANIMATION_DURATION)
            .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    setVisibility(View.GONE);
                }
            });
}

Źródło

Nelson Almendra
źródło