표를 그릴려면 어떻게 해야 할까? 여러가지 방법이 있을 것인데 하나는 큰 박스를 넣은 후 그 안에 선을 그리는 방법이 있을 것이다. 또다른 방법은 박스를 여러개 그리는 것이다. 이를테면 한 줄에 2개의 칸이 있는 2×1 표를 그린다고 해보자. 그러면 긴 박스와 작은 박스를 겹쳐서 그리면 될 것이다. 나는 선을 그리는 방법보다는 박스를 겹치는 방법을 선택했다.
왜냐하면 위의 소개 그림에서도 보듯이 셀에 음영을 넣는 경우가 생길텐데, 음영을 넣으려면 이 역시 박스를 그리는 방식으로 진행된다. 따라서 선을 그리고 음영을 넣는다는 것은 중복된 일을 하는 것가 마차가지가 되는 것이다. 그리고 박스를 중첩하는 방식으로 표를 만들면, 각 셀 안에 들어간 텍스트의 위치를 계산하는 것도 쉽다.
표를 그리려면 기준점이 있어야 한다. 좌측 상단을 기준점으로 잡는 것이 통상적이고, 가장 이해하기 쉬울 것이다. 좌측 상단을 기준으로 2개의 박스를 겹쳐서 1줄짜리 표를 그리면 다음과 같이 될 것이다.
따라서 다음의 코드가 될 것이다.
/** 변수 **/ val cellHeight = 30 // Row Height : 40 val columnWidth = 180f // 내부선 val vcOffset = 4f // 세로 중간을 맞추기 위한 오프셋 // Rect canvas.drawRect(currentPOS.X.toFloat(), currentPOS.Y.toFloat(), endOfBody, currentPOS.Y.toFloat() + cellHeight, linePaint) // 첫쨰 줄 canvas.drawRect(currentPOS.X.toFloat(), currentPOS.Y.toFloat(), currentPOS.X.toFloat() + columnWidth, currentPOS.Y.toFloat() + cellHeight, linePaint) // 제목박스
여기서 endOfBody는 본문 영역의 너비를 말한다. 사전에 다음과 같이 정의되었다.
// 여백 val marginTop = 42 val marginBottom = 50 val marginLeft = 47 val marginRight = 48 // end of 본문 val endOfBody = (PDF_PAGE_WIDTH - marginRight).toFloat()
이러한 셀들을 여러개를 연결하면 표가 될 것이다.
각 셀의 좌측상단을 기준점으로 잡았으므로 글자는 이를 기준으로 상대 좌표를 구하면 된다.
만약 셀안에 가로정렬을 한다고 해보자. 셀 안의 가운데 점을 잡아야 하므로
가로좌표는 기준점 + (cellwidth) / 2가 될 것이다. 세로좌표는 기준점 + (cellHeight) / 2가 될 것이다.
따라서 셀 안에 글자를 집어 넣는 것은 다음 코드가 될 것이다.
// Text canvas.drawText(header, currentPOS.X.toFloat() + columnWidth / 2, currentPOS.Y.toFloat() + cellHeight / 2 + vcOffset, cellHeaderLight) canvas.drawText(body, currentPOS.X.toFloat() + columnWidth + (endOfBody - (currentPOS.X + columnWidth)) / 2, currentPOS.Y.toFloat() + cellHeight / 2 + vcOffset, cellBody)
참고로 세로좌표의 경우에는 오프셋을 추가하였는데, 이는 글자의 베이스라인은 좌측하단에 있기 때문이다.
안드로이드의 폰트메트릭스에 대해서는 이전 포스팅을 참고하라.
이 포스팅의 서두부분에 나온 표를 그린다면 다음의 코드를 사용하면 될 것이다.
// 표 : 고소인 fun tablePlaintiff(canvas: Canvas) { /** 변수 **/ val cellHeight = 30 // Row Height : 40 val columnWidth = 60f // 내부선 val secondColumn = 260f // 두번쨰 열 val vcOffset = 4f // 세로 중간을 맞추기 위한 오프셋 plaintiffList?.forEach() { // 첫째 행 // Rect canvas.drawRect(currentPOS.X.toFloat(), currentPOS.Y.toFloat(), endOfBody, currentPOS.Y.toFloat() + cellHeight, linePaint) // 첫쨰 줄 canvas.drawRect(currentPOS.X.toFloat(), currentPOS.Y.toFloat(), currentPOS.X.toFloat() + columnWidth, currentPOS.Y.toFloat() + cellHeight, cellFill) // 제목박스 canvas.drawRect(currentPOS.X.toFloat() + secondColumn, currentPOS.Y.toFloat(), currentPOS.X.toFloat() + secondColumn + columnWidth, currentPOS.Y.toFloat() + cellHeight, cellFill) // 두번째 제목박스 // Text canvas.drawText("이 름", currentPOS.X.toFloat() + columnWidth / 2, currentPOS.Y.toFloat() + cellHeight / 2 + vcOffset , cellHeader) canvas.drawText(it.pName, currentPOS.X.toFloat() + columnWidth + (secondColumn - columnWidth) / 2, currentPOS.Y.toFloat() + cellHeight / 2 + vcOffset, cellBody) canvas.drawText("주민번호", currentPOS.X.toFloat() + secondColumn + columnWidth / 2, currentPOS.Y.toFloat() + cellHeight / 2 + vcOffset, cellHeader) // 2번쨰 칸 canvas.drawText(it.socialNumber, currentPOS.X.toFloat() + secondColumn + columnWidth + (endOfBody - (currentPOS.X + secondColumn + columnWidth)) / 2, currentPOS.Y.toFloat() + cellHeight / 2 + vcOffset, cellBody) // 둘재 행 // Rect canvas.drawRect(currentPOS.X.toFloat(), currentPOS.Y.toFloat() + cellHeight, endOfBody, currentPOS.Y.toFloat() + cellHeight * 2, linePaint) // 둘쨰 줄 canvas.drawRect(currentPOS.X.toFloat(), currentPOS.Y.toFloat() + cellHeight, currentPOS.X.toFloat() + columnWidth, currentPOS.Y.toFloat() + cellHeight * 2, cellFill) // 제목박스 // Text canvas.drawText("주 소", currentPOS.X.toFloat() + columnWidth / 2, currentPOS.Y.toFloat() + cellHeight * 1 + cellHeight / 2 + vcOffset, cellHeader) canvas.drawText(it.pAddress, currentPOS.X.toFloat() + columnWidth + (endOfBody - (currentPOS.X + columnWidth)) / 2, currentPOS.Y.toFloat() + cellHeight * 1 + cellHeight / 2 + vcOffset, cellBody) // 셋쨰 행 // Rect canvas.drawRect(currentPOS.X.toFloat(), currentPOS.Y.toFloat() + cellHeight * 2, endOfBody, currentPOS.Y.toFloat() + cellHeight * 3, linePaint) // 셋쨰 줄 canvas.drawRect(currentPOS.X.toFloat(), currentPOS.Y.toFloat() + cellHeight * 2, currentPOS.X.toFloat() + columnWidth, currentPOS.Y.toFloat() + cellHeight * 3, cellFill) // 제목박스 // Text canvas.drawText("연 락 처", currentPOS.X.toFloat() + columnWidth / 2, currentPOS.Y.toFloat() + cellHeight * 2 + cellHeight / 2 + vcOffset, cellHeader) // 제목 canvas.drawText(it.pPhoneNumber, currentPOS.X.toFloat() + columnWidth + (endOfBody - (currentPOS.X + columnWidth)) / 2, currentPOS.Y.toFloat() + cellHeight * 2 + cellHeight / 2 + vcOffset, cellBody) // 내용 // 아래 여백 totalPOS += POS(0, cellHeight * 3 + 20) currentPOS += POS(0, cellHeight * 3 + 20) }?:{ canvas.drawRect(currentPOS.X.toFloat(), currentPOS.Y.toFloat(), endOfBody, currentPOS.Y.toFloat() + cellHeight, linePaint) // 첫쨰 줄 canvas.drawText("당사자 정보가 없습니다. 당사자를 추가했는지 확인하세요!", currentPOS.X.toFloat() + endOfBody / 2, currentPOS.Y.toFloat() + cellHeight / 2 + vcOffset , cellHeader) // 아래 여백 linefeed() } }