Подтвердить что ты не робот

Android - оживить вид topMargin/bottomMargin/etc в LinearLayout или RelativeLayout

Я пытаюсь создать меню, которое соскальзывает снизу. Он начинается с того, что вид меню отображается в нижней части экрана, а затем щелчок по нему вызывает его ускорение. Я попытался использовать TranslateAnimation, но, хотя пиксели перемещаются, области попадания в меню находятся в том же положении, что и раньше. Поэтому я думаю, что если я смогу настроить поля меню после завершения анимации, это выполнит то, что я хочу. Однако я не могу понять, как настроить поля.

Я попытался создать объект LinearLayout.LayoutMargins, а затем установить его поля и применить его к виду меню (это LinearLayout), но это не сработает.

Любые идеи?

4b9b3361

Ответ 1

Мое решение состояло в том, чтобы создать два LinearLayouts, один в этом состоянии (установленный на нет), а другой в меню вниз. Затем, когда пользователь нажимает кнопку, чтобы переместить меню вверх, я вызываю TranslateAnimation, показывая, что меню открывается. Я помещаю слушателя в анимацию, которая заставляет состояние состояния быть видимым, а состояние "вниз" исчезает, когда анимация заканчивается. Я отменил это для действия "закрытия".

Не совсем так, как я изначально представлял себе это делать, но это сработало.

Ответ 2

Следующие работали для меня. Сначала определите нижние поля (в провалах), чтобы меню было вверх (полностью видимо) или вниз (большая часть скрыта).

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

Затем в 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;
    }
});

И вот идет секретный соус; -)

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

Я использую две служебные функции:

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!

Ответ 3

Я чувствую, что это немного меньше взлома. В принципе, это делает ваш собственный аниматор. Ниже он настраивается только для модификации topMargin в RelativeLayout, но это не сложно обобщить.

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

}

Ответ 4

Используйте ViewPropertyAnimator:

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

Ответ 5

Этот пост помог мне заставить мою анимацию работать. В моем случае у меня полноэкранный просмотр. При некоторых действиях пользователя этот веб-просмотр скользит вправо, около 70%, а новый веб-вид появляется слева и занимает свободное место. Конечный результат: новый веб-просмотр охватывает 70% (ось х), а старый веб-просмотр - остальные. Решение Arne очень помогло мне, настроив маржу на прежнее представление, как только анимация будет выполнена. Псевдокод:

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

Но я столкнулся с странным поведением, я думаю, что мой старый веб-просмотр (который теперь занимает только 30% пространства), переформатировал его содержимое, может думать, что теперь он сжат в меньшем пространстве, а не ведет себя так, как будто его просто скользнул вправо. Другими словами, как только я установил эту маржу, html-макет webview изменился. Опять же, я понятия не имел, почему, и я предполагаю, что он думал, что размер его родительского окна изменился. Исходя из этого предположения, я добавил еще одну строку кода:

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

И это сделало трюк, без переформатирования содержимого html, и я могу взаимодействовать с обоими веб-страницами параллельно.

Я публикую это как большое. Спасибо Арне за эту идею, а также за какие-либо материалы для поведения, которое я видел, и мои предположения. Мне действительно нравится конечное решение, имеет логический смысл, но я могу ошибаться., любые мысли и вводят высокую оценку. Большое вам спасибо.