iosched の中の Workspace (2)

onQueryComplete メソドについていくつか確認。

  • NotifyingAsyncQueryHandler は AsyncQueryHandler を継承してます
    • onQueryComplete 呼び出しのあたりの記述は移譲という観点で非常に参考になる実装になってますね
  • NotifyingAsyncQueryHandler#startQuery を呼び出してるのは requery メソド
  • requery を呼び出してるのは onResume メソド
  • startQuery を kickoff して終了した時点で onQueryComplete が呼び出されるはず

で、基本的には onQueryComplete メソドで ContentProvider から戻ってきたデータの一群に対して BlockView なオブジェクトをこしらえて取り出した値をオブジェクトに設定して Day オブジェクトが持ってるコンテナの BlocksLayout なオブジェクトにに追加をしている模様。

BlocksLayout クラス

ViewGroup のサブクラスです。コンテナ View として onLayout メソッド内で addView された View を取り出して View#layout メソドで配置している模様。
ええと、View の親子な階層が微妙に不明。なので見えてる今が整理しどき。

  • ScheduleFragment#onCreateView で LayoutInflater#inflate されるレイアウトは R.layout.fragment_schedule
  • fragment_schedule なレイアウトの中で ui.widget.Workspace を使う、と宣言されている
  • ui.widget.Workspace は ViewGroup のサブクラス
  • ScheduleFragment#setupDay メソドの中で Day クラスのオブジェクトを生成して rootView 属性を Workspace#addView している
  • Day オブジェクトの rootView 属性は R.layout.blocks_content を LayoutInflater#inflate した戻りが設定される
    • Workspace にセットされる子 View は blocks_content に記述されているものとなる
  • blocks_content で宣言されている一番上位の View は ui.widget.ObservableScrollView
  • ui.widget.ObservableScrollView は ui.widget.BlocksLayout を含む
  • ui.widget.BlocksLayout は ui.widget.TimeRulerView と View (R.id.block_now)
    • nowView という Day オブジェクトの属性が参照しているものが何なのかが謎
  • BlocksLayout には ScheduleFragment#onQueryComplete で BlockView なオブジェクトが addBlock される

ちなみにソースツリーを find-grep したら以下な出力。

find . -type f -print0 | xargs -0 -e grep -nH -e [nN]owView
./ui/ScheduleFragment.java:107:        private View nowView;
./ui/ScheduleFragment.java:223:        day.nowView = day.rootView.findViewById(R.id.blocks_now);
./ui/ScheduleFragment.java:267:                updateNowView(true);
./ui/ScheduleFragment.java:347:    private boolean updateNowView(boolean forceScroll) {
./ui/ScheduleFragment.java:354:                day.nowView.setVisibility(View.VISIBLE);
./ui/ScheduleFragment.java:356:                day.nowView.setVisibility(View.GONE);
./ui/ScheduleFragment.java:364:            nowDay.nowView.requestRectangleOnScreen(new Rect(0, offset, 0, offset), true);
./ui/ScheduleFragment.java:391:            if (!updateNowView(true)) {
./ui/ScheduleFragment.java:411:            updateNowView(false);
./ui/widget/BlocksLayout.java:37:    private View mNowView;
./ui/widget/BlocksLayout.java:65:        mNowView = findViewById(R.id.blocks_now);
./ui/widget/BlocksLayout.java:66:        if (mNowView == null) {
./ui/widget/BlocksLayout.java:69:        mNowView.setDrawingCacheEnabled(true);
./ui/widget/BlocksLayout.java:80:        addView(mNowView);
./ui/widget/BlocksLayout.java:93:        mNowView.measure(widthMeasureSpec, heightMeasureSpec);
./ui/widget/BlocksLayout.java:128:        final View nowView = mNowView;
./ui/widget/BlocksLayout.java:132:        final int bottom = top + nowView.getMeasuredHeight();
./ui/widget/BlocksLayout.java:136:        nowView.layout(left, top, right, bottom);

Grep finished (matches found) at Thu Sep  1 17:27:25

どうも optionsMenu (ActionBar) に_なう_な項目があって選択したら updateNowView というメソドを呼んでるみたいですね。あら、BroadcastReceiver なオブジェクトからも呼び出されてますな。
なんとなく時間に合わせてタイムテーブルを適正に表示する風らしいのかどうか。とりあえず View の階層関係なマンガを以下に控えておきます。

Workspace -+- ObservableScrollView -+- BlocksLayout -+- TimeRulerView 
                                                     |   
                                                     +- View 
                                                     |
                                                     +- BlockView

あら、上記は微妙に間違えてるな。ObservableScrollView は複数存在する可能性があるのか。ということは Workspace が含む View をどうやって切り替えてるか、が分かれば万歳だったりするのかどうか。

確認

ScheduleFragment#onCreateView にて切り替え制御な callback を記述してます。

        mLeftIndicator.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                mWorkspace.scrollLeft();
            }
        });

scroll{Right, Left} という手続きが切り替えな i/f になってる模様。しかし Workspace.java を読んでくのは色々な意味でハードルが高いな。
しかも snapToScreen メソドの意味が分からない。核心部分は以下なのかなぁ。

        mScroller.startScroll(sX, 0, delta, 0, duration);
        if (screenChanging && notify) {
            notifyScreenChangeListener(mNextScreen, false);
        }
        invalidate();

mScroller は Scroller クラスで initWorkspace メソドで生成。

    private void initWorkspace() {
        mScroller = new Scroller(getContext());

Scroller って何スかorz

Scroller

d.android.com なドキュメントによれば

This class encapsulates scrolling. The duration of the scroll can be passed in the constructor and specifies the maximum time that the scrolling animation should take. Past this time, the scrolling is automatically moved to its final stage and computeScrollOffset() will always return false to indicate that scrolling is over.

とのこと。Workspace のソースを材料に使い方を確認する方向ッス。