Android- LinearLayout 또는 Relativelayout에서 뷰의 Topmargin/Bottommargin/등을 애니메이션

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

문제

바닥에서 미끄러지는 메뉴를 만들려고합니다. 화면 하단에서 볼 수있는 메뉴보기로 시작한 다음 클릭하면 위로 미끄러집니다. 나는 a를 사용했다 TranslateAnimation, 그러나 픽셀이 움직이지만 메뉴의 적중 영역은 이전과 동일한 위치에 있습니다. 애니메이션이 완료된 후 메뉴의 여백을 조정할 수 있다면 이것이 내가 원하는 것을 달성 할 것이라고 생각합니다. 그러나 여백을 조정하는 방법을 알 수 없습니다.

나는 만들려고 노력했다 LinearLayout.LayoutMargins 객체를 한 다음 여백을 설정하고 메뉴의보기에 적용합니다 ( LinearLayout),하지만 이것은 작동하지 않습니다.

어떤 아이디어?

도움이 되었습니까?

해결책 2

내 솔루션은 두 개의 선형 레이 아웃을 만드는 것이 었습니다. 하나는 up 상태에 있고 다른 하나는 메뉴의 아래 상태에 있습니다. 그런 다음 사용자가 버튼을 클릭하여 메뉴를 미끄러지면 TranslateAnimation 메뉴가 미끄러 져 올라갑니다. 애니메이션이 완료되면 UP 상태가 보이고 다운 상태가 사라지는 애니메이션에 청취자를 넣었습니다. 나는 "폐쇄"액션을 위해 이것을 뒤집었다.

내가 원래 상상했던 방식이 아니라 효과가 있었지만 효과가있었습니다.

다른 팁

다음은 나를 위해 일했습니다. 먼저 메뉴가 위로 올라가거나 아래로 (대부분 숨겨진)에 대한 하단 마진 (딥)을 결정하십시오.

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

짜잔!

사용 ViewPropertyAnimator:

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

나는 이것이 약간의 해킹이라고 생각합니다. 기본적으로 자신만의 애니메이터를 만들고 있습니다. 아래는 수정하기위한 설정입니다 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;
            }
        }
    }

}

이 게시물은 제 애니메이션이 작동하는 데 도움이되었습니다. 제 경우에는 전체 화면 웹 뷰가 있습니다. 일부 사용자 조치 에서이 WebView는 오른쪽으로 미끄러 져 약 70%이며 새로운 WebView가 왼쪽에서 나오고 사용 가능한 공간을 차지합니다. 최종 결과, 새로운 WebView는 70% (x 축)와 오래된 웹 뷰를 포함합니다. Arne의 솔루션은 애니메이션이 완료 되 자마자 오래된 시야에 여백을 설정하면서 저를 엄청나게 도와주었습니다. 의사 코드 :

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

그러나 나는 이상한 행동에 직면했고, 내 오래된 웹 뷰 (이제 30% 공간만을 차지하고 있음)가 내용물을 재구성하고 있다고 생각합니다. 오른쪽. 다시 말해,이 마진을 설정하자마자 WebView의 HTML 레이아웃이 변경되었습니다. 다시, 나는 왜 그리고 내 이유를 전혀 몰랐다 추측 부모의 창 크기가 바뀌 었다고 생각합니까? 그 가정을 바탕으로 한 줄의 코드를 추가했습니다.

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

그리고 그것은 트릭, HTML 컨텐츠의 재구성이 없었으며 두 웹 뷰와 병렬로 상호 작용할 수 있습니다.

나는 이것을 아이디어에 대해 Arne에게 큰 감사로 게시하고, 내가 본 행동과 내 가정에 대한 입력을 얻기 위해 이것을 많이 감사합니다. 나는 실제로 최종 솔루션을 좋아하고 논리적으로 의미가 있지만 잘못되었을 수도 있습니다. . . 모든 생각과 의견은 크게 감사 할 것입니다. 매우 감사합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top