RubyMotionことはじめ
RubyMotion
最近おいらの周りでrubymotion++なひとが多く、おいらも始めました。 とりあえず勢いで買っちまったのできちんと勉強して使えるようにする。
なんぞ?
いとうなおやさんのスライドわかりやすい。。
https://speakerdeck.com/naoya/shi-jian-rubymotion
チュートリアル
とりあえず、下を読む
http://rubymotion-tutorial.com/
1 hello motion
プロジェクト作成
motion create HelloMotion
- $: はライブラリのロードパスの配列
- Rakefileの.setupにプロジェクトの設定を書く
- rake configでプロジェクト全体の設定を見る
- .nameにプロジェクト名
- require 'motion/project' でrubymotionのライブラリをロード
- ./app/app_delegate.rb がAppDelegateクラス
- [obj makeBoxWithOrigin:origin andSize: size] => obj.makeBox(origin, andSize: size) でAppleAPIに互換
アラートダイアログを出す
alert = UIAlertView.new
alert.message = "Hello Motion!"
alert.show
2 views
class AppDelegate
def application(application, didFinishLaunchingWithOptions:launchOptions)
@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
@window.makeKeyAndVisible
@blue_view = UIView.alloc.initWithFrame(CGRectMake(10, 10, 100, 100))
@blue_view.backgroundColor = UIColor.blueColor
@window.addSubview(@blue_view)
@green_view = UIView.alloc.initWithFrame(CGRectMake(30, 30, 40, 40))
@green_view.backgroundColor = UIColor.greenColor
@window.addSubview(@green_view)
@red_view = UIView.alloc.initWithFrame(CGRectMake(30, 30, 40, 40))
@red_view.backgroundColor = UIColor.redColor
@blue_view.addSubview(@red_view)
true
end
end
インタプリタで変更する
$ rake
(main)> delegate = UIApplication.sharedApplication.delegate
=> #<AppDelegate:0x950bb90 @window=#<UIWindow:0xb006be0> @blue_view=#<UIView:0x950d8f0> @green_view=#<UIView:0x950e2f0> @red_view=#<UIView:0x950e480>>
(main)> blue_view = delegate.instance_variable_get('@blue_view')
=> #<UIView:0x950d8f0>
(main)> blue_view.subviews.count
=> 1
(main)> red_view = blue_view.subviews[0]
=> #<UIView:0x950e480>
(main)> red_view.removeFromSuperview
=> #<UIView:0x950e480>
(main)> blue_view.subviews.count
=> 0
動的にblue_viewを削除できた。
3 controller
コントローラを作ってラベルを追加
class TapController < UIViewController
def viewDidLoad
super
self.view.backgroundColor = UIColor.whiteColor
@label = UILabel.alloc.initWithFrame(CGRectZero)
@label.text = "Taps"
@label.sizeToFit
@label.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2)
self.view.addSubview @label
end
end
delegate側も変更
class AppDelegate
def application(application, didFinishLaunchingWithOptions:launchOptions)
@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
@window.makeKeyAndVisible
@window.rootViewController = TapController.alloc.initWithNibName(nil, bundle: nil)
true
end
end
4 containers
UINavigationControllerを追加
@window.rootViewController = UINavigationController.alloc.initWithRootViewController(controller)
ナビゲーションアイテムを追加
right_button = UIBarButtonItem.alloc.initWithTitle("push", style: UIBarButtonItemStyleBordered, target: self, action: 'push')
self.navigationItem.rightBarButtonItem = right_button
ナビゲーションアイテムの追加処理
def push
new_controller = TapController.alloc.initWithNibName(nil, bundle: nil)
self.navigationController.pushViewController(new_controller, animated: true)
end
タイトルを変更
self.title = "Tap(#{ self.navigationController.viewControllers.count })"
...
タブメニュー(お気に入りアイコン)を追加
def initWithNibName(name, bundle: bundle)
super
self.tabBarItem = UITabBarItem.alloc.initWithTabBarSystemItem(UITabBarSystemItemFavorites, tag: 1)
self
end
タブメニュー(背景: 紫)を追加
other_controller = UIViewController.alloc.initWithNibName(nil, bundle: nil)
other_controller.title = "Other"
other_controller.view.background = UIColor.purpleColor
tab_controller = UITabBarController.alloc.initWithNibName(nil, bundle: nil)
tab_controller.viewControllers = [nav_controller, other_controller]
5 tables
app_delegate.rbにテーブルコントローラを追加
alphabet_controller = AlphabetController.alloc.initWithNibName(nil, bundle: nil)
tab_controller.viewControllers = [alphabet_controller, nav_controller ]
app/controllers/AlphabetController.rbにテーブルコントローラを記述
class AlphabetController < UIViewController
def viewDidLoad
super
self.title = "Alphabet"
@table = UITableView.alloc.initWithFrame(self.view.bounds)
self.view.addSubview @table
@table.dataSource = self
@table.delegate = self
@data = ("A".."Z").to_a
end
def tableView(tableView, cellForRowAtIndexPath: indexPath)
@reuseIdentifier ||= "CELL_IDENTIFIER"
cell = tableView.dequeueReusableCellWithIdentifier(@reuseIdentifier) || begin
UITableViewCell.alloc.initWithStyle(UITableViewCellStyleDefault, reuseIdentifier: @reuseIdentifier)
end
cell.textLabel.text = @data[indexPath.row]
cell
end
def tableView(tableView, numberOfRowsInSection: section)
@data.count
end
def tableView(tableView, didSelectRowAtIndexPath: indexPath)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
alert = UIAlertView.alloc.init
alert.message = "#{ @data[indexPath.row] } tapped!"
alert.addButtonWithTitle "OK"
alert.show
end
end
6 animations
class AppDelegate
def application(application, didFinishLaunchingWithOptions:launchOptions)
@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
@window.makeKeyAndVisible
@points = [[0, 0], [50, 0], [0, 50], [50, 50]]
@current_index = 0
@view = UIView.alloc.initWithFrame [@points[@current_index], [100, 100]]
@view.backgroundColor = UIColor.blueColor
@window.addSubview(@view)
animate_to_next_point
true
end
def animate_to_next_point
@current_index += 1
@current_index = @current_index % @points.count
UIView.animateWithDuration(
delay: 2,
options: UIViewAnimationOptionCurveLinear,
animations: lambda {
@view.frame = [@points[@current_index], [100, 100]]
},
completion: lambda {|finished|
self.animate_to_next_point
})
end
end
7 models
モデルをつくる
class User
attr_accessor :id
attr_accessor :name
attr_accessor :email
end
変数を監視する
class AppDelegate
include BW::KVO
attr_accessor :user
def application(application, didFinishLaunchingWithOptions:launchOptions)
@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.applicationFrame)
@window.makeKeyAndVisible
@name_label = UILabel.alloc.initWithFrame([[0,0], [100,30]])
@window.addSubview(@name_label)
@email_label = UILabel.alloc.initWithFrame([[0, @name_label.frame.size.height + 10], @name_label.frame.size])
@window.addSubview(@email_label)
@id_label = UILabel.alloc.initWithFrame([[0, @email_label.frame.origin.y + @email_label.frame.size.height + 10], @name_label.frame.size])
@window.addSubview(@id_label)
# ------
self.user = User.new
["name", "id", "email"].each do |prop|
observe(self.user, prop) do |old_value, new_value|
instance_variable_get("@#{prop}_label").text = new_value
end
end
true
end
end
ビルドして、リアルタイムに変数代入
$ rake
(main)> delegate = UIApplication.sharedApplication.delegate
=> #<AppDelegate:0xb14b8f0 @window=#<UIWindow:0x9660d70> @name_label=#<UILabel:0x9459320> @email_label=#<UILabel:0x9459e80> @id_label=#<UILabel:0x945a520> @user=#<NSKVONotifying_User:0x945a8a0> @targets={#<NSKVONotifying_User:0x945a8a0>=>{"name"=>[#<Proc:0x945ab10>], "id"=>[#<Proc:0x945d230>], "email"=>[#<Proc:0x945d750>]}}>
(main)> user = delegate.user
=> #<NSKVONotifying_User:0x945a8a0>
(main)> user.email = "test@xample.com"
=> "test@xample.com"
(main)> user.name = "john"
=> "john"
(main)> user.id = "1001"
=> "1001"
8 testing
ボタン一つのプロジェクトを作る.
class ButtonController < UIViewController
def viewDidLoad
super
@button = UIButton.buttonWithType(UIButtonTypeRoundedRect)
@button.setTitle("Test me title!", forState: UIControlStateNormal)
@button.accessibilityLabel = "Test me!"
@button.sizeToFit
self.view.addSubview(@button)
@button.addTarget(self, action:'tapped', forControlEvents:UIControlEventTouchUpInside)
end
def tapped
p "I'm tapped!"
@was_tapped = true
end
end
app/app_delegate.rb
class AppDelegate
def application(application, didFinishLaunchingWithOptions:launchOptions)
@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.applicationFrame)
@window.makeKeyAndVisible
@view_controller = ButtonController.alloc.initWithNibName(nil, bundle: nil)
@window.rootViewController = @view_controller
true
end
end
spec/main_spec.rb ボタンをタップしてテストする。
describe "Application 'Tests'" do
before do
@app = UIApplication.sharedApplication
end
it "has one window" do
@app.windows.size.should == 1
end
end
describe "button controller" do
tests ButtonController
it "changes instance variable when button is tapped" do
tap 'Test me!'
controller.intance_variable_get("@was_tapped").should == true
end
end
9 http
bubble-wrapでhttpリクエストが簡単に利用できる
BubbleWarp::Http.get("http://www.google.com") do |response|
p response.body.to_str
end
10 API Driven Example
長いのでぱす。