LineBreakMeasurer 클래스
LineBreakMeasurer 클래스
LineBreakMeasurer 클래스는 스타일이 적용된 텍스트를 특정 시각적 전진(visual advance) 안에 들어맞는 줄(또는 세그먼트)로 나누는 데 사용돼요. 특정 폭(줄바꿈 폭, wrapping width)에 들어맞는 단락을 표시하려는 클라이언트에게 유용해요.
본문
LineBreakMeasurer는 스타일 텍스트에 대한 반복자(iterator)로 구성돼요. 반복자의 범위는 텍스트의 단락 하나여야 해요. LineBreakMeasurer는 다음 텍스트 세그먼트의 시작 위치를 유지하는데, 처음에는 텍스트의 시작이에요.
public final class LineBreakMeasurer
extends Object
단락에는 양방향 포맷 규칙에 따라 전체 방향(왼쪽에서 오른쪽 또는 오른쪽에서 왼쪽)이 지정돼요. 단락에서 얻은 모든 세그먼트는 단락과 같은 방향이에요.
세그먼트 얻기
텍스트 세그먼트는 nextLayout 메서드를 호출해서 얻어요. 이 메서드는 줄바꿈 폭 안에 들어맞는 텍스트를 나타내는 TextLayout을 반환하고, 현재 위치를 반환된 레이아웃의 끝으로 옮겨요.
LineBreakMeasurer는 가장 흔히 쓰이는 줄바꿈 정책을 구현해요.
- 줄바꿈 폭 안에 들어맞는 모든 단어를 줄에 배치해요.
- 첫 단어가 들어맞지 않으면, 줄바꿈 폭 안에 들어맞는 모든 문자를 줄에 배치해요.
- 각 줄에는 최소 한 문자 이상 배치돼요.
탭 문자
LineBreakMeasurer가 반환한 TextLayout 인스턴스는 탭을 폭 0인 공백처럼 취급해요. 탭으로 구분된 세그먼트를 위치 지정용으로 얻으려면 텍스트에서 제한 오프셋(limiting offset)을 받는 nextLayout 오버로드를 사용해요. 제한 오프셋은 탭 바로 다음의 첫 문자여야 해요. 이 메서드가 반환한 TextLayout 객체는 제공한 제한에서 끝나요(현재 위치와 제한 사이의 텍스트가 줄바꿈 폭 안에 완전히 들어맞지 않으면 그보다 먼저 끝나요).
탭 구분 텍스트를 배치하는 클라이언트는 첫 세그먼트가 줄에 배치된 뒤 약간 다른 줄바꿈 정책이 필요해요. 남은 공간에 부분 단어를 맞추는 대신, 남은 공간에 들어맞지 않는 단어를 통째로 다음 줄에 배치해야 해요. 이 정책 변경은 boolean 파라미터를 받는 nextLayout 오버로드로 요청할 수 있어요.
텍스트 변경 처리
일반적으로 LineBreakMeasurer를 구성한 텍스트가 바뀌면, 변경을 반영하려면 새 LineBreakMeasurer를 구성해야 해요. (기존 LineBreakMeasurer는 계속 작동하지만 텍스트 변경을 인식하지 못해요.) 다만 단일 문자 삽입·삭제라면 insertChar 또는 deleteChar로 기존 인스턴스를 '업데이트'할 수 있는데, 새로 만드는 것보다 훨씬 빠르게 처리할 수 있어요. 사용자 타이핑에 따라 텍스트를 수정하는 클라이언트는 이 메서드들을 활용해야 해요.
주요 메서드
nextLayout(float wrappingWidth)— 줄바꿈 폭에 맞는 다음 세그먼트TextLayout을 반환해요.nextLayout(float wrappingWidth, int offset, boolean requireNextWord)— 제한 오프셋과 단어 단위 정책을 적용하는 오버로드예요.getPosition()/setPosition(int)— 현재 텍스트 위치를 읽고 설정해요.insertChar(AttributedCharacterIterator newParagraph, int insertPos)— 단일 문자 삽입을 반영해요.deleteChar(AttributedCharacterIterator newParagraph, int deletePos)— 단일 문자 삭제를 반영해요.
사용 예제 (단락 렌더링)
public void paint(Graphics graphics) {
float dx = 0f, dy = 5f;
Graphics2D g2d = (Graphics2D)graphics;
FontRenderContext frc = g2d.getFontRenderContext();
AttributedString text = new AttributedString(".....");
AttributedCharacterIterator paragraph = text.getIterator();
LineBreakMeasurer measurer = new LineBreakMeasurer(paragraph, frc);
measurer.setPosition(paragraph.getBeginIndex());
float wrappingWidth = (float)getSize().width;
while (measurer.getPosition() < paragraph.getEndIndex()) {
TextLayout layout = measurer.nextLayout(wrappingWidth);
dy += (layout.getAscent());
float dx = layout.isLeftToRight() ? 0 : (wrappingWidth - layout.getAdvance());
layout.draw(graphics, dx, dy);
dy += layout.getDescent() + layout.getLeading();
}
}