Android - Animer TopMargin est une vision / BottomMargin / etc dans LinearLayout ou RelativeLayout

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

Question

Je suis en train de créer un menu qui glisse vers le haut à partir du bas. Il commence par la vue du menu juste visible au bas de l'écran et en cliquant ensuite l'amène à glisser vers le haut. J'ai essayé d'utiliser un TranslateAnimation, mais bien que les pixels se déplacent, les zones touchées du menu sont dans la même position que précédemment. Je pense donc que si je peux ajuster après l'animation est complète les marges du menu, ce accomplira ce que je veux. Cependant, je ne peux pas comprendre comment ajuster les marges.

J'ai essayé de créer un objet LinearLayout.LayoutMargins puis définissez ses marges et l'appliquer à la vue du menu (qui est un LinearLayout), mais cela ne fonctionne pas.

Toutes les idées?

Était-ce utile?

La solution 2

Ma solution a été de créer deux LinearLayouts, un dans c'est l'état (mis à parti) et l'autre dans l'état bas du menu. Ensuite, lorsque l'utilisateur clique sur le bouton pour faire glisser le menu, j'appelle un TranslateAnimation montrant le menu de diapositives. Je mets un auditeur sur l'animation qui fait l'état jusqu'à être visible et l'état vers le bas pour être allé quand la fin de l'animation. Je renversé cela pour l'action « de fermeture ».

Pas exactement comme je l'avais imaginé au départ le faire, mais cela a fonctionné.

Autres conseils

Les personnes suivantes ont travaillé pour moi. Tout d'abord décider des marges inférieures (en creux) pour le menu étant en place (entièrement visible) ou vers le bas (la plus grande partie cachée).

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

Ensuite, dans 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;
    }
});

Et voilà la sauce secrète; -)

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

J'utilise deux fonctions d'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!

Utilisez le ViewPropertyAnimator:

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

Je me sens comme cela est un peu moins d'un hack. En gros, cela rend votre propre animateur. Ci-dessous il est configuré pour ne modifier topMargin dans un RelativeLayout, mais il ne serait pas difficile de généraliser.

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

}

Ce poste m'a aidé à obtenir mon travail d'animation. Dans mon cas, j'ai un WebView plein écran. Sur une action de l'utilisateur, ce glisse WebView à droite, environ 70% et une nouvelle WebView émerge de la gauche et prend l'espace disponible. Résultat final, une nouvelle WebView couvre les 70% (axe x) et l'ancien WebView le reste. La solution de Arne m'a énormément aidé, la mise en place de la marge à l'ancienne vue dès que l'animation se fait. Code Pseudo:

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

Mais je faisais face à un comportement bizarre, je suppose que mon vieux WebView (qui occupe aujourd'hui seulement 30% d'espace), a été reformater son contenu, on peut penser qu'il est maintenant pressé dans un plus petit espace, plutôt que de se comporter comme si sa juste glissés à droite. En d'autres termes, dès que je mets cette marge, la mise en page HTML du WebView a changé. Encore une fois, je ne savais pas pourquoi et mon deviner est-il pensé sa taille de fenêtre parent a changé. Sur la base de cette hypothèse, j'ajouté une ligne de code:

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

Et qui a fait l'affaire, sans reformatage du contenu html et je peux interagir avec les deux webviews en parallèle.

Je signale cela comme un grand merci à Arne pour l'idée et aussi d'obtenir des entrées pour le comportement que je voyais et mes hypothèses pour elle. J'aime vraiment la solution finale, est logique, mais je peux me tromper. . . les pensées et les commentaires seraient grandement appréciés. Merci beaucoup.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top