천복만복 프로그래밍/천복만복 안드로이드

ShapeDrawable

U&MeBlue 2022. 2. 1. 23:03

Shape Drawable

ShapeDrawable 은 2차원 그래픽을 동적으로 그려야할 때 요긴하게 사용할 수 있다. 프로그래밍을 통해서 기본적인 도형을 ShapeDrawable 상에 그릴 수 있고, 원하는 스타일 요소도 적용할 수 있다.

ShapeDrawable  Drawable 의 서브클래스이기 때문에 Drawable 가 사용되는 곳에서 ShapeDrawable 역시 사용 가능하다. 예를 들어 어떤 view 의 setBackgroundDrawable 메소드를 통해서 ShapeDrawable 을 배경으로 설정할 수 있다. 또한 커스텀 뷰 안에서 ShapeDrawble 을 그리게 하고, 커스텀 뷰를 레이아웃에 추가시킬 수도 있다.

ShapeDrawable 은 내부적으로 draw() 메소드를 가지고 있기 때문에 View 클래스를 상속하는 커스텀 뷰를 만든 뒤에 onDraw() 메소드에서 ShapeDrawable  draw() 메소드를 호출하여 2차원 그래픽을 그리는 뷰를 구현할 수도 있다. 다음은 그 예이다.

class CustomDrawableView(context: Context) : View(context) {
    private val drawable: ShapeDrawable = run {
        val x = 10
        val y = 10
        val width = 300
        val height = 50
        contentDescription = context.resources.getString(R.string.my_view_desc)

        ShapeDrawable(OvalShape()).apply {
            // If the color isn't set, the shape uses black as the default.
            paint.color = 0xff74AC23.toInt()
            // If the bounds aren't set, the shape can't be drawn.
            setBounds(x, y, x + width, y + height)
        }
    }

    override fun onDraw(canvas: Canvas) {
        drawable.draw(canvas)
    }
}

이제 코드상에서 다른 커스텀 뷰를 사용하는 것처럼 위 커스텀 뷰도 자유롭게 사용할 수 있다.

private lateinit var customDrawableView: CustomDrawableView

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    customDrawableView = CustomDrawableView(this)

    setContentView(customDrawableView)
}

ShapeDrawable  android.graphics.drawable 패키지의 드로어블 클래스들과 같이 public method 들을 통해서 컬러, 투명도, dither, 불투명도 등을 적용할 수 있다.

ShapeDrawable 은 기본적으로 Shape 객체를 전달받으며, screen 상엣의 해당 Shape 객체를 관리한다. 어떤 Shape 도 주어지지 않는다면 기본적으로 RectShape 를 취한다.

ShapeDrawable 왜 사용할까?

Canvas 객체를 이용하면 ShapeDrawable 을 사용하지 않고도 다양한 2차원 도형을 그릴 수가 있는데 왜 ShapeDrawable 을 굳이 사용하는 걸까? ShapeDrawable 을 사용하면 공통적으로 재사용 될 수 있는 어떤 모양(Shape)에 대해서 해당 Shape 를 그리는 작업을 독립적인 객체로 분리해서 작성할 수 있기 때문이다. Canvas 의 메소드를 순차적으로 작성한 코드의 형태는 imperative 하기 때문에 해당 코드들의 최종적으로 나타내고자 하는 형태를 한 눈에 알아보기 어렵다. 어떤 형태를 ShapeDrawable 로 만들어서 그리면 해당 클래스의 이름을 통해 이 드로어블이 어떤 형태를 그리고자 하는 건지 한 눈에 알아보기 쉽기 때문에 사용하는 것 같다.

예제

class SquareRoundedDrawable : ShapeDrawable {
    private val cornerRadius = 18f

    private val fillPaint = paint
    var checked = false

    constructor(view: View) : super(RectShape()) {
        fillPaint.isAntiAlias = true
    }

    override fun onDraw(shape: Shape, canvas: Canvas, fillPaint: Paint) {
        canvas.drawRoundRect(RectF(0f, 0f, shape.width, shape.height), cornerRadius, cornerRadius, fillPaint)
    }

    fun setFillColor(color: Int) {
        fillPaint.color = color
    }
}

...

val shape = SquareRoundedDrawable(view)
view.setBackgroundDrawable(shape)

참고자료

728x90