본문 바로가기
안드로이드 개발

Android - Paint, Canvas에서 자동으로 줄바꿈하기

by 아이엔 / ienground 2021. 3. 21.

EditText에서 입력된 값을 받아 Paint를 통해 Canvas에 텍스트를 그리는 경우, 다시 말해 drawText를 하는 경우, 그냥 텍스트를 그리면 한 줄로 길게 그려져서 캔버스를 넘어버립니다(당연하게도). 아니면 직접 EditText에서 엔터를 쳐 준 다음 \n으로 구분해 (split) forEach문으로 그려주는 방법도 있습니다.

 

상당히 귀찮고, 구현도 귀찮습니다. 근데 이제까지는 그렇게 해 왔습니다. 이런 노가다 방법만 있을 것 같지는 않았습니다. 포토샵 보면 width 설정해두면 자동으로 다음 줄로 넘어가던데, 안드로이드 Paint는 그런 거 없나? 있었습니다. 이 포스팅에서는 그 방법을 설명합니다.

 

코드
val text = binding.etChangelog.editText?.text?.toString() ?: ""

val textPaint = TextPaint(Paint.LINEAR_TEXT_FLAG or Paint.ANTI_ALIAS_FLAG)
textPaint.textSize = binding.etTextsize.editText?.text.toString().toInt().toFloat()
textPaint.color = Color.BLACK
textPaint.typeface = gmSansMedium

val textLayout = StaticLayout.Builder.obtain(text, 0, text.length, textPaint, 900)
  .setAlignment(Layout.Alignment.ALIGN_NORMAL)
  .setLineSpacing(0f, 1.2f)
  .setIncludePad(true).build()

canvas.save()
canvas.translate(50f, 350f)
textLayout.draw(canvas)
canvas.restore()

이 코드는 전체 코드이고, 한 줄 한 줄 설명을 곁들여 간단하게 설명하도록 합니다.

 

val text = binding.etChangelog.editText?.text?.toString() ?: ""

첫번째 줄인 변수 text는 아시다시피, EditText의 값을 가져오는 코드입니다. 저는 그냥 EditText는 안 쓰고 TextInputLayout과 TextInputEditText를 사용하고 있습니다.

 

val textPaint = TextPaint(Paint.LINEAR_TEXT_FLAG or Paint.ANTI_ALIAS_FLAG)
textPaint.textSize = binding.etTextsize.editText?.text.toString().toInt().toFloat()
textPaint.color = Color.BLACK
textPaint.typeface = gmSansMedium

TextPaint라는 Paint를 상속받은 클래스가 필요합니다. Paint에서 사용했던 속성들 (textSize, color, typeface 등) 모두 사용 가능하니, 기존에 Paint에서 사용한 속성이 있다면 그대로 가지고 오셔도 됩니다. 참고로, TextPaint 안에 있는 속성은 텍스트를 부드럽게 보이게 하는 속성입니다.

 

val textLayout = StaticLayout.Builder.obtain(text, 0, text.length, textPaint, 900)
  .setAlignment(Layout.Alignment.ALIGN_NORMAL)
  .setLineSpacing(0f, 1.2f)
  .setIncludePad(true).build()

핵심인데, StaticLayout이라는 도구를 이용해서 텍스트를 그려줄 거에요. 찾아보니 예전에는 이런 식으로 Builder를 이용해 만들지 않았는데, API 27인가부터 이렇게 바뀌었으니 참고하시면 좋겠습니다. 인자를 하나하나 설명드리면 입력되는 내용 text, 텍스트 시작, 텍스트 길이, 그리고 TextPaint 인자와 너비(px)입니다.

 

setAlignment는 생각하시는 대로 정렬이고, Layout.Alignment 내에 ALIGN_CENTER, ALIGN_NORMAL, ALIGN_OPPOSITE가 있습니다. 가로 기준으로 가운데 정렬, 왼쪽 정렬, 오른쪽 정렬인 것으로 보입니다.

 

LineSpacing도 설정할 수 있는데, 인자가 float spacingAdd, float spacingMult입니다. 왼쪽에는 수치, 오른쪽 인자는 글자 크기 대비입니다.

 

setIncludePad는 뭔지 몰라서 찾아보니 Pad가 Padding의 약자였습니다. 글자 위아래에 간격을 추가하는 함수였는데, 한국어나 영어는 true false 굳이 상관없는 것 같습니다.

 

canvas.save()
canvas.translate(50f, 350f)
textLayout.draw(canvas)
canvas.restore()

이제 캔버스에 붙일 차례인데, translate 없이 그리게 되면 (0, 0) 자리에 그려지게 됩니다. 따라서 위 과정을 거쳐야 해요. canvas.save() 함수 호출 후 translate(x, y) 를 해준 다음 그리고 제자리로 돌려놓게 되면, 왼쪽 상단 기준 x, y만큼 떨어진 곳에 텍스트가 그려지게 됩니다.

 

감사합니다.