マイペースなプログラミング日記

DTMやプログラミングにお熱なd-kamiがマイペースに書くブログ

簡易テキストエディタ作成 その5

今回はスクロール機能を実装した。

方向は垂直方向のみ。水平方向へはそのうち実装する予定。変更を加えたのは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;
}