美文网首页
RubyMotion学习记录

RubyMotion学习记录

作者: ShinPlus | 来源:发表于2015-09-08 15:33 被阅读460次

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

    启动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数据.

    相关文章

      网友评论

          本文标题:RubyMotion学习记录

          本文链接:https://www.haomeiwen.com/subject/msxpcttx.html