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は。