2011-09-22 14 views
8

Mam następujący układ:W jaki sposób jedna właściwość Animate Layout w ViewGroups?

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
       android:layout_height="match_parent" 
       android:layout_width="match_parent"> 

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

     ... children ... 

    </FrameLayout> 

    <LinearLayout android:id="@+id/viewgroup_right" 
        android:layout_height="match_parent" 
        android:layout_weight="1" 
        android:layout_width="0dp" 
        android:orientation="vertical"> 

     ... children ... 

    </LinearLayout> 

</LinearLayout> 

I skończyć z czymś takim:

+------------------------+------------+ 
    |      |   | 
    |      |   | 
    |   Left   | Right | 
    |      |   | 
    |      |   | 
    +------------------------+------------+ 

Kiedy pewna przełącznik jest przełączana, chcę animowanie lewo, tak że jej szerokość rozszerza się wypełnić cały ekran. Jednocześnie chciałbym animować szerokość prawej, aby zmniejszyła się do zera. Później, gdy przełącznik zostanie ponownie przełączony, muszę przywrócić rzeczy do powyższego stanu.

Próbowałem napisać własną animację, która wywołuje View.getWidth(), ale kiedy animuję z powrotem do tej wartości (ustawiając View.getLayoutParams().width), jest szersza niż w chwili rozpoczęcia. Podejrzewam, że robię to źle. Przeczytałem również całą dokumentację na temat animacji Honeycomb, ale nie chcę tłumaczyć ani skalować ... Chcę animować właściwość width layoutu. Nie mogę znaleźć tego przykładu.

Jaki jest prawidłowy sposób to zrobić?

Odpowiedz

12

Ponieważ nikt nie pomógł Ci jeszcze i moja pierwsza odpowiedź była taka bałagan Spróbuję dać właściwą odpowiedź, tym razem ;-)

Właściwie pomysł mi się podoba i myślę, że jest to świetny efekt wizualny co może być przydatne dla wielu ludzi. Wdałbym przepełnienie odpowiedniego widoku (myślę, że kurczyć wygląda dziwnie, ponieważ tekst rozszerza się do dołu).

Ale tak, oto kod, który działa idealnie dobrze (można nawet przełączać podczas animacji).

Szybkie wyjaśnienie:
zadzwonić toggle z logiczną dla kierunku, a ten rozpocznie pętlę obsługi połączeń animacyjnych. Spowoduje to zwiększenie lub zmniejszenie wag obu widoków na podstawie kierunku i czasu przeszłego (w celu płynnego obliczenia i animacji). Pętla wywołania animacji wywoła się sama, dopóki nie osiągnie pozycji początkowej lub końcowej.

Układ:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="horizontal" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:weightSum="10" 
    android:id="@+id/slide_layout"> 
    <TextView 
     android:layout_weight="7" 
     android:padding="10dip" 
     android:id="@+id/left" 
     android:layout_width="0dip" 
     android:layout_height="fill_parent"></TextView> 
    <TextView 
     android:layout_weight="3" 
     android:padding="10dip" 
     android:id="@+id/right" 
     android:layout_width="0dip" 
     android:layout_height="fill_parent"></TextView> 
</LinearLayout> 

Aktywność:

public class TestActivity extends Activity { 

    private static final int ANIMATION_DURATION = 1000; 

    private View mSlidingLayout; 
    private View mLeftView; 
    private View mRightView; 

    private boolean mAnimating = false; 
    private boolean mLeftExpand = true; 
    private float mLeftStartWeight; 
    private float mLayoutWeightSum; 
    private Handler mAnimationHandler = new Handler(); 
    private long mAnimationTime; 

    private Runnable mAnimationStep = new Runnable() { 
     @Override 
     public void run() { 
      long currentTime = System.currentTimeMillis(); 
      float animationStep = (currentTime - mAnimationTime) * 1f/ANIMATION_DURATION; 
      float weightOffset = animationStep * (mLayoutWeightSum - mLeftStartWeight); 

      LinearLayout.LayoutParams leftParams = (LinearLayout.LayoutParams) 
        mLeftView.getLayoutParams(); 
      LinearLayout.LayoutParams rightParams = (LinearLayout.LayoutParams) 
        mRightView.getLayoutParams(); 

      leftParams.weight += mLeftExpand ? weightOffset : -weightOffset; 
      rightParams.weight += mLeftExpand ? -weightOffset : weightOffset; 

      if (leftParams.weight >= mLayoutWeightSum) { 
       mAnimating = false; 
       leftParams.weight = mLayoutWeightSum; 
       rightParams.weight = 0; 
      } else if (leftParams.weight <= mLeftStartWeight) { 
       mAnimating = false; 
       leftParams.weight = mLeftStartWeight; 
       rightParams.weight = mLayoutWeightSum - mLeftStartWeight; 
      } 

      mSlidingLayout.requestLayout(); 

      mAnimationTime = currentTime; 

      if (mAnimating) { 
       mAnimationHandler.postDelayed(mAnimationStep, 30); 
      } 
     } 
    }; 

    private void toggleExpand(boolean expand) { 
     mLeftExpand = expand; 

     if (!mAnimating) { 
      mAnimating = true; 
      mAnimationTime = System.currentTimeMillis(); 
      mAnimationHandler.postDelayed(mAnimationStep, 30); 
     } 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.slide_test); 

     mLeftView = findViewById(R.id.left); 
     mRightView = findViewById(R.id.right); 
     mSlidingLayout = findViewById(R.id.slide_layout); 

     mLeftStartWeight = ((LinearLayout.LayoutParams) 
       mLeftView.getLayoutParams()).weight; 
     mLayoutWeightSum = ((LinearLayout) mSlidingLayout).getWeightSum(); 
    } 
} 
2

Wystarczy dodać moje 2 centy, żeby doskonałą odpowiedź Knickedi za - na wszelki wypadek, gdyby ktoś go potrzebuje:

Jeśli animować za pomocą Wagi będą kończyły się problemami z przycinaniem/bez przycinania zawartych widoków i grup widoków. Jest to szczególnie ważne, jeśli używasz grup widoku z wagą jako kontenerów fragmentów. Aby go pokonać, równie dobrze trzeba animować marginesy problematycznych widoków podrzędnych i grup widoków/fragmentów.

I robić wszystkie te rzeczy razem, jego zawsze lepiej iść do ObjectAnimator i AnimatorSet (o ile można z nich korzystać), wraz z niektórych klasach użytkowych jak MarginProxy

1

inny sposób rozwiązania zamieszczonych przez @ knickedi ma używać ObjectAnimator zamiast Runnable. Chodzi o to, aby użyć ObjectAnimatora, aby dostosować wagę obu widoków z lewej i prawej strony. Widoki muszą jednak być dostosowane tak, aby waga mogła zostać ujawniona jako właściwość do animacji ObjectAnimatora.

Więc najpierw zdefiniować niestandardowy widok (używając LinearLayout jako przykład):

public class CustomLinearLayout extends LinearLayout { 
    public CustomLinearLayout(Context context) { 
     super(context); 
    } 

    public CustomLinearLayout(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    public CustomLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) { 
     super(context, attrs, defStyleAttr); 
    } 

    public void setMyWeight(float value) { 
     LinearLayout.LayoutParams p = (LinearLayout.LayoutParams)getLayoutParams(); 
     p.weight = value; 
     requestLayout(); 
    } 
} 

Następnie zaktualizować XML układ do użycia tej niestandardowy układ liniowy.

Wtedy, kiedy trzeba włączyć animację, należy ObjectAnimator:

ObjectAnimator rightView = ObjectAnimator.ofFloat(viewgroup_right, "MyWeight", 0.5f, 1.0f); 
ObjectAnimator leftView = ObjectAnimator.ofFloat(viewgroup_left, "MyWeight", 0.5f, 0.0f); 
AnimatorSet animatorSet = new AnimatorSet(); 
animatorSet.setDuration(1000); // 1 second of animation 
animatorSet.playTogether(rightView, leftView); 
animatorSet.start(); 

Powyższy kod zakłada oba poglądy są układ liniowy i są o połowę masy na początek. Animacja powiększy właściwy widok do pełnej wagi (więc lewa jest ukryta). Zauważ, że ObjectAnimator jest animowany przy użyciu właściwości "MyWeight" dostosowanego układu liniowego. AnimatorSet służy do wiązania zarówno lewego, jak i prawego ObjectAnimatora, dzięki czemu animacja wygląda gładko.

Podejście to redukuje potrzebę zapisywania działającego kodu i obliczania masy w nim, ale wymaga zdefiniowania niestandardowej klasy.

Powiązane problemy