Rubotoを読み解いていく(ListView)

Rubotoでウィジェット(View)を使おうとしたら、

ruboto_import_widgets :LinearLayout, :ListView, :TextView

とかをする必要がある。まぁ何をやっているのかはわかるが、実際にどういう処理をやっているのかを読んでみようと思って、ruboto/widget.rbを開いてみた。

def ruboto_import_widget(class_name, package_name="android.widget")
  klass = java_import("#{package_name}.#{class_name}") || eval("Java::#{package_name}.#{class_name}")
  
  return unless klass

  RubotoActivity.class_eval "
     def #{(class_name.to_s.gsub(/([A-Z])/) { '_' + $1.downcase })[1..-1]}(params={})
        if force_style = params.delete(:default_style)
          rv = #{class_name}.new(self, nil, force_style)
        elsif api_key = params.delete(:apiKey)
          rv = #{class_name}.new(self, api_key)
        else
          rv = #{class_name}.new(self)
        end

        if parent = (params.delete(:parent) || @view_parent)
          parent.addView(rv, (params.delete(:parent_index) || parent.child_count))
        end

        rv.configure self, params

        return rv unless block_given?

        old_view_parent, @view_parent = @view_parent, rv
        yield
        @view_parent = old_view_parent

        rv
     end
   "

  setup_list_view if class_name == :ListView
  setup_spinner if class_name == :Spinner
  setup_button if class_name == :Button
  setup_image_button if class_name == :ImageButton
  setup_linear_layout if class_name == :LinearLayout
  setup_relative_layout if class_name == :RelativeLayout
end

メタプログラミングRubyを読んでいたおかげで意味がわかる!!
まず最初の行で、クラスのインポートを行っている。3行目でクラスがなければリターン。

クラスがあった場合、RubotoActivityをオープンしてウィジェット名のメソッドを定義している。:ListViewを渡したら、RubotoActivity.list_viewメソッドができるわけだ。ブロックを渡しているとなんか処理してくれるっぽい。

:ListViewがある場合、setup_list_viewメソッドが実行される。
では、setup_list_viewを見てみよう。

def setup_list_view
  Java::android.widget.ListView.class_eval do
    attr_reader :adapter, :adapter_list

    def configure(context, params = {})
      if params.has_key? :list
        @adapter_list = Java::java.util.ArrayList.new
        @adapter_list.addAll(params[:list])
        item_layout = params.delete(:item_layout) || R::layout::simple_list_item_1
        @adapter    = Java::android.widget.ArrayAdapter.new(context, item_layout, @adapter_list)
        setAdapter @adapter
        params.delete :list
      end
      if params.has_key? :adapter
        @adapter = params[:adapter]
      end
      super(context, params)
    end

    def reload_list(list)
      @adapter_list.clear
      @adapter_list.addAll(list)
      @adapter.notifyDataSetChanged
      invalidate
    end
  end
end

これもまた、ListViewクラスをオープンしてメソッドを定義している。メタプログラミング恐るべし。
ListView.configureメソッドとListView.reload_listメソッドを定義して、ListViewを使いやすくしているようである。

チュートリアルにあったソースコードを元に、ListViewを使ってみたので、載せておく。

ruboto_import_widgets :LinearLayout, :TextView, :ListView

$activity.start_ruboto_activity "$sample_activity" do
  setTitle 'This is the Title'

  def on_create(bundle)
    self.content_view =
        linear_layout(:orientation => :vertical) do
          @list = %w(aaa bbb ccc ddd eee fff ggg)
          @list_view = list_view(:list => @list,
                                 :on_item_click_listener => proc{|av, v, pos, item_id|
                                   toast(@list[pos])
                                 })
                     
    end
  end
end

:ListViewを読み込んでいるため、RubotoActivity内ではlist_viewメソッドが使える。
パラメータとして:list => @listを渡しているが、:item_layoutを省略しているので、R::layout::simple_list_item_1というListViewでは最もシンプルなViewが自動的に使われ、配列がArrayAdapterに渡されてListViewが表示される。

:on_item_click_listenerを無名関数(proc)で定義できるみたいだった。このソースでは、ListViewの押された行の文字列をトーストで表示するという処理をしている。非常に簡単な処理だが、これを調べるだけでもひと苦労するのである。コードは短いけど開発環境がいいのがないのかなぁ、Rubotoは。


カテゴリー Android | タグ | パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です