관리 메뉴

나만을 위한 블로그

[Manifest-Android] 39. 커스텀 뷰 구현 방법 본문

스터디

[Manifest-Android] 39. 커스텀 뷰 구현 방법

참깨빵위에참깨빵_ 2025. 7. 29. 23:09
728x90
반응형
커스텀 뷰 클래스 생성

 

기본 뷰 클래스(View, ImageView, TextView 등)를 확장하는 새 클래스를 정의한다. 그 후 구현할 커스텀 동작에 따라 onDraw(), onMeasure(), onLayout() 같은 필요한 메서드, 생성자를 재정의한다.

아래는 onDraw()를 오버라이드하여 캔버스에 적접 빨간색 원을 그리는 커스텀 뷰다.

 

class CustomCircleView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0
) : View(context, attrs, defStyle) {

    private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = Color.RED
        style = Paint.Style.FILL
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        canvas.drawCircle(width / 2f, height / 2f, min(width, height) / 4f, paint)
    }
}

 

XML에서 커스텀 뷰 사용

 

커스텀 뷰 클래스를 생성한 후 XML 레이아웃 파일에서 직접 참조할 수 있다. 커스텀 클래스의 전체 패키지 경로를 정확하게 입력해야 한다. XML에서 정의할 수 있는 커스텀 속성(layout_width 등)을 커스텀 뷰에 전달할 수도 있다.

 

<com.example.myapp.ui.CustomCircleView
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:layout_gravity="center"/>

 

커스텀 속성 추가

 

values 폴더에 attrs.xml을 만들고 커스텀 속성을 정의할 수 있다. 이걸 통해 XML에서 뷰 속성을 커스텀할 수 있다.

위의 커스텀 뷰에서 원 색깔, 반지름을 커스텀할 수 있게 해서 재사용성을 확장할 수 있다.

 

<resources>
    <declare-styleable name="CustomCircleView">
        <attr name="circleColor" format="color"/>
        <attr name="circleRadius" format="dimension"/>
    </declare-styleable>
</resources>

 

커스텀 뷰 클래스에선 context.obtainStyledAttributes()를 써서 커스텀 속성 값을 가져올 수 있다.

 

class CustomCircleView @JvmOverloads constructor(
  context: Context,
  attrs: AttributeSet? = null,
  defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    var circleColor: Int = Color.RED
    var circleRadius: Float = 50f

    private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        style = Paint.Style.FILL
    }

    init {
        attrs?.let {
            getAttrs(it, defStyleAttr)
        }
        paint.color = circleColor
    }

    private fun getAttrs(attrs: AttributeSet, defStyleAttr: Int) {
        val typedArray = context.obtainStyledAttributes(
            attrs, R.styleable.CustomCircleView, defStyleAttr, 0
        )
        try {
            setTypeArray(typedArray)
        } finally {
            typedArray.recycle()
        }
    }

    private fun setTypeArray(typedArray: TypedArray) {
        circleColor = typedArray.getColor(R.styleable.CustomCircleView_circleColor, Color.RED)
        circleRadius = typedArray.getDimension(R.styleable.CustomCircleView_circleRadius, 50f)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        canvas.drawCircle(width / 2f, height / 2f, circleRadius, paint)
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val desiredWidth = (circleRadius * 2 + paddingLeft + paddingRight).toInt()
        val desiredHeight = (circleRadius * 2 + paddingTop + paddingBottom).toInt()

        val width = resolveSize(desiredWidth, widthMeasureSpec)
        val height = resolveSize(desiredHeight, heightMeasureSpec)
        setMeasuredDimension(width, height)
    }

    fun setCircleProperties(color: Int, radius: Float) {
        this.circleColor = color
        this.circleRadius = radius
        paint.color = color
        requestLayout()
        invalidate()
    }
}

 

XML에선 아래처럼 커스텀 속성을 사용한다.

 

<com.example.myapp.ui.CustomCircleView
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/customCircleView"
    android:layout_width="100dp"
    android:layout_height="100dp"
    app:circleColor="@color/blue"
    app:circleRadius="30dp"/>

 

반응형
Comments