RubyMotion学习记录

杂七杂八的先记录一些,以后在更新;

启动Rubymotion

创建一个项目

$ motion create HelloMotion

启动

通常启动Simulator

rake

选择型号启动Simulator

rake device_name="iPhone 4s"

配置

Motion::Project::App.setup do |app|
  app.name = 'LocationManager2'
  app.frameworks += ['CoreLocation', 'MapKit']

  app.info_plist['NSLocationAlwaysUsageDescription'] = 'Description'
  app.info_plist['NSLocationWhenInUseUsageDescription'] = 'Description'
end

Views

UIViewUIWindow的父类

frame属性, 它包含了视图的x和y坐标, 以及它的height 高度和width宽度.

subviews属性, 是包含所有子视图的数组集合, 按照从后到前的顺序依次可视.

一个视图, 它的坐标是(10, 10), 我想让一个新的子视图出现在屏幕(50, 50) 的位置上, 那么我必须设置新视图的frame定位为(40, 40).

def application(application, didFinishLaunchingWithOptions:launchOptions)
   # UIScreen describes the display our app is running on
   @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)
   true
end
  • 创建了一个UIWindow的实例@window,大小和屏幕大小一样。
    调用方法makeKeyAndVisible以上这些告诉操作系统该窗口接收触摸事件, 在屏幕上可视.
  • 创建@blue_view视图,并添加为该@window的子视图。视图的Frame作为一个CGRect对象被存储,使用CGRectMake(x, y, w, h);CGRect由两个对象组合而成:CGPointCGSize 读取视图的y坐标view.frame.position.y 视图高度view.frame.size.height

注意: 直接在UIWindow上添加UIView这种做法@window.addSubview(@blue_view)并不值得推荐, 我只是为了说明问题才这样做的. 在生产环境中不能这样做. [1]

UIScreen

UIScreen.mainScreen.bounds根据返回的矩形大小屏幕尺寸和器件的定位

一个UIScreen对象包含设备的整个屏幕的边框。

label

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

使用CGRectZero初始化时先假设这个视图大小为0,

label.textColor = UIColor.greenColor

label.font = UIFont.fontWithName("HelveticaNeue- CondensedBold",size:18)

Alert

UIAlertView < UIView < UIResponder < NSObject

alert = UIAlertView.alloc.initWithTitle "This is foo title",message:"Do you like this example?",
delegate: nil,
cancelButtonTitle: "cancel"
otherButtonTitles: "Yes","No",nil
alert.show

irb

> delegate = UIApplication.sharedApplication.delegate
=> #<AppDelegate>
> blue_view = delegate.instance_variable_get('@blue_view')
=> #<UIView>
> blue_view.subviews.count
> => 1
> > red_view = blue_view.subviews[0]
> => #<UIView>
> > red_view.removeFromSuperview
> => #<UIView>
  • UIApplication.sharedApplication 返回一个对象, 系统可以使用这个对象描述整个应用程序, 这个对象只有一个.
  • 使用.delegate来获取配置
  • 一旦获取到, 就可以使用instance_variable_get方法来获取其中的视图.

Controller

  • 视图重用: 假设我们有一个PostView, 用来展示Post的所有信息. 我想在不同的屏幕上使用这个视图. 为了可重用性, PostView不应该有获取信息的逻辑代码, 所以处理数据的的任务就应该由Controller来承担, 然后把处理好的数据传递给视图.
  • Presentation management: 有时候我们需要让一个视图占据一整块屏幕, 而有些时候需要让这个视图占据屏幕的一部分, 比如对于ipad和iPhone来说. 如果就因为这事就写两个内容完全相同的视图class只是大小不同就没有必要了, 所以我们使用Controller来让视图显示相应的大小.

创建一个./app/controllers/tap_controller.rb

class TapController < UIViewController
  def viewDidLoad
    super
    self.view.backgroundColor = UIColor.redColor
  end
end

viewDidLoad 是UIViewController生命周期方法之一.
@window.rootViewController = TapController.alloc.initWithNibName(nil, bundle: nil)

  • initWithNibName:bundle: 是用于从NIB文件中载入Controller. NIB 是使用Xcode’s Interface Builder 作为一种可视化构建视图的方式来创建的.
  • initWithNibName:bundle: 也是一种UIViewController的特点初始化. 只要以创建一个控制器, 你必须要调用这个方法.

Containers

UITabBarControllerUINavigationController这些container (容器) 是UIViewController, 同时管理其他UIViewController.

IOS SDK使用UINavigationControllersUITabBarController 来包含子视图Controllers.

UINavigationController(需要继续补充)

UINavigationController使用stack这样的结构管理它里面的Controllers.[2]

AppDelegate中, 把rootViewController赋值为一个UINavigationController :

controller = TapController.alloc.initWithNibName(nil, bundle:nil)
@window.rootViewController = UINavigationController.alloc.initWithRootViewController(controller)

initWithRootViewController会把controller作为stack的第一个元素.

导航条添加按钮

def viewDidLoad
  ...
  self.title = "Tap (#{self.navigationController.viewControllers.count})"
  right_button = UIBarButtonItem.alloc.initWithTitle("Push", style: UIBarButtonItemStyleBordered, target:self, action:'push')
  self.navigationItem.rightBarButtonItem = right_button
end
  • 创建了UIBarButtonItem的实例, style 属性决定按钮的样子风格
  • 设置成了Controller的navigationItemrightBarButtonItem
  • 每一个UIViewController都有navigationItem, 我们通过这个属性可以访问到导航条的信息.
  • 注意: UINavigationItem不是UIView, 不能随意添加子视图.
定义action 对于的方法push
def push
  new_controller = TapController.alloc.initWithNibName(nil, bundle: nil)
  self.navigationController.pushViewController(new_controller, animated: true)
end
  • pushViewController会把Controller推入stack中
  • 默认 navigation controller 会在左侧显示一个back的按钮来把当前Controller弹出栈.
  • UINavigationControllerpushViewController:animatedpopViewControllerAnimated 来控制进栈和弹栈.

UITabBarController

TabBarControllers它只能作为windowrootViewController, 你不能把它push到NavigationController中.

UITabBarController 使用viewControllers=来控制它的子元素, 注意UITabBarController只允许被用作window的rootViewController

other_controller = UIViewController.alloc.initWithNibName(nil, bundle: nil)
other_controller.title = "Other"
other_controller.view.backgroundColor = UIColor.purpleColor
tab_controller = UITabBarController.alloc.initWithNibName(nil, bundle: nil)
tab_controller.viewControllers = [nav_controller, other_controller]
@window.rootViewController = tab_controller

创建了UITabBarController, 然后设置viewControllers 为一个数组. 数组的元素为所要含有的 NavigationController.

TapController重写initWithNibName:bundle方法

def initWithNibName(name, bundle: bundle)
  super
  self.tabBarItem = UITabBarItem.alloc.initWithTabBarSystemItem(UITabBarSystemItemFavorites, tag: 1)
  self
end
  • 使用了系统的图标, 使用的方法是initWithTabBarSystemItem
  • 然后我把它放到initWithNibName:bundle, 为的是只有Controller一初始化, 就创建tabBarItem.
  • 使用controller(self).tabBarItem改变tab图标和title.

Tables

UITableView有dataSource, 用来提供数据信息; delegate 用来管理用户的行为, 视觉体验

class AlphabetController < UIViewController
  def viewDidLoad
    super
    self.title = "Alphabet"
    @table = UITableView.alloc.initWithFrame(self.view.bounds)
    self.view.addSubview @table
  end
end
  • view.bounds返回的是CGRect对象, 类似于view.frame, 但是frame只描述了大小, 没有位置.
  • newView.initWithFrame(view.bounds)则是让newView填充view.

在AppDelegate里添加这个新的AlphabetController:

alphabet_controller = AlphabetController.alloc.initWithNibName(nil, bundle: nil)

需要设置dataSource :

def viewDidLoad
...
@table.dataSource = self
end

data source 必须要实现以下方法:

  • numberOfRowsInSectioncellForRowAtIndexPath
  • cellForRowAtIndexPath应该返回UITableViewCell的实例
def tableView(tableView, cellForRowAtIndexPath: indexPath)
  @reuseIdentifier ||= "CELL_IDENTIFIER"
  cell = tableView.dequeueReusableCellWithIdentifier(@reuseIdentifier) || begin  UITableViewCell.alloc.initWithStyle(UITableViewCellStyleDefault, reuseIdentifier:@reuseIdentifier)
  end
  # put your data in the cell
  cell
end

这里reuseIdentifier 是对这一种的cell做一个标记, 这些cell是一个类型的, 因为在iOS中管理着若干cell 池, 当需要重新使用一个cell时, 通过这个reuseIdentifier去相应的cell池中拿出即可.

需要准备数据

def viewDidLoad
  ...
  @data = ("A".."Z").to_a
  @table.dataSource = self
  @table.delegate = self
end

在numberOfRowsInSection中, 需要设置行的数量

def tableView(tableView, numberOfRowsInSection: section)
  @data.count
end

使用delegate和didSelectRowAtIndexPath方法来响应用户触碰某一个行

deselectRowAtIndexPath:animated 的作用是, 点击一个cell之后, 它会被高亮, 该方法就是取消高亮.

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

Models(需要继续补充)

属性访问

class User
  attr_accessor :id
  attr_accessor :name
  attr_accessor :email
end

之后可以像这样操作对象

@user = User.new
@user.name = "Clay"
@user.email = "clay@mail.com"

如果需要处理一些远程API, 就应该技巧性的处理

class User
  PROPERTIES = [:id, :name, :email]
  PROPERTIES.each do |prop|
    attr_accessor prop
  end
  def initialize(attributes = {}) 
    attributes.each do |key, value|
      self.send("#{key}=", value) if PROPERTIES.member? key
    end
  end
end

在初始化User的时候可以这样做

server_hash = { name: "Clay", email: "my@email.com", id: 200000 }
@user = User.new(server_hash)
@user.name
=> Clay

NSCoding

NSUserDefaults

对象可以作为持久化的K-V存储.一般, 我们会使用NSUserDefaults.standardUserDefaults的实例作为对象

@defaults = NSUserDefaults.standardUserDefaults
@defaults["one"] = 1
# somewhere else, next time we run the app
@defaults["one"]
=> 1
  • 只要你的app被安装, NSUserDefaults的值就会被保存.
  • NSUserDefaults.resetStandardUserDefaults方法可以清空所有的key value.
  • 注意的是, 我们不能在NSUserDefaults 中存储旧的对象[3]
  • 因为不是原始数据, 所以必须使用data 方法.

符合NSCoding的两个方法是initWithCoder:(用于载入一个对象) 和 encodeWithCoder(用于保存对象).这两个方法像镜子一样, encodeWithCoder可以通过key把所有对象的值进行编码, initWithCoder通过这些key对对象的值解码.

class Post
  attr_accessor :message
  attr_accessor :id
  
  # called when an object is loaded from NSUserDefaults
  # this is an initializer, so should return `self`
  def initWithCoder(decoder)
    self.init
    self.message = decoder.decodeObjectForKey("message")
    self.id = decoder.decodeObjectForKey("id")
    self
  end
  # called when saving an object to NSUserDefaults
  def encodeWithCoder(encoder)
    encoder.encodeObject(self.message, forKey: "message")
    encoder.encodeObject(self.id, forKey: "id")
  end
end

这就允许我们把任意对象转换成数据, 可以保存到NSUserDefaults中:

defaults = NSUserDefaults.standardUserDefaults
post = Post.new
post.message = "hello!"
post.id = 1000
post_as_data = NSKeyedArchiver.archivedDataWithRootObject(post)
defaults["saved_post"] = post_as_data
# later on, we want to load this post:
post_as_data = defaults["saved_post"]
post = NSKeyedUnarchiver.unarchiveObjectWithData(post_as_data)

Key-Value Observing

https://danielzhangqinglong.github.io/2015/04/12/rubymotion-tut07

HTTP

https://github.com/clayallsopp/afmotion


  1. rootViewController=方法让窗口使用给定的UIViewController所调整(产生)的视图, 相对于window.addSubview这样做更好.@window.rootViewController = TapController.alloc.initWithNibName(nil, bundle: nil)

  2. https://developer.apple.com/library/ios/documentation/UIKit/Reference/UINavigationController_Class/

  3. 可以存储基本数据类型( strings, integers, and hashes ), 或者使用原生的byte数据.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • iOS 实战开发课程笔记 本贴旨在作为对极客班 《iOS 开发实战》第五期期课程视频重新学习的笔记。目标是建立一个...
    黄穆斌阅读 2,939评论 12 57
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,612评论 4 59
  • 醉眼朦胧看足球,惊魂动魄酒已醒。命运何须他人定,只要拼搏就会赢!
    叶小北阅读 143评论 0 1
  • 1.适合你的未必是你喜欢的。你所需要的也未必会喜欢。人生而在世,总有许多身不由己。无需抱怨,接受与否,端看自己的选...
    染青绫阅读 195评论 0 2