前回は単純にテキストを表示するだけだったが、今回はキーワードに色を付けて表示するようにした。今回のスクリーンショットを載せる。
今回はTextTokenizerとJavaTokenizerというクラスを作り、前回作ったEditorViewを編集した。プロジェクトのソースコードはこんな感じで配置している
まずはTextTokenizer。こいつはabstractなクラスで、これから作るであろう様々なTokenizerのスーパークラス。解析する文字の配列をコンストラクタで受け取り、abstractなgetNextTokenメソッドを定義している
package text.edit.token; public abstract class TextTokenizer { protected final char[] text; protected int index; protected TextTokenizer(char[] text){ this.text = text; index = 0; } public abstract String getNextToken(); }
次にJavaTokenizer。これはJavaのソースコードを解析するためのクラス。解析とは言っても区切り文字で分割してるだけだけど…。このクラスのgetNextTokenメソッドで返された文字列をEditorViewで描画し、特定のキーワードなら色分けするようにする
package text.edit.token; import java.util.Set; import java.util.HashSet; public class JavaTokenizer extends TextTokenizer{ private int index; private static final Set<Character> SEPARATOR_SET; static{ SEPARATOR_SET = new HashSet<Character>(); SEPARATOR_SET.add('.'); SEPARATOR_SET.add('('); SEPARATOR_SET.add(')'); SEPARATOR_SET.add('['); SEPARATOR_SET.add(']'); SEPARATOR_SET.add(' '); SEPARATOR_SET.add('\t'); SEPARATOR_SET.add('\n'); } public JavaTokenizer(String text){ super(text.toCharArray()); } public JavaTokenizer(char[] text){ super(text); } public String getNextToken(){ String token = null; StringBuilder tokenBuilder = new StringBuilder(); while(true){ if(index >= text.length){ break; } char tokenc = text[index]; if(SEPARATOR_SET.contains(tokenc)){ if(tokenBuilder.length() == 0){ //区切り文字だけの場合 tokenBuilder.append(tokenc); index++; break; }else{ break; } }else{ //区切り文字じゃなければトークンの文字として追加 tokenBuilder.append(tokenc); } index++; } //トークンがあればStringにして返す if(tokenBuilder.length() > 0){ token = tokenBuilder.toString(); } return token; } }
次にEditorView。initColorMapでキーワードとそのキーワードの色をMapに追加している。drawTextでTokenizerを使ってテキストを分割し、drawStringでキーワードの色分けを行い描画をしている
package text.edit.view; import java.util.Map; import java.util.HashMap; import android.view.View; import android.content.Context; import android.graphics.Color; import android.graphics.Canvas; import android.text.TextPaint; import text.edit.document.TextDocument; import text.edit.token.TextTokenizer; import text.edit.token.JavaTokenizer; public class EditorView extends View{ private int fontSize; private TextDocument document; private Map<String, Integer> colorMap; public EditorView(Context context){ super(context); fontSize = 16; document = new TextDocument(); setBackgroundColor(Color.WHITE); initColorMap(); } private void initColorMap(){ colorMap = new HashMap<String, Integer>(); //キーワードと色の関連付け colorMap.put("import", Color.BLUE); colorMap.put("public", Color.BLUE); colorMap.put("class", Color.BLUE); colorMap.put("static", Color.RED); colorMap.put("String", 0xFF008000); colorMap.put("void", 0xFF008000); } public void setText(String text){ document.setText(text); invalidate(); } @Override protected void onDraw(Canvas canvas){ drawText(canvas, document.getText()); } //テキストを描画する private void drawText(Canvas canvas, String text){ TextPaint paint = new TextPaint(); paint.setTextSize(fontSize); String token; TextTokenizer tokenizer = new JavaTokenizer(text.toCharArray()); int drawX = 0, drawY = fontSize; while((token = tokenizer.getNextToken()) != null){ if(token.equals("\n")){ drawX = 0; drawY += fontSize; }else{ drawX = drawString(canvas, token, drawX, drawY, paint); } } } //文字列を描画して次の文字列を描画する位置を返す private int drawString(Canvas canvas, String text, int drawX, int drawY, TextPaint paint){ int srcColor = paint.getColor(); //渡された文字列がキーワードに登録されてるなら //関連付けられた色で描画する if(colorMap.containsKey(text)){ paint.setColor(colorMap.get(text)); }else{ paint.setColor(Color.BLACK); } for(char c : text.toCharArray()){ drawX = drawCharacter(canvas, c, drawX, drawY, paint); } paint.setColor(srcColor); return drawX; } //一文字描画して次の文字の描画位置を返す private int drawCharacter(Canvas canvas, char c, int drawX, int drawY, TextPaint paint){ String drawChar = Character.toString(c); canvas.drawText(drawChar, 0, 1, drawX, drawY, paint); drawX += (int)paint.measureText(drawChar, 0, 1); return drawX; } }
最後にActivity。ただ、表示する文字列を変えただけ
package text.edit; import android.app.Activity; import android.os.Bundle; import text.edit.view.EditorView; public class TextEditorTest extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); EditorView editor = new EditorView(this); StringBuilder text = new StringBuilder(); text.append("import java.util.List;\n\n"); text.append("public class Main{\n"); text.append(" public static void main(String[] args){\n"); text.append(" }\n"); text.append("}"); editor.setText(text.toString()); setContentView(editor); } }