Android - Animare di una visualizzazione topMargin / bottomMargin / etc in LinearLayout o RelativeLayout

StackOverflow https://stackoverflow.com/questions/2239442

Domanda

Sto cercando di creare un menu che scorre verso l'alto dal basso. Si inizia con la vista del menu di appena visibile nella parte inferiore dello schermo, e poi clic su di esso induce a scivolare in su. Ho provato ad utilizzare un TranslateAnimation, ma anche i pixel si muovono, le aree colpite del menu sono nella stessa posizione di prima. Quindi penso che se riesco a regolare i margini del menu, dopo l'animazione è completa, questo porterà a compimento quello che voglio. Tuttavia, non riesco a capire come regolare i margini.

Ho cercato di creare un oggetto LinearLayout.LayoutMargins e quindi impostare i propri margini e applicarlo alla visualizzazione del menu (che è un LinearLayout), ma questo non funziona.

Tutte le idee?

È stato utile?

Soluzione 2

La mia soluzione era quella di creare due LinearLayouts, uno in tocca stato (insieme al andata) e l'altro in stato giù del menu. Poi, quando l'utente fa clic sul pulsante per scorrere il menu su, io chiamo un TranslateAnimation che mostra il menu diapositiva. Ho messo un ascoltatore su l'animazione che provoca lo stato fino ad essere visibile e lo stato verso il basso per essere andato quando termina di animazione. Ho invertito questo per l'azione "di chiusura".

Non esattamente il modo in cui avevo inizialmente immaginato di fare, ma ha funzionato.

Altri suggerimenti

Di seguito ha lavorato per me. Prima di decidere i margini inferiori (in tuffi) per il menu di essere all'altezza (completamente visibile) o verso il basso (la maggior parte di nascosto).

private static final int BOTTOM_MARGIN_UP = -50; // My menu view is a bit too tall.
private static final int BOTTOM_MARGIN_DOWN = -120;

Poi, in onCreate ():

menuLinearLayout = (LinearLayout)findViewById(R.id.menuLinearLayout);
setBottomMargin(menuLinearLayout, BOTTOM_MARGIN_DOWN);

upAnimation = makeAnimation(BOTTOM_MARGIN_DOWN, BOTTOM_MARGIN_UP);
downAnimation = makeAnimation(BOTTOM_MARGIN_UP, BOTTOM_MARGIN_DOWN);

Button toggleMenuButton = (Button)findViewById(R.id.toggleMenuButton);
toggleMenuButton.setOnTouchListener(new View.OnTouchListener()
{
    public boolean onTouch(View view, MotionEvent motionEvent)
    {
        if (motionEvent.getAction() != MotionEvent.ACTION_DOWN) return false;
        ViewGroup.MarginLayoutParams layoutParams =
            (ViewGroup.MarginLayoutParams)menuLinearLayout.getLayoutParams();
        boolean isUp = layoutParams.bottomMargin == dipsToPixels(BOTTOM_MARGIN_UP);
        menuLinearLayout.startAnimation(isUp ? downAnimation : upAnimation);
        return true;
    }
});

E qui arriva la salsa segreta; -)

private TranslateAnimation makeAnimation(final int fromMargin, final int toMargin)
{
    TranslateAnimation animation = 
        new TranslateAnimation(0, 0, 0, dipsToPixels(fromMargin - toMargin));
    animation.setDuration(250);
    animation.setAnimationListener(new Animation.AnimationListener()
    {
        public void onAnimationEnd(Animation animation)
        {
            // Cancel the animation to stop the menu from popping back.
            menuLinearLayout.clearAnimation();

            // Set the new bottom margin.
            setBottomMargin(menuLinearLayout, toMargin);
        }

        public void onAnimationStart(Animation animation) {}

        public void onAnimationRepeat(Animation animation) {}
    });
    return animation;
}

Io uso due funzioni di utilità:

private void setBottomMargin(View view, int bottomMarginInDips)
{
    ViewGroup.MarginLayoutParams layoutParams =    
        (ViewGroup.MarginLayoutParams)view.getLayoutParams();
    layoutParams.bottomMargin = dipsToPixels(bottomMarginInDips);
    view.requestLayout();
}

private int dipsToPixels(int dips)
{
    final float scale = getResources().getDisplayMetrics().density;
    return (int)(dips * scale + 0.5f);
}

Voila!

Utilizza il ViewPropertyAnimator:

if (view.getY() != margin) {
    view.animate().y(margin).setDuration(150).start();
}

Mi sento come questo è un po 'meno di un hack. In sostanza, si sta facendo il proprio animatore. Qui di seguito è l'installazione solo per la modifica topMargin in un RelativeLayout, ma non sarebbe stato difficile generalizzare.

import java.util.Calendar;

import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.view.animation.Interpolator;
import android.widget.RelativeLayout.LayoutParams;

public class MarginAnimation extends Thread {
    final String TAG = "MarginAnimation";
    long mStartTime;
    long mTotalTime;
    Interpolator mI;

    int mStartMargin;
    int mEndMargin;

    View mV;
    Activity mA;
    public MarginAnimation(Activity a, View v, 
            int startMargin, int endMargin, int totaltime,
            Interpolator i) {
        mV = v;
        mStartMargin = startMargin;
        mEndMargin = endMargin;
        mTotalTime = totaltime;
        mI = i;
        mA = a;
    }

    @Override
    public void run() {
        mStartTime = Calendar.getInstance().getTimeInMillis();
        while(!this.isInterrupted() && 
                Calendar.getInstance().getTimeInMillis() - mStartTime < mTotalTime) {

            mA.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if(MarginAnimation.this.isInterrupted())
                        return;
                    long cur_time = Calendar.getInstance().getTimeInMillis();
                    float perc_done = 1.0f*(cur_time-mStartTime)/mTotalTime;

                    final int new_margin = (int)(1.0f*(mEndMargin-mStartMargin)*mI.getInterpolation(perc_done)) + mStartMargin;
                    LayoutParams p = (LayoutParams) mV.getLayoutParams();
                    Log.v(TAG, String.format("Setting Margin to %d", new_margin));
                    p.topMargin = new_margin;
                    mV.setLayoutParams(p);                  
                }
            });

            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                return;
            }
        }
    }

}

Questo post mi ha aiutato a ottenere il mio lavoro di animazione. Nel mio caso, ho un WebView a schermo intero. Su alcuni azione dell'utente, questo WebView scivola a destra, circa il 70% e un nuovo WebView emerge dalla sinistra e prende lo spazio disponibile. Risultato finale, un nuovo WebView copre il 70% (asse x) e il vecchio WebView il resto. La soluzione di Arne mi ha aiutato immensamente, impostare il margine al vecchio vista non appena l'animazione è fatto. pseudo codice:

       marginParams.leftMargin = 336; //(70% of 480px)

Ma ho dovuto affrontare un comportamento strano, credo che il mio vecchio WebView (che ora occupa solo lo spazio 30%), è stata la riformattazione dei suoi contenuti, può pensare che ora è schiacciato in uno spazio più piccolo, invece di comportarsi come se il suo solo scivolato verso destra. In altre parole, non appena ho impostato questo margine, il layout html della webview cambiato. Anche in questo caso, non avevo idea perché e il mio indovinate è ha pensato la sua dimensione finestra padre è cambiato. Sulla base di tale presupposto, ho aggiunto una linea più di codice:

      marginParams.rightMargin = -336; //(same amount, but negative margin!)

E che ha fatto il trucco, senza riformattazione dei contenuti html e posso interagire con entrambe le visualizzazioni in parallelo.

sto postando questo come un grande grazie a Arne per l'idea e anche per ottenere eventuali ingressi per il comportamento che ho visto e le mie supposizioni per esso. Io in realtà come la soluzione finale, ha un senso logico, ma potrei sbagliarmi. . . eventuali pensieri e ingresso sarebbe molto apprezzato. Grazie mille.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top