Androidで縦書きを実現する
androidのTextViewは縦書きには対応していません。
縦書きを実現するためには自分で実装するしかありません。
縦書きについてさっぱり知らない状態から実装しました。
twitterでのやりとり
Togetter - 「Android縦書き」 http://togetter.com/li/92001
誤っている箇所があれば指摘お願いします!
完成はこんな感じです。
参考にしたサイト
字体 - Wikipedia http://ja.wikipedia.org/wiki/%E5%AD%97%E4%BD%93
グリフがフォント1文字分、グリフがたくさん集まってフォントという単位になる
禁則処理 - Wikipedia http://ja.wikipedia.org/wiki/%E7%A6%81%E5%89%87%E5%87%A6%E7%90%86
行の最初に「、」「。」などの文字が配置される場合、前行の最後に表示するべきという処理
*1
ハイフネーションとは【hyphenation】 - 意味/解説/説明/定義 : IT用語辞典 http://e-words.jp/w/E3838FE382A4E38395E3838DE383BCE382B7E383A7E383B3.html
英語版禁則処理みたいなもの
行をまたいで英単語を描画する場合ハイフンを使って繋ぐ
*2
ルビ - Wikipedia http://ja.wikipedia.org/wiki/%E3%83%AB%E3%83%93
ふりがなに使うルビ
*3
[SOLVED] Android: Using Custom Fonts « RussenReaktor's Weblog http://russenreaktor.wordpress.com/2010/04/29/solved-android-using-custom-fonts/
自分で用意したフォントを使う例
assetsには1MBまでしか入りません。この例ではassetsにフォントを入れていますが、これは英字フォントのみだからこそできることです。
日本語のフォントが入っていてると1MBなんて余裕で超えちゃうので別途SDカードに入れてあげる必要があります。
他のAndroid縦書きアプリでは大抵アプリインストール後にダウンロードする仕組みになっています。
テキストの描画(FontMetrics) - Android Wiki* http://wikiwiki.jp/android/?%A5%C6%A5%AD%A5%B9%A5%C8%A4%CE%C9%C1%B2%E8(FontMetrics)
FontMetrixについて
Canvas.drawText()ではbaseLineを基準に描かれます。
簡易禁則入ってるソース - inuchin104がiPhoneと格闘したメモ http://d.hatena.ne.jp/inuchin104/20110121
ちゃんと読めていませんが、
[twitter:@inuchin] さんの作ったDirectXを使ったiPhone用縦書きコードらしいです。
ルビと簡易禁則処理がついているそうです。
Typeface | Android Developers http://developer.android.com/reference/android/graphics/Typeface.html
フォントのクラスです。
Paint | Android Developers http://developer.android.com/reference/android/graphics/Paint.html
getFontから始まるメソッドを見ておくといいです。
基本的な作り
独自Viewを作り、onDrawでCanvas#drawText()を使って文字を縦に並べていきます。
ひらがなや、漢字などのだいたいの文字の表示は大丈夫ですが、横書き用フォントなので「ー」や「、」や「ぁ」などを使った場合表示が狂った様に見えます。特別な小文字や記号などには別途設定を設けて位置を調整するようにします。
横フォント問題の解決法は縦書きビューワを作られている[twitter:@2SC1815J] さんにもご意見頂きました。
実装
独自フォントのロード
Typeface typeface = Typeface.createFromFile(FONT_PATH); Paintm paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setTextSize(FONT_SIZE); paint.setColor(Color.BLACK); paint.setTypeface(typeface); canvas.drawText("こんにちは!", x, y, paint);
このコードを使えば独自フォントを使った文字列を表示する事ができます。
フォントはIPA明朝を使用しました。
IPAフォントのダウンロード || OSS iPedia http://ossipedia.ipa.go.jp/ipafont/index.html
こんにちはの文字は横に表示されていますが、縦書きにするために1文字ずつ描画します。
文字サイズ
テキストを縦に並べるためには1文字のサイズを取得する必要があります。
文字サイズはPaint#getFontSpacing()でピクセルサイズを取得する事ができます。
これを使えば固定ピッチで表示する事が可能です。
行間を1文字分、最初の行を1文字落とす設定で走れメロスの冒頭を表示してみました。
この状態でもけっこう様になってます。
しかし「、」「。」「っ」の位置がおかしいです。
横用フォントのため、位置がおかしく表示されます。
文字位置を調整する
文字位置調整の対象はだいたい思いつくもので
- 記号
- ひらがな小文字
- カタカナ小文字
- アルファベット半角大文字
- アルファベット半角小文字
- アルファベット全角大文字
- アルファベット全角小文字
などがあります。
ひらがな・カタカナ小文字については位置の調整でいいですが、
アルファベット・記号については90度回転する必要があります。
管理が楽になるように設定用のクラスを作っておいてexcelで生成できるようにします。
public class CharSetting { /** * 文字 */ public final String charcter; /** * 回転角度 */ public final float angle; /** * xの差分 * Paint#getFontSpacing() * xが足される * -0.5fが設定された場合、1/2文字分左にずれる */ public final float x; /** * xの差分 * Paint#getFontSpacing() * yが足される * -0.5fが設定された場合、1/2文字分上にずれる */ public final float y; public CharSetting(String charcter, float angle, float x, float y) { super(); this.charcter = charcter; this.angle = angle; this.x = x; this.y = y; } public static final CharSetting[] settings = { new CharSettings("、", 0.0f, 0.7f, -0.6f), new CharSettings("。", 0.0f, 0.7f, -0.6f), new CharSettings("「", 90.0f, -1.0f, -0.3f), new CharSettings("」", 90.0f, -1.0f, 0.0f), new CharSettings("ぁ", 0.0f, 0.1f, -0.1f), new CharSettings("ぃ", 0.0f, 0.1f, -0.1f), new CharSettings("ぅ", 0.0f, 0.1f, -0.1f), new CharSettings("ぇ", 0.0f, 0.1f, -0.1f), new CharSettings("ぉ", 0.0f, 0.1f, -0.1f), new CharSettings("っ", 0.0f, 0.1f, -0.1f), // 略 new CharSettings("V", 90.0f, 0.0f, -0.1f), new CharSettings("W", 90.0f, 0.0f, -0.1f), new CharSettings("X", 90.0f, 0.0f, -0.1f), new CharSettings("Y", 90.0f, 0.0f, -0.1f), new CharSettings("Z", 90.0f, 0.0f, -0.1f), new CharSettings(":", 90.0f, 0.0f, -0.1f), new CharSettings(";", 90.0f, 0.0f, -0.1f), new CharSettings("/", 90.0f, 0.0f, -0.1f), new CharSettings("", 90.0f, 0.0f, -0.1f), new CharSettings(":", 90.0f, 0.0f, -0.1f), new CharSettings(";", 90.0f, 0.0f, -0.1f), new CharSettings("/", 90.0f, 0.0f, -0.1f), new CharSettings(".", 90.0f, 0.0f, -0.1f), }; public static CharSetting getSetting(String character) { for (int i = 0; i < settings.length; i++) { if (settings[i].charcter.equals(character)) { return settings[i]; } } return null; } }
文字を描画する前にCharSetting#getSetting()を呼び、設定があったらその設定通りに描画します。
nullが帰ってきた場合、回転も位置調整もせずに描画します。
コードで表すとこんな感じ
CharSettings setting = CharSettings.getSetting(s); if (setting == null) { canvas.drawText(s, x, y, paint); } else { canvas.save(); canvas.rotate(setting.angle, x, y); canvas.drawText(s, x + fontSpacing * setting.x, y + fontSpacing * setting.y, paint); canvas.restore(); }
また、CharSettingsをたくさん生成しているところはexcelで管理して生成できるようにしました。
CharSettings作成シート https://spreadsheets.google.com/ccc?key=0AmA_8rkF2TwodHIyUWpMdldicVhhMGxZWVItNmQ1UkE&hl=ja&authkey=CK_XjqsK
android縦書き完成
あとは表示位置がおかしい文字の設定を随時追加していったり、
行末に「、」「。」などがくるよう禁則処理したり、
ルビの表示を実装したりすればいいと思います。
特にルビはデータをどのように保持するか、またパースのやり方を考えないといけないので大変かもしれません。