Android에서 뷰 배경색 애니메이션 변경


335

Android에서 뷰의 배경색 변경을 어떻게 애니메이션합니까?

예를 들면 다음과 같습니다.

빨간색 배경색으로 볼 수 있습니다. 뷰의 배경색이 파란색으로 바뀝니다. 색상 간을 부드럽게 전환하려면 어떻게해야합니까?

뷰를 사용하여이 작업을 수행 할 수없는 경우 다른 방법을 환영합니다.


11
안드로이드와 같은 플랫폼에서는 색상 간의 부드러운 전환이 문제가되지 않을 것으로 예상합니다. 그러나 뷰가 내장되어 있지 않을 수도 있습니다. 문제는 여전히 유효합니다.
hpique

답변:


374

나는이 문제에 대한 (꽤 좋은) 해결책을 알아 냈습니다!

TransitionDrawable 을 사용하여이 작업을 수행 할 수 있습니다 . 예를 들어 드로어 블 폴더의 XML 파일에서 다음과 같이 작성할 수 있습니다.

<?xml version="1.0" encoding="UTF-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- The drawables used here can be solid colors, gradients, shapes, images, etc. -->
    <item android:drawable="@drawable/original_state" />
    <item android:drawable="@drawable/new_state" />
</transition>

그런 다음 실제보기의 XML에서 android:background속성 에서이 TransitionDrawable을 참조 합니다.

이 시점에서 다음을 수행하여 명령에 따라 코드 전환을 시작할 수 있습니다.

TransitionDrawable transition = (TransitionDrawable) viewObj.getBackground();
transition.startTransition(transitionTime);

또는 다음을 호출하여 전환을 반대로 실행하십시오.

transition.reverseTransition(transitionTime);

이 답변이 처음 게시 된 시점에는 사용할 수 없었던 Property Animation API를 사용하는 다른 솔루션에 대한 Roman의 답변 을 참조하십시오 .


3
mxrider 감사합니다! 이것은 질문에 대답합니다. 불행히도 배경으로 TransitionDrawable이있는 뷰도 애니메이션해야하기 때문에 뷰 작동하지 않으며 뷰 애니메이션이 배경 전환을 재정의하는 것처럼 보입니다. 어떤 아이디어?
hpique

6
애니메이션을 시작한 후 TransitionDrawable을 시작하여 문제를 해결했습니다.
hpique

2
대박! 당신이 일하게되어 기쁘다! 안드로이드로 XML로 할 수있는 멋진 것들이 많이 있습니다. 대부분은 문서에 묻혀 있고 내 의견으로는 명확하지 않습니다.
우상화

4
전혀 명확하지 않습니다. 색상이 동적이므로 필자의 경우 xml을 사용하지 않는다고 언급해야합니다. 코드로 TransitionDrawable을 만들면 솔루션이 작동합니다.
hpique

2
주요 단점 중 하나는 어떤 애니메이션이 완료 청취자가 없다는 것입니다
레오 Droidcoder

511

컬러 애니메이션에 새로운 속성 애니메이션 API 를 사용할 수 있습니다 .

int colorFrom = getResources().getColor(R.color.red);
int colorTo = getResources().getColor(R.color.blue);
ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.setDuration(250); // milliseconds
colorAnimation.addUpdateListener(new AnimatorUpdateListener() {

    @Override
    public void onAnimationUpdate(ValueAnimator animator) {
        textView.setBackgroundColor((int) animator.getAnimatedValue());
    }

});
colorAnimation.start();

Android 2.x와의 호환성을 위해 Jake Wharton의 Nine Old Androids 라이브러리 를 사용하십시오 .

getColor방법은 Android M에서 더 이상 사용되지 않으므로 다음 두 가지 중에서 선택할 수 있습니다.

  • 지원 라이브러리를 사용하는 경우 getColor통화를 다음과 같이 바꿔야합니다 .

    ContextCompat.getColor(this, R.color.red);
  • 지원 라이브러리를 사용하지 않는 경우 getColor통화를 다음과 같이 바꿔야합니다 .

    getColor(R.color.red);

2
Property Animation API (또는 NineOldAndroid)를 사용하는 경우 "musthave"솔루션 매우 부드럽게 움직입니다.
Dmitry Zaytsev

1
이 방법으로 전환 지속 시간을 설정하는 방법이 있습니까?
iGio90

159
@ iGio90 네, 믿지 않을 것이지만 메소드 호출 setDuration () :)
Roman Minenok

6
ValueAnimator.ofArgb(colorFrom, colorTo)요점을 더 잘 보지만 슬프게도 새로운 것입니다.
TWiStErRob

1
아름다운 해결책! 감사합니다.
Steve Folly

137

뷰의 배경색을 얻는 방법과 대상 색을 얻는 방법에 따라 여러 가지 방법이 있습니다.

처음 두 개는 Android 속성 애니메이션 프레임 워크를 사용합니다 .

다음과 같은 경우 Object Animator를 사용하십시오 .

  • 뷰의 배경색 argb이 xml 파일 의 값으로 정의되어 있습니다.
  • 보기에서 이전에 색상을 설정했습니다 view.setBackgroundColor()
  • 뷰의 배경색은 드로어 블에 정의되어 있으며 획 또는 모서리 반경과 같은 추가 속성을 정의 하지 않습니다 .
  • 뷰의 배경색이 드로어 블에 정의되어 있고 획 또는 모서리 반경과 같은 추가 속성을 제거하려는 경우 추가 속성을 제거해도 애니메이션이 적용되지 않습니다.

객체 애니메이터 view.setBackgroundColor는 정의 된 드로어 블 ColorDrawable이 거의 인스턴스가 아닌 한 정의 된 드로어 블을 대체하여 호출 하여 작동 합니다 . 즉, 획 또는 모서리와 같은 드로어 블의 추가 배경 속성이 제거됩니다.

다음과 같은 경우 Value Animator를 사용하십시오 .

  • 뷰에는 배경색이 드로어 블에 정의되어 있으며 획 또는 모서리 반경과 같은 속성을 설정하고 실행 중에 결정된 새 색상으로 변경하려고합니다.

다음과 같은 경우 전환 드로어 블을 사용하십시오 .

  • 뷰는 배치 전에 정의 된 두 드로어 블 사이를 전환해야합니다.

해결할 수 없었던 DrawerLayout을 여는 동안 실행되는 전환 드로어 블과 관련된 성능 문제가 발생했습니다. 따라서 예기치 않은 말더듬이 발생하면 같은 버그가 발생했을 수 있습니다.

StateList 드로어 블 또는 LayerLists 드로어 을 사용하려면 Value Animator 예제를 수정해야합니다 . 그렇지 않으면 final GradientDrawable background = (GradientDrawable) view.getBackground();줄에서 충돌이 발생 합니다.

오브젝트 애니메이터 :

정의보기 :

<View
    android:background="#FFFF0000"
    android:layout_width="50dp"
    android:layout_height="50dp"/>

ObjectAnimator이와 같이 만들고 사용 하십시오.

final ObjectAnimator backgroundColorAnimator = ObjectAnimator.ofObject(view,
                                                                       "backgroundColor",
                                                                       new ArgbEvaluator(),
                                                                       0xFFFFFFFF,
                                                                       0xff78c5f9);
backgroundColorAnimator.setDuration(300);
backgroundColorAnimator.start();

XMight가 Android 객체 에서하는 것과 같은 AnimatorInflater를 사용하여 XML에서 애니메이션 정의를로드 할 수도 있습니다.

가치 애니메이터 :

정의보기 :

<View
    android:background="@drawable/example"
    android:layout_width="50dp"
    android:layout_height="50dp"/>

드로어 블 정의 :

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#FFFFFF"/>
    <stroke
        android:color="#edf0f6"
        android:width="1dp"/>
    <corners android:radius="3dp"/>

</shape>

다음과 같이 ValueAnimator를 만들고 사용하십시오.

final ValueAnimator valueAnimator = ValueAnimator.ofObject(new ArgbEvaluator(),
                                                           0xFFFFFFFF,
                                                           0xff78c5f9);

final GradientDrawable background = (GradientDrawable) view.getBackground();
currentAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

    @Override
    public void onAnimationUpdate(final ValueAnimator animator) {
        background.setColor((Integer) animator.getAnimatedValue());
    }

});
currentAnimation.setDuration(300);
currentAnimation.start();

전환 드로어 블 :

정의보기 :

<View
    android:background="@drawable/example"
    android:layout_width="50dp"
    android:layout_height="50dp"/>

드로어 블 정의 :

<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <solid android:color="#FFFFFF"/>
            <stroke
                android:color="#edf0f6"
                android:width="1dp"/>
            <corners android:radius="3dp"/>
        </shape>
    </item>

    <item>
        <shape>
            <solid android:color="#78c5f9"/>
            <stroke
                android:color="#68aff4"
                android:width="1dp"/>
            <corners android:radius="3dp"/>
        </shape>
    </item>
</transition>

다음과 같이 TransitionDrawable을 사용하십시오.

final TransitionDrawable background = (TransitionDrawable) view.getBackground();
background.startTransition(300);

.reverse()애니메이션 인스턴스를 호출하여 애니메이션을 되돌릴 수 있습니다 .

애니메이션을 만드는 다른 방법이 있지만이 세 가지가 가장 일반적 일 것입니다. 나는 일반적으로 ValueAnimator를 사용합니다.


실제로 코드에서 TransitionDrawable을 정의하고 사용할 수는 있지만 어떤 이유로 두 번째로 작동하지 않습니다. 기묘한.
안드로이드 개발자

뷰에 ColorDrawable이 설정되어 있어도 객체 애니메이터를 사용할 수 있습니다. 그냥 로컬 변수에 저장하고 null로 설정하고 애니메이션이 끝나면 원래 ColorDrawable을 다시 설정하십시오.
Miloš Černilovský

55

객체 애니메이터를 만들 수 있습니다. 예를 들어 targetView가 있고 배경색을 변경하고 싶습니다.

int colorFrom = Color.RED;
int colorTo = Color.GREEN;
int duration = 1000;
ObjectAnimator.ofObject(targetView, "backgroundColor", new ArgbEvaluator(), colorFrom, colorTo)
    .setDuration(duration)
    .start();

2
API 21에서을 사용할 수 있습니다 ofArgb(targetView, "backgroundColor", colorFrom, colorTo). 구현은 단지 ofInt(...).setEvaluator(new ArgbEvaluator())입니다.
ypresto

20

이와 같은 컬러 애니메이션을 원한다면

여기에 이미지 설명을 입력하십시오

이 코드는 당신을 도울 것입니다 :

ValueAnimator anim = ValueAnimator.ofFloat(0, 1);   
anim.setDuration(2000);

float[] hsv;
int runColor;
int hue = 0;
hsv = new float[3]; // Transition color
hsv[1] = 1;
hsv[2] = 1;
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

    @Override
    public void onAnimationUpdate(ValueAnimator animation) {

        hsv[0] = 360 * animation.getAnimatedFraction();

        runColor = Color.HSVToColor(hsv);
        yourView.setBackgroundColor(runColor);
    }
});

anim.setRepeatCount(Animation.INFINITE);

anim.start();

9
애님 변수가 초기화 될 때 그 부분은 어디에 있습니까 ?
VoW

@VoW는 ValueAnimator의 인스턴스 일뿐입니다.
RBK

현재로서는 anim.setRepeatCount(ValueAnimator.INFINITE);동일하지 않습니다. 현재는 동일하지만 보장 할 사항은 없습니다.
MikhailKrishtop

@MikhailKrishtop Animation.INFINITE의 문제점은 무엇입니까? developer.android.com/reference/android/view/animation/…
RBK

14

가장 좋은 방법은 사용하는 것입니다 ValueAnimator을 하고ColorUtils.blendARGB

 ValueAnimator valueAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
 valueAnimator.setDuration(325);
 valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator valueAnimator) {

              float fractionAnim = (float) valueAnimator.getAnimatedValue();

              view.setBackgroundColor(ColorUtils.blendARGB(Color.parseColor("#FFFFFF")
                                    , Color.parseColor("#000000")
                                    , fractionAnim));
        }
});
valueAnimator.start();

12

이를 달성하는 또 다른 쉬운 방법은 AlphaAnimation을 사용하여 페이드를 수행하는 것입니다.

  1. 뷰를 ViewGroup으로 설정
  2. match_parent 레이아웃 크기로 인덱스 0에 자식 뷰를 추가하십시오.
  3. 자녀에게 용기와 같은 배경을 제공하십시오
  4. 컨테이너의 배경을 대상 색상으로 변경
  5. AlphaAnimation을 사용하여 아이를 페이드 아웃하십시오.
  6. 애니메이션이 완료되면 자식을 제거합니다 (AnimationListener 사용)

9

이것이 기본 활동에서 배경을 변경하는 데 사용하는 방법입니다. 코드로 생성 된 GradientDrawables를 사용하고 있지만 적합하게 조정할 수 있습니다.

    protected void setPageBackground(View root, int type){
        if (root!=null) {
            Drawable currentBG = root.getBackground();
            //add your own logic here to determine the newBG 
            Drawable newBG = Utils.createGradientDrawable(type); 
            if (currentBG==null) {
                if(Build.VERSION.SDK_INT<Build.VERSION_CODES.JELLY_BEAN){
                    root.setBackgroundDrawable(newBG);
                }else{
                    root.setBackground(newBG);
                }
            }else{
                TransitionDrawable transitionDrawable = new TransitionDrawable(new Drawable[]{currentBG, newBG});
                transitionDrawable.setCrossFadeEnabled(true);
                if(Build.VERSION.SDK_INT<Build.VERSION_CODES.JELLY_BEAN){
                     root.setBackgroundDrawable(transitionDrawable);
                }else{
                    root.setBackground(transitionDrawable);
                }
                transitionDrawable.startTransition(400);
            }
        }
    }

업데이트 : 내가 발견 한 동일한 문제가 setCrossFadeEnabled(true)발생하는 경우 안드로이드 <4.3에서 어떤 이유로 인해 바람직하지 않은 화이트 아웃 효과가 발생하므로 위에서 언급 한 @Roman Minenok ValueAnimator 방법을 사용하여 <4.3의 단색으로 전환해야했습니다.


이것이 바로 내가 찾던 것입니다. 감사! :)
cyph3r

7

답변은 여러 가지 방법으로 제공됩니다. 당신은 또한 사용할 수 ofArgb(startColor,endColor)ValueAnimator.

API> 21의 경우 :

int cyanColorBg = ContextCompat.getColor(this,R.color.cyan_bg);
int purpleColorBg = ContextCompat.getColor(this,R.color.purple_bg);

ValueAnimator valueAnimator = ValueAnimator.ofArgb(cyanColorBg,purpleColorBg);
        valueAnimator.setDuration(500);
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
              @Override
              public void onAnimationUpdate(ValueAnimator valueAnimator) {
                   relativeLayout.setBackgroundColor((Integer)valueAnimator.getAnimatedValue());
              }
        });
        valueAnimator.start();

7

XML 기반 애니메이션에 대한 문서는 끔찍합니다. 당신은 사용할 수 있습니다 : 난 그냥 누르면 ... 슬픈 일이 애니메이션은 하나의 속성 떨어져 있다는 것입니다 버튼의 배경색을 애니메이션으로 시간의 주위에 검색 한 exitFadeDuration에서 selector:

<selector xmlns:android="http://schemas.android.com/apk/res/android"
    android:exitFadeDuration="200">

    <item android:state_pressed="true">
        <shape android:tint="#3F51B5" />
    </item>

    <item>
        <shape android:tint="#F44336" />
    </item>

</selector>

그런 다음 background보기 와 같이 사용하십시오 . Java / Kotlin 코드가 필요하지 않습니다.


당신은 내 하루를 구했습니다. 감사.
Federico Heiland

1
훌륭한 답변입니다. android:enterFadeDuration또한 필요할 수도 있습니다. 내 경험은 그것 없이는 내 애니메이션이 두 번째로 작동하지 않았다는 것입니다.
문자열

7

이를 가능하게하는 멋진 기능이 있습니다.

public static void animateBetweenColors(final @NonNull View viewToAnimateItsBackground, final int colorFrom,
                                        final int colorTo, final int durationInMs) {
    final ColorDrawable colorDrawable = new ColorDrawable(durationInMs > 0 ? colorFrom : colorTo);
    ViewCompat.setBackground(viewToAnimateItsBackground, colorDrawable);
    if (durationInMs > 0) {
        final ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
        colorAnimation.addUpdateListener(animator -> {
            colorDrawable.setColor((Integer) animator.getAnimatedValue());
            ViewCompat.setBackground(viewToAnimateItsBackground, colorDrawable);
        });
        colorAnimation.setDuration(durationInMs);
        colorAnimation.start();
    }
}

그리고 코 틀린에서 :

@JvmStatic
fun animateBetweenColors(viewToAnimateItsBackground: View, colorFrom: Int, colorTo: Int, durationInMs: Int) {
    val colorDrawable = ColorDrawable(if (durationInMs > 0) colorFrom else colorTo)
    ViewCompat.setBackground(viewToAnimateItsBackground, colorDrawable)
    if (durationInMs > 0) {
        val colorAnimation = ValueAnimator.ofObject(ArgbEvaluator(), colorFrom, colorTo)
        colorAnimation.addUpdateListener { animator: ValueAnimator ->
            colorDrawable.color = (animator.animatedValue as Int)
            ViewCompat.setBackground(viewToAnimateItsBackground, colorDrawable)
        }
        colorAnimation.duration = durationInMs.toLong()
        colorAnimation.start()
    }
}

이것은
저가형

2
@Kartheeks는 Android 10 이하를 의미합니까? 그렇다면 "nineOldAndroids"라이브러리를 사용하여 쉽게 지원할 수 있습니다 : nineoldandroids.com . 구문은 거의 동일합니다.
안드로이드 개발자

하위 버전의 경우 colorAnimation.addUpdateListener (new ValueAnimator.AnimatorUpdateListener () {@ public void onAnimationUpdate (ValueAnimator animation) 재정의 {colorDrawable.setColor ((Integer) animation.getAnimatedValue ()); ViewCompat.setBackground (viewToAnimateItsBackground, colorDrawable);}}) ;
Mahbubur Rahman Khan

5

폴더 애니메이터res 폴더에 추가하십시오 . 이름은 애니메이터 여야합니다 . 애니메이터 리소스 파일을 추가하십시오. 예를 들어 res / animator / fade.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
        android:propertyName="backgroundColor"
        android:duration="1000"
        android:valueFrom="#000000"
        android:valueTo="#FFFFFF"
        android:startOffset="0"
        android:repeatCount="-1"
        android:repeatMode="reverse" />
</set>

내부 활동 자바 파일, 이것을 호출

View v = getWindow().getDecorView().findViewById(android.R.id.content);
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.fade);
set.setTarget(v);
set.start();

3

Kotlin에 아래 기능을 사용하십시오.

private fun animateColorValue(view: View) {
    val colorAnimation =
        ValueAnimator.ofObject(ArgbEvaluator(), Color.GRAY, Color.CYAN)
    colorAnimation.duration = 500L
    colorAnimation.addUpdateListener { animator -> view.setBackgroundColor(animator.animatedValue as Int) }
    colorAnimation.start()
}

색상을 변경하려는 뷰를 전달하십시오.


2

ArgbEvaluatorAndroid 소스 코드에서 사용되는 구현 이 전환 색상에서 가장 잘 작동 한다는 것을 알았습니다 . HSV를 사용할 때 두 가지 색상에 따라 전환이 너무 많은 색조를 뛰어 넘었습니다. 그러나이 방법은 그렇지 않습니다.

단순히 애니메이션을 적용하려는 경우 다음 ArgbEvaluatorValueAnimator같이 제안 된대로 사용 하십시오 .

ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.addUpdateListener(new AnimatorUpdateListener() {

    @Override
    public void onAnimationUpdate(ValueAnimator animator) {
        view.setBackgroundColor((int) animator.getAnimatedValue());
    }

});
colorAnimation.start();

그러나 당신이 나와 같고 입력에서 전달 된 일부 사용자 제스처 또는 다른 값으로 전환을 묶고 싶다면 ValueAnimatorAPI 22 이상을 대상으로하지 않는 한 큰 도움이되지 않습니다.이 경우 ValueAnimator.setCurrentFraction()메소드를 사용할 수 있습니다 ). API 22 이하를 대상으로하는 경우 다음 과 같이 ArgbEvaluator소스 코드 에서 찾은 코드 를 고유 한 방법으로 래핑하십시오 .

public static int interpolateColor(float fraction, int startValue, int endValue) {
    int startA = (startValue >> 24) & 0xff;
    int startR = (startValue >> 16) & 0xff;
    int startG = (startValue >> 8) & 0xff;
    int startB = startValue & 0xff;
    int endA = (endValue >> 24) & 0xff;
    int endR = (endValue >> 16) & 0xff;
    int endG = (endValue >> 8) & 0xff;
    int endB = endValue & 0xff;
    return ((startA + (int) (fraction * (endA - startA))) << 24) |
            ((startR + (int) (fraction * (endR - startR))) << 16) |
            ((startG + (int) (fraction * (endG - startG))) << 8) |
            ((startB + (int) (fraction * (endB - startB))));
}

원하는대로 사용하십시오.


0

ademar111190의 답변따라이 방법을 사용하여 두 가지 색상 사이에서보기의 배경색을 펄스합니다.

private void animateBackground(View view, int colorFrom, int colorTo, int duration) {


    ObjectAnimator objectAnimator = ObjectAnimator.ofObject(view, "backgroundColor", new ArgbEvaluator(), colorFrom, colorTo);
    objectAnimator.setDuration(duration);
    //objectAnimator.setRepeatCount(Animation.INFINITE);
    objectAnimator.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {

        }

        @Override
        public void onAnimationEnd(Animator animation) {
            // Call this method again, but with the two colors switched around.
            animateBackground(view, colorTo, colorFrom, duration);
        }

        @Override
        public void onAnimationCancel(Animator animation) {

        }

        @Override
        public void onAnimationRepeat(Animator animation) {

        }
    });
    objectAnimator.start();
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.