텀블러로 블로그를 옮깁니다. by 오리대마왕

블로그를 옮긴다 옮긴다 하다 이제 진짜로 옮깁니다.


이글루스는 다른 기능은 모르겠고, 일단 글 쓰기가 너무 귀찮고 지난 몇년 동안 아무런 개선이 없었으며, 앞으로도 개선의 여지가 없어보이네요.

기술 글을 쓰려면 code 붙여넣기나 여러 링크를 적어야 하는데 이글루스에선 이런 작업에 너무 손이 많이 갑니다. 그래서 이 참에 markdown을 지원하는 텀블러로 옮겨탔습니다.

안녕~ 이글루스!

공유하기 버튼

 
 

안드로이드, TextView에 볼드 먹인 emoji가 제대로 표현되지 않는 문제 우회하기 by 오리대마왕

TextView에 emoji를 먹인 텍스트를 적용할 경우, 대부분 잘 보여준다. 폰트가 영 엉망이 아닌 이상 말이지.
하지만 여기에 bold를 먹일 경우 삼성 갤럭시 S3의 기본 폰트에선 줄 쳐진 네모 박스가 나와버린다.

이 경우 생각해 볼 수 있는 대안은 다음과 같다.

1. 냅둔다.
2. 전체 bold를 빼버린다.
3. 이모지 들어간 부분만 bold를 빼버린다.
4. 아싸리 앱에 폰트를 하나 심어두고, 볼드 처리된 emoji가 들어감직한 부분엔 저 폰트를 사용한다.
5. fakebold 플래그를 사용한다.

하나하나 살펴보자.

1. 냅둔다.

깨져보이던 말던 알게 뭐야. 아니 왜 저런 꾸진 폰트를 쓰니, 좋은 폰트를 쓰지! 그리고 왜 이모지를 사용하고 그래!!!
하지만 사장님이 싫어한다.

2. 전체 bold를 빼버린다.

좀 아쉽지만 디자이너와 쇼부쳐서 볼드를 빼자고 꼬드긴다.

3. 이모지 들어간 부분만 bold를 빼버린다.

얼핏 최고의 솔루션같지만, 막상 구현해보려면 굉장히 손이 들어간다. 한 택스트 안에 Spannable을 부분부분 먹여야 할 터이니.

4. emoji 들어감직한 textview에 custom font를 먹인다.

사용자가 선택한 폰트가 아닌 다른 폰트가 사용된다는 문제가 있다. 이것도 문제지만 어지간한 폰트는 수 메가에 달하기 때문에 용량면에서도 일단 꽝. emoji만을 포함한 font( 일례로 쉽게 구할 수 있는 AndroidEmoji.ttf 는 400kb 남짓된다.)를 사용하고 나머지 글자 표현은 기본 폰트를 이용한다면 되지 싶기도 하다. 그런데 내가 뭘 잘못했는지 좀 잘 안되더라.

5. fakebold 플래그를 사용한다.

굉장히 쉬운 방법이다. TextView.getPaint().setFakeBoldText(true); 를 먹이면 된다. 왜 짜가 bold냐면 bold에 해당하는 폰트를 사용해서 bold를 표현하는게 아닌, 기본 폰트를 찐하게 만들어서 bold를 표현하기 때문이다. 이렇게 해서 갤S3 에 올려보면 이모지들이 표현되긴 한데, normal 표현에 비해 세부 표현이 좀 뭉게진다. 예를 들어 웃는 안드로이드 얼굴의 눈이 사라진다거나 하는. 하지만 네모박스보단 훨 낫잖아!

위의 결론을 보면 알겠지만 fakebold 플래그 사용하는게 약간은 아쉽지만 쉬운 선택이라 볼 수 있다. 완벽을 추구하겠다면 3번 같이 Spannable을 부분 부분 먹이면 될 터이고. 

fakebold를 쓴다면 텍스트에 emoji가 포함될 경우에만 먹이는 게 좋겠지. 아무래도 bold 폰트를 사용하는게 fakebold를 먹이는 것 보다 이쁠테니까. 그럼 텍스트에 emoji가 포함되었는지 여부는 어찌 알아낼까 하는 부분이 다음 문제이다.

wikipedia의 emoji unicode 코드표를 보면 emoji에 해당하는 code point는 대략 U+1F300 부터 U+1F6FF 라고 보면 된다. 자, 그럼 String의 char를 iteration돌면서 각 글자가 저 영역에 해당하는지만 보면 될 것 같은데 char는 16bit이고 저 영역은 32bit로 표현하는 영역이라 제대로 동작하지 않는다.
32bit code point까지 제대로 접근하려면 String.codePointAt() 메서드를 사용해야 한다. 이 경우에도 iteration은 char 단위로 돌기 때문에 중간 중간 low surrogate에 해당하는 code point가 튀어나오지만 이런 문제는 그냥 무시하고, 하여간 emoji 에 해당하는 code point 값이 들어있는지만 확인하자면 다음과 같이 코딩하면 된다.



private static final int emojiStartCodePoint = 0x1F300;
private static final int emojiEndCodePoint = 0x1F6FF;

public static boolean isStringContainsEmoji(String text) {
for (int i = 0; i < text.length(); i++) {
int codePoint = text.codePointAt(i);
if (codePoint >= emojiStartCodePoint && codePoint <= emojiEndCodePoint) {
return true;
}
}
return false;
}


이렇게 text에 emoji가 들어갔는지 판단해서 들어갔다면 fakeBold를 먹이면 될 터이다. 대충 이렇게 만들면 되겠지?


if( isStringContainsEmoji(myText)) {
tv.setTypeface(null, Typeface.NORMAL);
tv.getPaint().setFakeBoldText(true);
} else {
tv.setTypeface(null, Typeface.BOLD);
tv.getPaint().setFakeBoldText(false);
}

공유하기 버튼

 
 

1 2 3 4 5 6 7 8 9 10 다음