티스토리 뷰

안드로이드 API에서 제공하는 위젯을 사용하면 거의 대부분의 화면을 만들 수 있다. 하지만, 우리가 원하는 기능만 가진 커스텀 위젯을 따로 구상하여 새로운 뷰를 정의하는 것 또한 가능하다.

 

API에서 제공하는 뷰를 사용하려면 API의 뷰를 상속해야 한다. 이 때 뷰의 영역과 크기는 해당 뷰를 포함하고 있는 레이아웃의 영향을 받아 정해지며, 개발자가 뷰의 상태에 따라 추가적인 코드를 넣을 수 있도록 콜백 메서드가 호출된다. 

 

뷰가 스스로의 크기를 정할 때 자동으로 호출되는 메서드는 onMeasure()이고 스스로를 레이아웃에 맞게 그릴 때는 onDraw() 가 호출된다.

 

일반적으로 사용하는 뷰 객체의 콜백 메서드는 다음과 같다.

  • public void onMeasure(int widthMeasureSpec, int heightMeasureSpec): params는 해당 뷰 객체에 허용되는 폭과 높이이다.
  • public void onDraw(Canvas canvas)
  • void setMeasuredDimension(int measuredWidth, int measuredHeight): params는 해당 뷰 객체의 폭과 높이
  • void invalidate(): 해당 뷰객체 삭제

바로 한번 예제와 함께 확인해보자.


우선 MyButton 이라는 새 클래스를 생성하고 일반적인 버튼의 동작을 하도록 AppCompatButton 클래스를 상속시켜준다.

 

◎MyButton.java

package com.example.sampleview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatButton;

public class MyButton extends AppCompatButton {

    public MyButton(@NonNull Context context) {
        super(context);
        init(context);
    }

    public MyButton(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    @Override
    public void onDraw(Canvas canvas){
        super.onDraw(canvas);
        Log.d("MyButton", "onDraw 호출됨");
    }


    private void init(Context context) {
        setBackgroundColor(Color.CYAN);
        setTextColor(Color.BLACK);

        float textSize = getResources().getDimension(R.dimen.text_size);
        setTextSize(textSize);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d("MyButton", "onTouch 호출됨");

        int action = event.getAction();

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                setBackgroundColor(Color.BLUE);
                setTextColor(Color.RED);
                break;

            case MotionEvent.ACTION_OUTSIDE:

            case MotionEvent.ACTION_CANCEL:

            case MotionEvent.ACTION_UP:
                setBackgroundColor(Color.CYAN);
                setTextColor(Color.BLACK);
                break;
        }

        invalidate();

        return true;
    }
}

MyButton은 2개의 생성자 메서드를 가지고 있는데, 하나는 View객체를 포함할 액티비티의 컨텍스트를 가지고 다른 하나는 컨텍스트와 AttributeSet을 가지는 데 이는 XML 레이아웃에서 태그에 추가하는 속성을 전달받기 위한 것으로 반드시 필요하다.

 

또한 init() 메서드를 작성하면서 사용한 res/dimen.xml파일은 크기가 값 등을 정의할 수 있는 파일이다.

 

이제 생성한 뷰 객체를 레이아웃에 추가해보자.

 

◎activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

    <com.example.sampleview.MyButton android:layout_height="80dp" android:layout_width="200dp"
                                     android:id="@+id/button" android:text="시작하기"
                                     app:layout_constraintEnd_toEndOf="parent"
                                     app:layout_constraintStart_toStartOf="parent"
                                     app:layout_constraintTop_toTopOf="parent"
                                     app:layout_constraintHorizontal_bias="0.497"
                                     app:layout_constraintBottom_toBottomOf="parent">


    </com.example.sampleview.MyButton>
</androidx.constraintlayout.widget.ConstraintLayout>

Comments