View.setVisibility (GONE)을 애니메이션하려면 어떻게합니까?


84

나는 가시성이으로 설정된 Animation경우에 대해 만들고 싶습니다 . 그냥 사라지는 대신 '붕괴'해야합니다. 나는 이것을 시도 하지만 그때는 붕괴이지만, 레이아웃 만의 후 (또는 이전) 공간의 크기를 조정합니다 중지 (또는 시작).ViewGONEViewScaleAnimationViewAnimation

어떻게 만들 수 있습니다 Animation애니 메이팅 반면, 낮은, 그래서 View들 대신에 빈 공간이 필요없이, 내용 바로 아래에 남아있을 것입니다?


여기 앤디 내 ExpandAnimation에 제시하고 나는이 같은 기술을 사용했습니다 : udinic.wordpress.com/2011/09/03/expanding-listview-items 나는 규모의 애니메이션을 사용하지 않은, 그냥 새로운 애니메이션을 내장 그 클래스.
Udinic 2011 년

이 작업을 수행하는 동안 매우 유용했습니다. 감사합니다
atraudes 2011 년

뛰어난 Udinic .. 정말 내 문제를 해결했습니다 .. :) 감사합니다
Yousuf Qureshi

좋아, 내 문제에 적응해야하지만 결국에는 효과가있다. 나 에게이 솔루션은 다른 답변보다 낫습니다.
Derzu 2012

답변:


51

애니메이션은 실제 크기가 아닌 뷰의 렌더링 매트릭스를 변경하기 때문에 API를 통해이 작업을 수행하는 쉬운 방법이없는 것 같습니다. 그러나 우리는 LinearLayout을 속여 뷰가 작아지고 있다고 생각하도록 음의 여백을 설정할 수 있습니다.

따라서 ScaleAnimation을 기반으로 자신 만의 Animation 클래스를 만들고 "applyTransformation"메서드를 재정 의하여 새 여백을 설정하고 레이아웃을 업데이트하는 것이 좋습니다. 이렇게 ...

public class Q2634073 extends Activity implements OnClickListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.q2634073);
        findViewById(R.id.item1).setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        view.startAnimation(new MyScaler(1.0f, 1.0f, 1.0f, 0.0f, 500, view, true));
    }

    public class MyScaler extends ScaleAnimation {

        private View mView;

        private LayoutParams mLayoutParams;

        private int mMarginBottomFromY, mMarginBottomToY;

        private boolean mVanishAfter = false;

        public MyScaler(float fromX, float toX, float fromY, float toY, int duration, View view,
                boolean vanishAfter) {
            super(fromX, toX, fromY, toY);
            setDuration(duration);
            mView = view;
            mVanishAfter = vanishAfter;
            mLayoutParams = (LayoutParams) view.getLayoutParams();
            int height = mView.getHeight();
            mMarginBottomFromY = (int) (height * fromY) + mLayoutParams.bottomMargin - height;
            mMarginBottomToY = (int) (0 - ((height * toY) + mLayoutParams.bottomMargin)) - height;
        }

        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            super.applyTransformation(interpolatedTime, t);
            if (interpolatedTime < 1.0f) {
                int newMarginBottom = mMarginBottomFromY
                        + (int) ((mMarginBottomToY - mMarginBottomFromY) * interpolatedTime);
                mLayoutParams.setMargins(mLayoutParams.leftMargin, mLayoutParams.topMargin,
                    mLayoutParams.rightMargin, newMarginBottom);
                mView.getParent().requestLayout();
            } else if (mVanishAfter) {
                mView.setVisibility(View.GONE);
            }
        }

    }

}

일반적인주의 사항이 적용됩니다. 보호 된 메서드 (applyTransformation)를 재정의하기 때문에 향후 Android 버전에서 작동하지 않을 수도 있습니다.


3
도대체 내가 생각하지 않은 이유는 무엇입니까?! 감사합니다. 또한 "일반적인 경고가 적용됩니다. 보호 된 메서드 (applyTransformation)를 재정의하고 있기 때문에 향후 Android 버전에서 작동하지 않을 수 있습니다." -API 버전마다 보호되는 기능이 다른 이유는 무엇입니까? 그것들은 숨겨지지 않고 보호되어 구현되어 덮어 쓸 수 있습니다 (그렇지 않으면 패키지 범위가됩니다).
MrSnowflake

당신은 아마도 보호 된 방법에 대해 옳을 것입니다. API에서 액세스하는 데 지나치게주의하는 경향이 있습니다.
Andy

1
이것은 "축소"가 작동하도록하기 위해 (fromY = 0.0f, toY = 1.0f) 계산 0 - 에서 제거해야한다는 점을 제외하고는 저에게 효과적이었습니다 marginBottomToY.
dmon

2
MarginLayoutParams특정 LayoutParam유형 으로 캐스팅하는 대신 일반 유형을 사용하는 것이 좋습니다 .
Paul Lammertsma

3
내가 토글 애니메이션을해야한다고 가정하면, 어떻게 그 반대로 할 수 있습니까? 조언 부탁드립니다.
Umesh

99

레이아웃이 아닌 경우보기를 배치 android:animateLayoutChanges="true"하고 해당 레이아웃에 대해 설정 합니다.


1
필요한 최소 API는 11 이상입니다! 하위 버전에는이 방법을 사용할 수 없습니다.
Nagaraj Alagusudaram

2
이것은 가장 과소 평가 된 레이아웃 속성입니다 ... 감사합니다!
Andres Santiago

7

여기서 Andy가 제시 한 것과 동일한 기술을 사용했습니다. 마진 값을 애니메이션으로 만들어 항목의 효과가 사라지거나 나타나도록하는 애니메이션 클래스를 작성했습니다. 다음과 같이 보입니다.

public class ExpandAnimation extends Animation {

// Initializations...

@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
    super.applyTransformation(interpolatedTime, t);

    if (interpolatedTime < 1.0f) {

        // Calculating the new bottom margin, and setting it
        mViewLayoutParams.bottomMargin = mMarginStart
                + (int) ((mMarginEnd - mMarginStart) * interpolatedTime);

        // Invalidating the layout, making us seeing the changes we made
        mAnimatedView.requestLayout();
    }
}
}

내 블로그 게시물 http://udinic.wordpress.com/2011/09/03/expanding-listview-items/ 에서 작동하는 전체 예제가 있습니다.


2

여기에서는 Andy와 동일한 기술을 사용하고 여기에 설명 된 기술을 사용하여 결함없이 확장 및 축소에 사용할 수 있도록 개선했습니다. https://stackoverflow.com/a/11426510/1317564

import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.ScaleAnimation;
import android.view.animation.Transformation;
import android.widget.LinearLayout;

class LinearLayoutVerticalScaleAnimation extends ScaleAnimation {
    private final LinearLayout view;
    private final LinearLayout.LayoutParams layoutParams;

    private final float beginY;
    private final float endY;
    private final int originalBottomMargin;

    private int expandedHeight;
    private boolean marginsInitialized = false;
    private int marginBottomBegin;
    private int marginBottomEnd;

    private ViewTreeObserver.OnPreDrawListener preDrawListener;

    LinearLayoutVerticalScaleAnimation(float beginY, float endY,
            LinearLayout linearLayout) {
        super(1f, 1f, beginY, endY);

        this.view = linearLayout;
        this.layoutParams = (LinearLayout.LayoutParams) linearLayout.getLayoutParams();

        this.beginY = beginY;
        this.endY = endY;
        this.originalBottomMargin = layoutParams.bottomMargin;

        if (view.getHeight() != 0) {
            expandedHeight = view.getHeight();
            initializeMargins();
        }
    }

    private void initializeMargins() {
        final int beginHeight = (int) (expandedHeight * beginY);
        final int endHeight = (int) (expandedHeight * endY);

        marginBottomBegin = beginHeight + originalBottomMargin - expandedHeight;
        marginBottomEnd = endHeight + originalBottomMargin - expandedHeight;
        marginsInitialized = true;
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        super.applyTransformation(interpolatedTime, t);     

        if (!marginsInitialized && preDrawListener == null) {                       
            // To avoid glitches, don't draw until we've initialized everything.
            preDrawListener = new ViewTreeObserver.OnPreDrawListener() {
                @Override
                public boolean onPreDraw() {                    
                    if (view.getHeight() != 0) {
                        expandedHeight = view.getHeight();
                        initializeMargins();
                        adjustViewBounds(0f);
                        view.getViewTreeObserver().removeOnPreDrawListener(this);                               
                    }

                    return false;
                }
            };

            view.getViewTreeObserver().addOnPreDrawListener(preDrawListener);                   
        }

        if (interpolatedTime < 1.0f && view.getVisibility() != View.VISIBLE) {          
            view.setVisibility(View.VISIBLE);           
        }

        if (marginsInitialized) {           
            if (interpolatedTime < 1.0f) {
                adjustViewBounds(interpolatedTime);
            } else if (endY <= 0f && view.getVisibility() != View.GONE) {               
                view.setVisibility(View.GONE);
            }
        }
    }

    private void adjustViewBounds(float interpolatedTime) {
        layoutParams.bottomMargin = 
                marginBottomBegin + (int) ((marginBottomEnd - marginBottomBegin) * interpolatedTime);       

        view.getParent().requestLayout();
    }
}

이것을 사용하여 먼저 기존 LinearLayout을 축소 한 다음 나중에 동일한 LinearLayout을 다시 확장 할 수 있습니까? 이 작업을 수행하려고하면 축소되고 다시 확장되지 않습니다 (아마도보기의 높이가 이제 0이거나 이와 비슷한 것이기 때문일 것입니다).
AHaahr

선형 레이아웃에 둘 이상의 뷰가 포함되어있을 때 더 안정적으로 작동한다는 것을 알았습니다. 보기가 하나만 포함 된 경우 항상 확장되지는 않습니다.
OpenGL ES 배우기
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.