Android - Animieren Sie die Topmargin/Bottommargin/etc einer Ansicht in Linearlayout oder RelATelayout

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

Frage

Ich versuche ein Menü zu erstellen, das von unten nach oben rutscht. Es beginnt mit der Ansicht des Menüs, nur am Ende des Bildschirms sichtbar zu sein, und anschließend wird es dazu gebracht, sie zu schieben. Ich habe versucht, eine zu verwenden TranslateAnimation, Aber obwohl sich die Pixel bewegen, befinden sich die Hit -Bereiche der Speisekarte in der gleichen Position wie zuvor. Ich denke also, wenn ich die Margen des Menüs nach Abschluss der Animation anpassen kann, wird dies das erreichen, was ich will. Ich kann jedoch nicht herausfinden, wie ich die Ränder einstellen kann.

Ich habe versucht, eine zu erstellen LinearLayout.LayoutMargins Objekt und setzen LinearLayout), aber das funktioniert nicht.

Irgendwelche Ideen?

War es hilfreich?

Lösung 2

Meine Lösung bestand darin, zwei Linearlayouts zu erstellen, eines im State (Set to Gone) und den anderen im Menü im Down -Status des Menüs. Wenn der Benutzer dann auf die Schaltfläche klickt, um das Menü nach oben zu schieben, rufe ich a auf TranslateAnimation Zeigen Sie das Menü an. Ich habe einen Hörer auf die Animation gesetzt, die dazu führt, dass der Up -Status sichtbar ist, und der Down -Status ist verschwunden, wenn die Animation beendet ist. Ich habe dies für die "schließende" Aktion umgekehrt.

Nicht genau so, wie ich es mir ursprünglich vorgestellt hatte, aber es hat funktioniert.

Andere Tipps

Das Folgende funktionierte für mich. Entscheiden Sie zuerst die unteren Ränder (in Dips) für das Menü (völlig sichtbar) oder unten (das meiste davon versteckt).

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

Dann 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;
    }
});

Und hier kommt die geheime Sauce ;-)

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;
}

Ich verwende zwei Dienstprogrammfunktionen:

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!

Verwenden Sie das ViewPropertyAnimator:

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

Ich habe das Gefühl, dass dies ein bisschen weniger ein Hack ist. Grundsätzlich macht es Ihren eigenen Animator. Unten ist es ein Setup, um nur zu modifizieren topMargin in einem RelativeLayout, aber es wäre nicht schwer, es zu verallgemeinern.

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;
            }
        }
    }

}

Dieser Beitrag hat mir geholfen, meine Animation zum Laufen zu bringen. In meinem Fall habe ich ein Vollbild -Webview. Bei einigen Benutzeraktionen rutscht dieses WebView nach rechts, etwa 70% und ein neues Webview entsteht links und nimmt den verfügbaren Platz ein. Endergebnis deckt ein neues WebView die 70% (X-Achse) und den alten WebView The Rest ab. Arnes Lösung hat mir immens geholfen und den Rand der alten Sichtweise festgelegt, sobald die Animation fertig ist. Pseudocode:

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

Aber ich habe ein seltsames Verhalten ausgesetzt, ich denke, mein altes Webview (das jetzt nur noch 30% Platz belegt), hat seine Inhalte neu formatiert und denken, dass es jetzt in einen kleineren Raum gepresst wird, anstatt sich so zu verhalten Rechts. Mit anderen Worten, sobald ich diesen Rand festgelegt habe, änderte sich das HTML -Layout des WebView. Wieder hatte ich keine Ahnung warum und meine erraten Ist es gedacht, dass sich die Größe der Elternfenster geändert hat? Basierend auf dieser Annahme habe ich eine weitere Codezeile hinzugefügt:

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

Und das hat den Trick gemacht, keine Neuformatierung des HTML -Inhalts und ich kann parallel mit beiden Webviews interagieren.

Ich poste dies als großes Dankeschön an Arne für die Idee und um Eingaben für das Verhalten, das ich gesehen habe, und meine Annahmen dafür. Ich mag die Endlösung tatsächlich, macht logisch Sinn, aber ich kann mich irren. . . Alle Gedanken und Input wären sehr geschätzt. Vielen Dank.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top