Android Custom Views Animations

Android: Custom Views and Animations

안드로이드 애플리케이션에서 사용자 경험을 개선하고, 더욱 풍부한 인터페이스를 제공하기 위해 커스텀 뷰와 애니메이션을 활용할 수 있습니다. 이 장에서는 커스텀 뷰를 만드는 방법과 애니메이션을 적용하는 다양한 기법에 대해 자세히 설명하겠습니다.

1. 커스텀 뷰 만들기

커스텀 뷰는 안드로이드의 기본 뷰 클래스(View, TextView, ImageView 등)를 상속받아 사용자 정의 동작과 모양을 갖는 뷰를 만드는 것을 말합니다.

커스텀 뷰 만들기 단계
  1. View 클래스 상속 및 생성자 정의
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public class CustomView extends View {
private Paint paint;
private Path path;
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
paint = new Paint();
paint.setColor(Color.RED);
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.STROKE);
path = new Path();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
int height = getHeight();
path.moveTo(0, height / 2);
path.lineTo(width, height / 2);
canvas.drawPath(path, paint);
}
}
public class CustomView extends View { private Paint paint; private Path path; public CustomView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { paint = new Paint(); paint.setColor(Color.RED); paint.setStrokeWidth(5); paint.setStyle(Paint.Style.STROKE); path = new Path(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int width = getWidth(); int height = getHeight(); path.moveTo(0, height / 2); path.lineTo(width, height / 2); canvas.drawPath(path, paint); } }
public class CustomView extends View {

    private Paint paint;
    private Path path;

    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStrokeWidth(5);
        paint.setStyle(Paint.Style.STROKE);

        path = new Path();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int width = getWidth();
        int height = getHeight();

        path.moveTo(0, height / 2);
        path.lineTo(width, height / 2);

        canvas.drawPath(path, paint);
    }
}
  1. 레이아웃 파일에 커스텀 뷰 추가
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<!-- res/layout/activity_main.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<com.example.CustomView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<!-- res/layout/activity_main.xml --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <com.example.CustomView android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
<!-- res/layout/activity_main.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <com.example.CustomView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>
  1. 커스텀 뷰 사용
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// MainActivity.java
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
// MainActivity.java import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
// MainActivity.java
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

2. 애니메이션 기본

애니메이션을 사용하면 뷰의 속성 변화를 부드럽게 보여줄 수 있습니다. 안드로이드에서 기본적으로 제공하는 애니메이션은 ViewPropertyAnimator, ObjectAnimator, 그리고 XML 애니메이션 등이 있습니다.

ViewPropertyAnimator 예제
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
view.animate()
.translationX(100)
.alpha(0.5f)
.setDuration(1000);
view.animate() .translationX(100) .alpha(0.5f) .setDuration(1000);
view.animate()
    .translationX(100)
    .alpha(0.5f)
    .setDuration(1000);
ObjectAnimator 예제
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "translationX", 100f);
animator.setDuration(1000);
animator.start();
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "translationX", 100f); animator.setDuration(1000); animator.start();
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "translationX", 100f);
animator.setDuration(1000);
animator.start();
XML 애니메이션 예제
  1. 애니메이션 XML 파일 생성
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<!-- res/anim/translate.xml -->
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0%"
android:toXDelta="100%"
android:duration="1000" />
<!-- res/anim/translate.xml --> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:fromXDelta="0%" android:toXDelta="100%" android:duration="1000" />
<!-- res/anim/translate.xml -->
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="0%"
    android:toXDelta="100%"
    android:duration="1000" />
  1. 애니메이션 적용
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Animation animation = AnimationUtils.loadAnimation(this, R.anim.translate);
view.startAnimation(animation);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.translate); view.startAnimation(animation);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.translate);
view.startAnimation(animation);

3. 트랜지션과 애니메이터

트랜지션 프레임워크

트랜지션 프레임워크는 화면 간의 전환 효과를 적용하는 데 사용됩니다. 기본적인 트랜지션 종류에는 Fade, Slide, Explode 등이 있습니다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Transition fade = new Fade();
fade.setDuration(1000);
TransitionManager.beginDelayedTransition(sceneRoot, fade);
Transition fade = new Fade(); fade.setDuration(1000); TransitionManager.beginDelayedTransition(sceneRoot, fade);
Transition fade = new Fade();
fade.setDuration(1000);
TransitionManager.beginDelayedTransition(sceneRoot, fade);
애니메이터

애니메이터는 Animator 클래스의 서브클래스를 사용하여 다양한 애니메이션 효과를 제공할 수 있습니다. 대표적인 예로 ValueAnimator, ObjectAnimator 등이 있습니다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
animator.setDuration(1000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
view.setAlpha(value);
}
});
animator.start();
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f); animator.setDuration(1000); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float value = (float) animation.getAnimatedValue(); view.setAlpha(value); } }); animator.start();
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
animator.setDuration(1000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        float value = (float) animation.getAnimatedValue();
        view.setAlpha(value);
    }
});
animator.start();

4. 커스텀 애니메이션

복잡한 애니메이션을 구현하려면 AnimatorSet을 사용하여 여러 애니메이션을 함께 사용할 수 있습니다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
ObjectAnimator moveX = ObjectAnimator.ofFloat(view, "translationX", 100f);
ObjectAnimator fadeIn = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(moveX, fadeIn);
animatorSet.setDuration(1000);
animatorSet.start();
ObjectAnimator moveX = ObjectAnimator.ofFloat(view, "translationX", 100f); ObjectAnimator fadeIn = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether(moveX, fadeIn); animatorSet.setDuration(1000); animatorSet.start();
ObjectAnimator moveX = ObjectAnimator.ofFloat(view, "translationX", 100f);
ObjectAnimator fadeIn = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f);

AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(moveX, fadeIn);
animatorSet.setDuration(1000);
animatorSet.start();

예제 종합

커스텀 뷰와 애니메이션 통합 예제

  1. 커스텀 뷰 구현
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public class AnimatedCustomView extends View {
private Paint paint;
private float radius = 0f;
public AnimatedCustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStyle(Paint.Style.FILL);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
int height = getHeight();
canvas.drawCircle(width / 2, height / 2, radius, paint);
}
public void animateRadius() {
ValueAnimator animator = ValueAnimator.ofFloat(0f, Math.min(getWidth(), getHeight()) / 2);
animator.setDuration(1000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
radius = (float) animation.getAnimatedValue();
invalidate();
}
});
animator.start();
}
}
public class AnimatedCustomView extends View { private Paint paint; private float radius = 0f; public AnimatedCustomView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { paint = new Paint(); paint.setColor(Color.BLUE); paint.setStyle(Paint.Style.FILL); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int width = getWidth(); int height = getHeight(); canvas.drawCircle(width / 2, height / 2, radius, paint); } public void animateRadius() { ValueAnimator animator = ValueAnimator.ofFloat(0f, Math.min(getWidth(), getHeight()) / 2); animator.setDuration(1000); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { radius = (float) animation.getAnimatedValue(); invalidate(); } }); animator.start(); } }
public class AnimatedCustomView extends View {

    private Paint paint;
    private float radius = 0f;

    public AnimatedCustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        paint = new Paint();
        paint.setColor(Color.BLUE);
        paint.setStyle(Paint.Style.FILL);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int width = getWidth();
        int height = getHeight();
        canvas.drawCircle(width / 2, height / 2, radius, paint);
    }

    public void animateRadius() {
        ValueAnimator animator = ValueAnimator.ofFloat(0f, Math.min(getWidth(), getHeight()) / 2);
        animator.setDuration(1000);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                radius = (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        animator.start();
    }
}
  1. 레이아웃 파일에 커스텀 뷰 추가
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<!-- res/layout/activity_main.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<com.example.AnimatedCustomView
android:id="@+id/animatedCustomView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Animate"
android:onClick="startAnimation"/>
</LinearLayout>
<!-- res/layout/activity_main.xml --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <com.example.AnimatedCustomView android:id="@+id/animatedCustomView" android:layout_width="match_parent" android:layout_height="match_parent" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Animate" android:onClick="startAnimation"/> </LinearLayout>
<!-- res/layout/activity_main.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <com.example.AnimatedCustomView
        android:id="@+id/animatedCustomView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Animate"
        android:onClick="startAnimation"/>
</LinearLayout>
  1. 애니메이션 시작 버튼 구현
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// MainActivity.java
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private AnimatedCustomView animatedCustomView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
animatedCustomView = findViewById(R.id.animatedCustomView);
}
public void startAnimation(View view) {
animatedCustomView.animateRadius();
}
}
// MainActivity.java import android.os.Bundle; import android.view.View; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { private AnimatedCustomView animatedCustomView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); animatedCustomView = findViewById(R.id.animatedCustomView); } public void startAnimation(View view) { animatedCustomView.animateRadius(); } }
// MainActivity.java
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    private AnimatedCustomView animatedCustomView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        animatedCustomView = findViewById(R.id.animatedCustomView);
    }

    public void startAnimation(View view) {
        animatedCustomView.animateRadius();
    }
}

요약

이 장에서는 안드로이드 애플리케이션에서 커스텀 뷰를 만들고 애니메이션을 적용하는 방법에 대해 알아보았습니다. 이를 통해 앱의 UI를 더욱 풍부하고 사용자 친화적으로 만들 수 있습니다. 다양한 애니메이션 기법과 트랜지션을 활용하여 사용자가 즐길 수 있는 동적인 인터페이스를 구현해 보세요.

Leave a Reply

Your email address will not be published. Required fields are marked *