今回はスクロール機能を実装した。
方向は垂直方向のみ。水平方向へはそのうち実装する予定。変更を加えたのはEditorViewとRowRulerのみ。
まずはEditorViewの描画部分から。描画位置drawYをあらかじめ垂直スクロール位置を引いた状態にしておく(drawText内)。そして、drawString内でテキストが画面内にあるかどうか確認して、画面内であれば描画フラグを立てる。drawCharacterは描画フラグを受けとるようにして、フラグが立ってる場合のみ文字の描画を行う
//テキストを描画する private void drawText(Canvas canvas, String text, TextPaint paint){ paint.setTextSize(fontSize); String token; TextTokenizer tokenizer = new JavaTokenizer(text.toCharArray()); int drawX = 0; //描画位置は垂直スクロール位置を引いた場所 int drawY = fontSize - viewInfo.getInt(ConstName.SCROLL_Y); 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(); int height = viewInfo.getInt(ConstName.EDITOR_HEIGHT); //テキストが画面内にあれば描画用フラグを立てる boolean isDraw = 0 <= drawY && drawY <= height ? true : false; //テキストを描画する場合の色設定 if(isDraw){ //渡された文字列がキーワードに登録されてるなら //関連付けられた色で描画する 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, isDraw); } paint.setColor(srcColor); return drawX; } //一文字描画して次の文字の描画位置を返す private int drawCharacter(Canvas canvas, char c, int drawX, int drawY, TextPaint paint, boolean isDraw){ String drawChar = Character.toString(c); //テキストを描画する場合、この文字を描画する if(isDraw){ canvas.drawText(drawChar, 0, 1, drawX, drawY, paint); } drawX += (int)paint.measureText(drawChar, 0, 1); return drawX; }
次にRowRuler。drawLineNumberのみの変更。描画する範囲を計算して、その範囲の部分だけ行番号を描画する。
//行番号描画 private void drawLineNumber(Canvas canvas, int width, int height, ViewInfo viewInfo, TextPaint paint){ int srcColor = paint.getColor(); int fontSize = viewInfo.getInt(ConstName.EDITOR_FONT_SIZE); int scrollY = viewInfo.getInt(ConstName.SCROLL_Y); paint.setColor(Color.BLACK); //描画を行う範囲を設定 int top = scrollY; int bottom = height + scrollY + fontSize; //最初に描画する行番号を計算 int row = (top / fontSize) - 1; //実際に描画する座標を計算 int drawY = (fontSize - (scrollY % fontSize)) - fontSize; for(int y = top; y <= bottom; y += fontSize){ String rowNumber = String.format("%0" + place + "d", ++row); int x = alignRight(rowNumber, width, paint); canvas.drawText(rowNumber, x, drawY, paint); drawY += fontSize; } //このメソッドが呼ばれる前の色に戻す paint.setColor(srcColor); }
最後にタッチイベントでスクロールするようにする。ただし、これはAndroidのスクロール動作と違うけど、今はこれぐらいの動作にしておく
@Override public boolean onTouchEvent(MotionEvent event){ switch(event.getAction()){ case MotionEvent.ACTION_DOWN: touchX = (int)event.getX(); touchY = (int)event.getY(); break; case MotionEvent.ACTION_MOVE: int currentX = (int)event.getX(); int currentY = (int)event.getY(); int scrollX = viewInfo.getInt(ConstName.SCROLL_X); int scrollY = viewInfo.getInt(ConstName.SCROLL_Y); scrollX -= (currentX - touchX); scrollY -= (currentY - touchY); scrollY = scrollY < 0 ? 0 : scrollY; viewInfo.put(ConstName.SCROLL_X, scrollX); viewInfo.put(ConstName.SCROLL_Y, scrollY); touchX = (int)event.getX(); touchY = (int)event.getY(); invalidate(); break; } return true; }