フリープログラマー日記

iOS,アンドロイド開発を気ままにしながら生きてるおじさんのブログです。

第22回 Androidでスクロールビュー

ちょっと、イベントがあり、留守にしてました。
早速ですが、続きで、スクロールビューの設置。

Android版で注意するべきことが一つあり、スクロールビューにのせることができるのは一つのオブジェクトになっているということです。なので、中に入れるレイアウトを、リラティブレイアウト を利用することにしました。個人的な趣味により、リニアレイアウトは使いません。

では、まず、一人分の Runnerクラスから。

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;

public class Runner extends View {

    int myWidth;
    int myHeight;

    final float lineWidth;
    final int myNumber;

    String name = "未登録";        //氏名表示
    Boolean entry = false;         // エントリーしたか?


    public Runner(Context context, int number, int width, int height) {
        super(context);
        myNumber = number;
        myWidth = width;
        myHeight = height;

        lineWidth = width * 0.01f;

        setBackgroundColor(Color.argb(255,255,255,180));

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        final float numberWidth = myWidth * 0.22f;

        // アンドロイドではcanvasを使用する,canvasは呼び出し元にあるので引数で受け取る

        // android では Paintクラスを使って色やスタイルを決めていく
        Paint paint = new Paint();

        // 両サイド
        paint.setStrokeWidth(lineWidth);
        paint.setColor(Color.BLACK);
        canvas.drawLine(lineWidth/2, 0, lineWidth/2, myHeight,paint);
        canvas.drawLine(myWidth-lineWidth/2, 0, myWidth-lineWidth/2, myHeight,paint);

        // 上下サイド
        paint.reset();
        paint.setColor(Color.BLACK);
        paint.setStrokeWidth(lineWidth*0.3f);
        canvas.drawLine(0,lineWidth*0.15f,myWidth,lineWidth*0.15f,paint);
        canvas.drawLine(0,myHeight-lineWidth*0.15f,myWidth,myHeight-lineWidth*0.15f,paint);

        // 見た目が悪いので、最初の分だけ上の線を太く。
        if (myNumber == 1) {
            paint.reset();
            paint.setStrokeWidth(lineWidth*0.8f);
            paint.setColor(Color.BLACK);
            canvas.drawLine(0,lineWidth*0.4f,myWidth,lineWidth*0.4f,paint);
        }

        // 中間の仕切り線
        paint.reset();
        paint.setColor(Color.BLACK);
        paint.setStrokeWidth(lineWidth*0.6f);
        canvas.drawLine(numberWidth,0.0f,numberWidth,myHeight,paint);

        // 番号の描画
        paint.reset();
        if (name=="未登録") {
            paint.setColor(Color.LTGRAY);
        } else {
            paint.setColor(Color.BLACK);
        }
        paint.setTextSize(myHeight*0.5f);
        paint.setTextAlign(Paint.Align.CENTER);
        final String number = String.valueOf(myNumber);
        canvas.drawText(number,numberWidth*0.5f,myHeight*0.7f,paint);

        paint.setTextSize(myHeight*0.6f);
        paint.setTextAlign(Paint.Align.CENTER);
        canvas.drawText(name,numberWidth*0.5f+myWidth*0.5f,myHeight*0.7f,paint);

    }
}

途中で、entryというBooleanの変数が入っていますが、これはまだ使っていません。いずれ使うことになるだろうなと思いながら書いています。

だいたい、オブジェクト指向プログラムというのは、オブジェクトにその属性となる変数(プロパティ)や関数(メソッド)を入れるものだから、このRunnerオブジェクトというのは、名前、タイム、周回数、タイム、エントリーの状況、ボタンの位置など様々なプロパティを持つことが予想されます。ただ、心配な状況として、エントリーが終わると廃棄されるのか、そもそも、Viewオブジェクトでいいのか?みたいなちょっと心配な状況があります。

この辺りが、教科書にない自分で考えなければならないところなんですよね。

さて、続いて、スクロールビューのクラスですが、インナークラスとしてリラティブレイアウト を入れました。おかしいかもしれませんが、スクロールビューのコードが少ないのでいい感じです。

import android.content.Context;
import android.widget.RelativeLayout;
import android.widget.ScrollView;

public class RunnerList extends ScrollView {

    /**
     * このクラスはスクロールビューの中におくものとして作成
     * 内部クラスとして一つのリラティブレイアウト を作成し
     * スクロールビューにのせる
     */

    // 一人分のサイズ
    private int aWidth;
    private int aHeight;

    // このクラスには選手名のリストが必要

    // 暫定的に50人いるとして、ビューを作成
    private int member = 50;


    // コンストラクタ
    public RunnerList(Context context,int width, int height) {
        super(context);

        aWidth = width;
        aHeight = height;

        RunnerLayout runnerLayout = new RunnerLayout(getContext());

        addView(runnerLayout);
    }


    class RunnerLayout extends RelativeLayout {


        // コンストラクタ
        public RunnerLayout(Context context) {
            super(context);

            for (int i=1; i<=member; i++) {

                final Runner runner = new Runner(getContext(),i,aWidth,aHeight);
                runner.setId(i);        // ビューにidセット

                // Androidの位置決めはレイアウトパラメータで指定する
                RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
                        aWidth,aHeight);

                if (i == 1) {
                    // 1番目のビューは親ビューを基準にする
                    params.addRule(RelativeLayout.CENTER_IN_PARENT);
                    params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
                } else {
                    // 2番目以降は前のビューを基準にする
                    params.addRule(RelativeLayout.CENTER_IN_PARENT);
                    params.addRule(RelativeLayout.BELOW,i - 1);
                }

                addView(runner,params);

            }
        }
    }
}

Runnerビューを縦にずらずらっと並べるのですが、idをセットし、一つ前のビューの真下に順番に置いています。多分これがいいやり方だと思うのですが。
なお、1番目だけは、親ビューを基準にしています。

そして、スクロールビューでは Addview するだけで終わっています。

このクラスの呼び出しは、前に作ったEntryViewにおきます。(ボタン配置の後)

        addView(buttons,buttonsParams);

        // スクロールビュー設置
        // 一人分のサイズ
        final int aWidth = myWidth*80/100;
        final int aHeight = myWidth*13/100;

        final RunnerList runnerList = new RunnerList(getContext(),aWidth,aHeight);

        RelativeLayout.LayoutParams runnerListParams = new RelativeLayout.LayoutParams(
                myWidth*80/100, myHeight-myWidth*40/100
        );
        runnerListParams.addRule(CENTER_IN_PARENT);
        runnerListParams.addRule(CENTER_IN_PARENT);

        addView(runnerList,runnerListParams);
    }
}

もう一つ悩みが・・・
int と float が混ざりすぎてて厄介ですよね?
ちょっと課題です。

結果としてはほぼ同じ状態となりました。

f:id:momonga117:20180522111553p:plain