teacup 2.1.13 → 2.1.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/lib/teacup-ios/handler.rb +1 -1
  2. data/lib/teacup-osx/handler.rb +1 -1
  3. data/lib/teacup/calculations.rb +2 -2
  4. data/lib/teacup/core_extensions/view_getters.rb +2 -2
  5. data/lib/teacup/layout.rb +1 -1
  6. data/lib/teacup/stylesheet_extensions/constraints.rb +14 -2
  7. data/lib/teacup/teacup_controller.rb +1 -1
  8. data/lib/teacup/teacup_view.rb +3 -3
  9. data/lib/teacup/version.rb +1 -1
  10. data/spec/ios/calculations_spec.rb +5 -1
  11. data/spec/ios/layout_module_spec.rb +2 -2
  12. metadata +24 -79
  13. data/.gitignore +0 -8
  14. data/.travis.yml +0 -3
  15. data/CHANGES.md +0 -26
  16. data/Gemfile +0 -9
  17. data/Gemfile.lock +0 -18
  18. data/LICENSE +0 -26
  19. data/README.md +0 -1527
  20. data/Rakefile +0 -18
  21. data/resources/Default-568h@2x.png +0 -0
  22. data/samples/README.md +0 -15
  23. data/samples/ios/AutoLayout/Gemfile +0 -1
  24. data/samples/ios/AutoLayout/Gemfile.lock +0 -13
  25. data/samples/ios/AutoLayout/Rakefile +0 -13
  26. data/samples/ios/AutoLayout/app/app_delegate.rb +0 -12
  27. data/samples/ios/AutoLayout/app/root_controller.rb +0 -16
  28. data/samples/ios/AutoLayout/app/styles/root.rb +0 -29
  29. data/samples/ios/AutoLayout/lib/dummy.rb +0 -2
  30. data/samples/ios/AutoLayout/lib/handlers.rb +0 -3
  31. data/samples/ios/AutoLayout/lib/styles/base.rb +0 -33
  32. data/samples/ios/Hai/.gitignore +0 -5
  33. data/samples/ios/Hai/Gemfile +0 -1
  34. data/samples/ios/Hai/Gemfile.lock +0 -13
  35. data/samples/ios/Hai/Rakefile +0 -12
  36. data/samples/ios/Hai/app/app_delegate.rb +0 -9
  37. data/samples/ios/Hai/app/hai_controller.rb +0 -13
  38. data/samples/ios/Hai/app/styles/iphone.rb +0 -47
  39. data/samples/ios/Hai/resources/Default-568h@2x.png +0 -0
  40. data/samples/ios/sweettea-example/Gemfile +0 -5
  41. data/samples/ios/sweettea-example/Gemfile.lock +0 -23
  42. data/samples/ios/sweettea-example/Rakefile +0 -11
  43. data/samples/ios/sweettea-example/app/app_delegate.rb +0 -43
  44. data/samples/ios/sweettea-example/resources/Default-568h@2x.png +0 -0
  45. data/samples/osx/Tweets/Gemfile +0 -1
  46. data/samples/osx/Tweets/Gemfile.lock +0 -13
  47. data/samples/osx/Tweets/README +0 -7
  48. data/samples/osx/Tweets/Rakefile +0 -10
  49. data/samples/osx/Tweets/app/app_delegate.rb +0 -18
  50. data/samples/osx/Tweets/app/data_parser.rb +0 -10
  51. data/samples/osx/Tweets/app/json_parser.rb +0 -12
  52. data/samples/osx/Tweets/app/main_window.rb +0 -99
  53. data/samples/osx/Tweets/app/menu.rb +0 -108
  54. data/samples/osx/Tweets/app/stylesheet.rb +0 -21
  55. data/samples/osx/Tweets/app/tweet.rb +0 -11
  56. data/samples/osx/Tweets/resources/Credits.rtf +0 -29
  57. data/samples/osx/simple/.gitignore +0 -1
  58. data/samples/osx/simple/Gemfile +0 -1
  59. data/samples/osx/simple/Gemfile.lock +0 -16
  60. data/samples/osx/simple/Rakefile +0 -9
  61. data/samples/osx/simple/app/app_delegate.rb +0 -21
  62. data/samples/osx/simple/app/controller.rb +0 -11
  63. data/samples/osx/simple/app/menu.rb +0 -108
  64. data/samples/osx/simple/app/window.rb +0 -12
  65. data/samples/osx/simple/resources/Credits.rtf +0 -29
  66. data/samples/osx/simple/resources/teacup.png +0 -0
  67. data/teacup.gemspec +0 -25
@@ -3,7 +3,7 @@ module Teacup
3
3
 
4
4
  def apply_method(target, assign, setter, value)
5
5
  if assign and target.respond_to?(assign)
6
- NSLog "Setting #{key} = #{value.inspect}" if target.respond_to? :debug and target.debug
6
+ NSLog "Setting #{setter} = #{value.inspect}" if target.respond_to? :debug and target.debug
7
7
  target.send(assign, value)
8
8
  elsif target.respondsToSelector(setter)
9
9
  NSLog "Calling target.#{setter}(#{value.inspect})" if target.respond_to? :debug and target.debug
@@ -3,7 +3,7 @@ module Teacup
3
3
 
4
4
  def apply_method(target, assign, setter, value)
5
5
  if assign and target.respond_to?(assign)
6
- NSLog "Setting #{key} = #{value.inspect}" if target.respond_to? :debug and target.debug
6
+ NSLog "Setting #{setter} = #{value.inspect}" if target.respond_to? :debug and target.debug
7
7
  target.send(assign, value)
8
8
  elsif target.respondsToSelector(setter)
9
9
  NSLog "Calling target.#{setter}(#{value.inspect})" if target.respond_to? :debug and target.debug
@@ -10,9 +10,9 @@ module Teacup
10
10
 
11
11
  case dimension
12
12
  when :width
13
- view.superview.bounds.size.width * percent + offset
13
+ view.superview.frame.size.width * percent + offset
14
14
  when :height
15
- view.superview.bounds.size.height * percent + offset
15
+ view.superview.frame.size.height * percent + offset
16
16
  else
17
17
  raise "Unknown dimension #{dimension}"
18
18
  end
@@ -10,13 +10,13 @@ module Teacup
10
10
  def viewWithStylename name_or_class
11
11
  return self if self._teacup_check_stylename(name_or_class)
12
12
 
13
- view = subviews.find { |view| view._teacup_check_stylename(name_or_class) }
13
+ view = self.teacup_subviews.find { |view| view._teacup_check_stylename(name_or_class) }
14
14
  return view if view
15
15
 
16
16
  # found_subview will get assigned to the view we want, but the subview is
17
17
  # what is returned.
18
18
  found_subview = nil
19
- view = subviews.find { |subview| found_subview = subview.viewWithStylename(name_or_class) }
19
+ view = self.teacup_subviews.find { |subview| found_subview = subview.viewWithStylename(name_or_class) }
20
20
  return found_subview if view
21
21
 
22
22
  return nil # couldn't find it
data/lib/teacup/layout.rb CHANGED
@@ -255,7 +255,7 @@ module Teacup
255
255
  def auto(layout_view=top_level_view, layout_subviews={}, &layout_block)
256
256
  raise "gem install 'motion-layout'" unless defined? Motion::Layout
257
257
 
258
- styled_subviews = layout_view.subviews.select { |v| v.stylename }
258
+ styled_subviews = layout_view.teacup_subviews.select { |v| v.stylename }
259
259
  styled_subviews.each do |view|
260
260
  if ! layout_subviews[view.stylename.to_s]
261
261
  layout_subviews[view.stylename.to_s] = view
@@ -50,9 +50,21 @@ module Teacup
50
50
  end
51
51
 
52
52
  def constrain_size(width, height)
53
+ if width.is_a? Numeric
54
+ width_attr = nil
55
+ else
56
+ width_attr = :width
57
+ end
58
+
59
+ if height.is_a? Numeric
60
+ height_attr = nil
61
+ else
62
+ height_attr = :height
63
+ end
64
+
53
65
  [
54
- Teacup::Constraint.new(:self, :width).equals(width),
55
- Teacup::Constraint.new(:self, :height).equals(height),
66
+ Teacup::Constraint.new(:self, :width).equals(width, width_attr),
67
+ Teacup::Constraint.new(:self, :height).equals(height, height_attr),
56
68
  ]
57
69
  end
58
70
 
@@ -108,7 +108,7 @@ module Teacup
108
108
  self.top_level_view.restyle!
109
109
  end
110
110
 
111
- if defined? NSLayoutConstraint
111
+ if defined?(NSLayoutConstraint)
112
112
  self.top_level_view.apply_constraints
113
113
  end
114
114
  end
@@ -21,10 +21,9 @@ module Teacup
21
21
 
22
22
  # Subviews or empty collection of views to cater for issue with iOS7 dp3
23
23
  def teacup_subviews
24
- subviews || []
24
+ self.subviews || []
25
25
  end
26
26
 
27
-
28
27
  # Alter the stylename of this view.
29
28
  #
30
29
  # This will cause new styles to be applied from the stylesheet.
@@ -187,6 +186,7 @@ module Teacup
187
186
 
188
187
  if original_constraint.relative_to && ! constraint.relative_to
189
188
  container = self
189
+ puts "Searching for #{original_constraint.relative_to.inspect} in the tree:"
190
190
  tab = ''
191
191
  while container
192
192
  tab << '->'
@@ -310,7 +310,7 @@ module Teacup
310
310
 
311
311
  def reset_constraints
312
312
  @teacup_constraints = nil
313
- subviews.each do |subview|
313
+ self.teacup_subviews.each do |subview|
314
314
  subview.reset_constraints
315
315
  end
316
316
  end
@@ -1,5 +1,5 @@
1
1
  module Teacup
2
2
 
3
- VERSION = '2.1.13'
3
+ VERSION = '2.1.14'
4
4
 
5
5
  end
@@ -4,7 +4,11 @@ class Viewish
4
4
  end
5
5
 
6
6
  def bounds
7
- CGRect.new([0, 0,], [100, 44])
7
+ CGRect.new([0, 0], [100, 44])
8
+ end
9
+
10
+ def frame
11
+ CGRect.new([10, 10], [100, 44])
8
12
  end
9
13
  end
10
14
 
@@ -47,8 +47,8 @@ describe 'Layout module' do
47
47
 
48
48
  it 'should have view-creation methods' do
49
49
  @helper.create_views
50
- UIView.should === @helper.container
51
- UILabel.should === @helper.label
50
+ @helper.container.should.is_a?(UIView)
51
+ @helper.label.should.is_a?(UILabel)
52
52
  end
53
53
 
54
54
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: teacup
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.13
4
+ version: 2.1.14
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,17 +9,17 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-10-30 00:00:00.000000000 Z
12
+ date: 2014-02-25 00:00:00.000000000 Z
13
13
  dependencies: []
14
- description: ! 'Teacup is a community-driven DSL for making CSS-like styling, and
15
- layouts for
14
+ description: ! 'Teacup is a community-driven DSL for RubyMotion. It has CSS-like
15
+ styling, and
16
16
 
17
- complex and simple iOS apps with RubyMotion.
17
+ helps create complex and simple layouts in iOS and OS X apps.
18
18
 
19
19
 
20
- By aiming at making RubyMotion less tedious, Teacup makes RubyMotion feel like
20
+ Teacup aims at making UI develpoment in RubyMotion less tedious. It''s like
21
21
 
22
- interface builder, and work like a CSS stylesheet.
22
+ Interface Builder for RubyMotion!
23
23
 
24
24
  '
25
25
  email:
@@ -27,14 +27,21 @@ executables: []
27
27
  extensions: []
28
28
  extra_rdoc_files: []
29
29
  files:
30
- - .gitignore
31
- - .travis.yml
32
- - CHANGES.md
33
- - Gemfile
34
- - Gemfile.lock
35
- - LICENSE
36
- - README.md
37
- - Rakefile
30
+ - lib/teacup/calculations.rb
31
+ - lib/teacup/constraint.rb
32
+ - lib/teacup/core_extensions/ca_layer.rb
33
+ - lib/teacup/core_extensions/view_getters.rb
34
+ - lib/teacup/handler.rb
35
+ - lib/teacup/layout.rb
36
+ - lib/teacup/merge_defaults.rb
37
+ - lib/teacup/restyle.rb
38
+ - lib/teacup/stylesheet.rb
39
+ - lib/teacup/stylesheet_extensions/constraints.rb
40
+ - lib/teacup/stylesheet_extensions/transform.rb
41
+ - lib/teacup/teacup_controller.rb
42
+ - lib/teacup/teacup_util.rb
43
+ - lib/teacup/teacup_view.rb
44
+ - lib/teacup/version.rb
38
45
  - lib/teacup-ios/appearance.rb
39
46
  - lib/teacup-ios/core_extensions/teacup_handlers.rb
40
47
  - lib/teacup-ios/core_extensions/ui_view.rb
@@ -55,67 +62,6 @@ files:
55
62
  - lib/teacup-osx/style.rb
56
63
  - lib/teacup-osx/style_extensions/autoresize.rb
57
64
  - lib/teacup.rb
58
- - lib/teacup/calculations.rb
59
- - lib/teacup/constraint.rb
60
- - lib/teacup/core_extensions/ca_layer.rb
61
- - lib/teacup/core_extensions/view_getters.rb
62
- - lib/teacup/handler.rb
63
- - lib/teacup/layout.rb
64
- - lib/teacup/merge_defaults.rb
65
- - lib/teacup/restyle.rb
66
- - lib/teacup/stylesheet.rb
67
- - lib/teacup/stylesheet_extensions/constraints.rb
68
- - lib/teacup/stylesheet_extensions/transform.rb
69
- - lib/teacup/teacup_controller.rb
70
- - lib/teacup/teacup_util.rb
71
- - lib/teacup/teacup_view.rb
72
- - lib/teacup/version.rb
73
- - resources/Default-568h@2x.png
74
- - samples/README.md
75
- - samples/ios/AutoLayout/Gemfile
76
- - samples/ios/AutoLayout/Gemfile.lock
77
- - samples/ios/AutoLayout/Rakefile
78
- - samples/ios/AutoLayout/app/app_delegate.rb
79
- - samples/ios/AutoLayout/app/root_controller.rb
80
- - samples/ios/AutoLayout/app/styles/root.rb
81
- - samples/ios/AutoLayout/lib/dummy.rb
82
- - samples/ios/AutoLayout/lib/handlers.rb
83
- - samples/ios/AutoLayout/lib/styles/base.rb
84
- - samples/ios/Hai/.gitignore
85
- - samples/ios/Hai/Gemfile
86
- - samples/ios/Hai/Gemfile.lock
87
- - samples/ios/Hai/Rakefile
88
- - samples/ios/Hai/app/app_delegate.rb
89
- - samples/ios/Hai/app/hai_controller.rb
90
- - samples/ios/Hai/app/styles/iphone.rb
91
- - samples/ios/Hai/resources/Default-568h@2x.png
92
- - samples/ios/sweettea-example/Gemfile
93
- - samples/ios/sweettea-example/Gemfile.lock
94
- - samples/ios/sweettea-example/Rakefile
95
- - samples/ios/sweettea-example/app/app_delegate.rb
96
- - samples/ios/sweettea-example/resources/Default-568h@2x.png
97
- - samples/osx/Tweets/Gemfile
98
- - samples/osx/Tweets/Gemfile.lock
99
- - samples/osx/Tweets/README
100
- - samples/osx/Tweets/Rakefile
101
- - samples/osx/Tweets/app/app_delegate.rb
102
- - samples/osx/Tweets/app/data_parser.rb
103
- - samples/osx/Tweets/app/json_parser.rb
104
- - samples/osx/Tweets/app/main_window.rb
105
- - samples/osx/Tweets/app/menu.rb
106
- - samples/osx/Tweets/app/stylesheet.rb
107
- - samples/osx/Tweets/app/tweet.rb
108
- - samples/osx/Tweets/resources/Credits.rtf
109
- - samples/osx/simple/.gitignore
110
- - samples/osx/simple/Gemfile
111
- - samples/osx/simple/Gemfile.lock
112
- - samples/osx/simple/Rakefile
113
- - samples/osx/simple/app/app_delegate.rb
114
- - samples/osx/simple/app/controller.rb
115
- - samples/osx/simple/app/menu.rb
116
- - samples/osx/simple/app/window.rb
117
- - samples/osx/simple/resources/Credits.rtf
118
- - samples/osx/simple/resources/teacup.png
119
65
  - spec/ios/appearance_spec.rb
120
66
  - spec/ios/calculations_spec.rb
121
67
  - spec/ios/constraints_spec.rb
@@ -136,7 +82,6 @@ files:
136
82
  - spec/ios/ui_view_getters_spec.rb
137
83
  - spec/ios/uiswitch_spec.rb
138
84
  - spec/ios/view_spec.rb
139
- - teacup.gemspec
140
85
  homepage: https://github.com/rubymotion/teacup
141
86
  licenses:
142
87
  - BSD
@@ -158,10 +103,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
158
103
  version: '0'
159
104
  requirements: []
160
105
  rubyforge_project:
161
- rubygems_version: 1.8.25
106
+ rubygems_version: 1.8.11
162
107
  signing_key:
163
108
  specification_version: 3
164
- summary: A community-driven DSL for creating user interfaces on iOS.
109
+ summary: A community-driven DSL for creating user interfaces on iOS and OS X.
165
110
  test_files:
166
111
  - spec/ios/appearance_spec.rb
167
112
  - spec/ios/calculations_spec.rb
data/.gitignore DELETED
@@ -1,8 +0,0 @@
1
- .repl_history
2
- *.bridgesupport
3
- build
4
- resources/*.nib
5
- resources/*.momd
6
- resources/*.storyboardc
7
- teacup-*.gem
8
- /.dat*
data/.travis.yml DELETED
@@ -1,3 +0,0 @@
1
- language: objective-c
2
- before_install: rvm use ruby-1.9.3-p392
3
- before_script: sudo chown -R travis ~/Library/RubyMotion
data/CHANGES.md DELETED
@@ -1,26 +0,0 @@
1
- v0.2.0
2
- ------
3
-
4
- - Stylesheets are no longer constants. Instead, they can be fetched by name: `Teacup::Stylesheet[:iphone]`
5
- - Stylesheets can be assigned by calling the `stylesheet :stylesheet_name` inside a view controller.
6
- - Ability to style based on view class.
7
- - Support for orientation-based styles.
8
-
9
-
10
- v0.1.0
11
- ------
12
-
13
- Working code! Uses finalized proposal, but changes are still happenin'.
14
-
15
- v0.0.0
16
- ------
17
-
18
- Proposals. They have been merged into a finalized proposal, based mostly on
19
- ConradIrwin's stylesheets and a declaritive layout DSL that emerged from
20
- discussions
21
-
22
- embryo
23
- ------
24
-
25
- It will be known as "teacup".
26
-
data/Gemfile DELETED
@@ -1,9 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- group :test, :development do
4
- gem 'rake'
5
- end
6
-
7
- gem 'motion-layout'
8
-
9
- gemspec
data/Gemfile.lock DELETED
@@ -1,18 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- teacup (2.1.13)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- motion-layout (0.0.1)
10
- rake (0.9.2)
11
-
12
- PLATFORMS
13
- ruby
14
-
15
- DEPENDENCIES
16
- motion-layout
17
- rake
18
- teacup!
data/LICENSE DELETED
@@ -1,26 +0,0 @@
1
- Copyright (c) 2012, rubymotion community
2
- All rights reserved.
3
-
4
- Redistribution and use in source and binary forms, with or without
5
- modification, are permitted provided that the following conditions are met:
6
-
7
- 1. Redistributions of source code must retain the above copyright notice, this
8
- list of conditions and the following disclaimer.
9
- 2. Redistributions in binary form must reproduce the above copyright notice,
10
- this list of conditions and the following disclaimer in the documentation
11
- and/or other materials provided with the distribution.
12
-
13
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17
- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
-
24
- The views and conclusions contained in the software and documentation are those
25
- of the authors and should not be interpreted as representing official policies,
26
- either expressed or implied, of the Teacup Project.
data/README.md DELETED
@@ -1,1527 +0,0 @@
1
- Teacup
2
- ======
3
-
4
- A community-driven DSL for creating user interfaces on iOS and OS X.
5
-
6
- [![Build Status](https://travis-ci.org/rubymotion/teacup.png)](https://travis-ci.org/rubymotion/teacup)
7
-
8
- Using Teacup, you can create and style layouts and keeping your code dry. The
9
- goal is to offer a rubyesque (well, actually a rubymotion-esque) way to create
10
- interfaces programmatically.
11
-
12
- **Check out some sample apps!**
13
-
14
- * iOS
15
- * “[Hai][Hai]”
16
- * “[AutoLayout][AutoLayout]”
17
- * “[Sweettea Example][sweettea-example]”
18
- * OS X
19
- * “[Tweets][Tweets]” - ported from [RubyMotionSamples][]
20
- * “[simple][]”
21
-
22
- [Hai]: https://github.com/rubymotion/teacup/tree/master/samples/ios/Hai
23
- [AutoLayout]: https://github.com/rubymotion/teacup/tree/master/samples/ios/AutoLayout
24
- [sweettea-example]: https://github.com/rubymotion/teacup/tree/master/samples/ios/sweettea-example
25
-
26
- [Tweets]: https://github.com/rubymotion/teacup/tree/master/samples/osx/Tweets
27
- [simple]: https://github.com/rubymotion/teacup/tree/master/samples/osx/simple
28
-
29
- [RubyMotionSamples]: https://github.com/HipByte/RubyMotionSamples/tree/master/osx/Tweets
30
-
31
- **Quick Install**
32
-
33
- ```bash
34
- > gem install teacup
35
- ```
36
- and in your Rakefile
37
- ```ruby
38
- require 'teacup'
39
- ```
40
-
41
- #### 10 second primer, iOS
42
-
43
- 1. Create a `UIViewController` subclass:
44
-
45
- ```ruby
46
- class MyController < UIViewController
47
- ```
48
- 2. Assign a stylesheet name:
49
-
50
- ```ruby
51
- class MyController < UIViewController
52
- stylesheet :main_screen
53
- ```
54
- 3. Create a layout:
55
-
56
- ```ruby
57
- class MyController < UIViewController
58
- stylesheet :main_screen
59
-
60
- layout do
61
- subview(UIButton, :hi_button)
62
- end
63
- end
64
- ```
65
- 4. Create the stylesheet (in `app/styles/` or somewhere near the controller)
66
-
67
- ```ruby
68
- Teacup::Stylesheet.new :main_screen do
69
- style :hi_button,
70
- origin: [10, 10],
71
- title: 'Hi!'
72
- end
73
- ```
74
-
75
- #### 10 second primer, OS X
76
-
77
- Pretty much the same! Note that on OS X, view coordinates are based on having
78
- the origin in the bottom-left corner, not the upper-left like it is *on every
79
- other GUI system ever*. :-|
80
-
81
- **You should use the `TeacupWindowController` parent class instead of `NSWindowController`**
82
-
83
- 1. Create a `TeacupWindowController` subclass.
84
-
85
- ```ruby
86
- class MyController < TeacupWindowController
87
- ```
88
- 2. Assign a stylesheet name:
89
-
90
- ```ruby
91
- class MyController < TeacupWindowController
92
- stylesheet :main_window
93
- ```
94
- 3. Create a layout:
95
-
96
- ```ruby
97
- class MyController < TeacupWindowController
98
- stylesheet :main_window
99
-
100
- layout do
101
- subview(NSButton, :hi_button)
102
- end
103
- end
104
- ```
105
- 4. Create the stylesheet (in `app/styles/` or somewhere near the controller)
106
-
107
- ```ruby
108
- Teacup::Stylesheet.new :main_window do
109
- style :hi_button,
110
- origin: [10, 10],
111
- title: 'Hi!'
112
- end
113
- ```
114
-
115
- Teacup
116
- ------
117
-
118
- Teacup's goal is to facilitate the creation and styling of your view hierarchy.
119
- Say "Goodbye!" to Xcode & XIB files!
120
-
121
- Teacup is composed of two systems:
122
-
123
- - Layouts
124
- A DSL to create Views and to organize them in a hierarchy. You assign the
125
- style name and style classes from these methods.
126
-
127
- - Stylesheets
128
- Store the "styles" that get applied to your views. The stylesheet DSL is
129
- meant to resemble CSS, but is targeted at iOS, and so the precedence rules are
130
- very different.
131
-
132
- Teacup supports [Pixate][] and [NUI][], too, so you can use those systems for
133
- styling and Teacup to manage your view hierarchy and apply auto-layout
134
- constraints. Teacup can also integrate with the [motion-layout][] gem!
135
-
136
- ### Table of Contents
137
-
138
- * [Layouts](#layouts)
139
- * [Stylesheets](#stylesheets)
140
- * [Using and re-using styles in a Stylesheet](#using-and-re-using-styles-in-a-stylesheet)
141
- * [Style via Stylename](#style-via-stylename)
142
- * [Extending Styles](#extending-styles)
143
- * [Style via View Class](#style-via-view-class)
144
- * [Importing stylesheets](#importing-stylesheets)
145
- * [Style via UIAppearance](#style-via-uiappearance) (iOS only)
146
- * [UITableViews](#uitableviews) - This is important if you are using styles and
147
- constraints in a `UITableViewDelegate`.
148
- * [More Teacup features](#more-teacup-features)
149
- * [Styling View Properties](#styling-view-properties)
150
- * [Orientation Styles](#orientation-styles) (iOS only)
151
- * [Animation additions](#animation-additions)
152
- * [Style Handlers](#style-handlers)
153
- * [Frame Calculations](#frame-calculations)
154
- * [Auto-Layout](#auto-layout)
155
- * [Motion-Layout](#motion-layout)
156
- * [Stylesheet extensions](#stylesheet-extensions)
157
- * [Autoresizing Masks](#autoresizing-masks)
158
- * [Device detection](#device-detection) (iOS only)
159
- * [Rotation helpers](#rotation-helpers) (iOS only)
160
- * [Showdown](#showdown)
161
- * [The Nitty Gritty](#the-nitty-gritty)
162
- * [Advanced Teacup Tricks](#advanced-teacup-tricks)
163
- * [Including `Teacup::Layout` on arbitrary classes](#including-teacup-layout-on-arbitrary-classes)
164
- * [Sweettea](#sweettea)
165
- * [Misc notes](#misc-notes)
166
- * [The Dummy](#the-dummy)
167
-
168
- Layouts
169
- -------
170
-
171
- The `Teacup::Layout` module is mixed into `UIViewController` and `UIView` on
172
- iOS, and `NSWindowController`, `NSViewController`, and `NSView` on OS X. These
173
- classes can take advantage of the view-hierarchy DSL.
174
-
175
- You saw an example in the primer, using the
176
- `UIViewController`/`NSWindowController` class method `layout`. This is a helper
177
- function that stores the layout code. A more direct example might look like
178
- this:
179
-
180
- ```ruby
181
- # controller example
182
- class MyController < UIViewController
183
-
184
- def viewDidLoad
185
- # we will modify the controller's `view`, assigning it the stylename `:root`
186
- layout(self.view, :root) do
187
- # these subviews will be added to `self.view`
188
- subview(UIToolbar, :toolbar)
189
- subview(UIButton, :hi_button)
190
- end
191
- end
192
-
193
- end
194
- ```
195
-
196
- You can use very similar code in your view subclasses.
197
-
198
- ```ruby
199
- # view example
200
- #
201
- # if you use Teacup in all your projects, you can bundle your custom views with
202
- # their own stylesheets
203
- def MyView < UIView
204
-
205
- def initWithFrame(frame)
206
- super.tap do
207
- self.stylesheet = :my_stylesheet
208
- subview(UIImageView, :image)
209
- end
210
- end
211
-
212
- end
213
- ```
214
-
215
- The `layout` and `subview` methods are the work horses of the Teacup view DSL.
216
-
217
- * `layout(view|ViewClass, stylename, style_classes, additional_styles, &block)`
218
- - `view|ViewClass` - You can layout an existing class or you can have Teacup
219
- create it for you (it just calls `new` on the class, nothing special). This
220
- argument is required.
221
- - `stylename` (`Symbol`) - This is the name of a style in your stylesheet. It
222
- is optional
223
- - `style_classes` (`[Symbol,...]`) - Other stylenames, they have lower
224
- priority than the `stylename`.
225
- - `additional_styles` (`Hash`) - You can pass other styles in here as well,
226
- either to override or augment the settings from the `Stylesheet`. It is
227
- common to use this feature to assign the `delegate` or `dataSource`.
228
- - `&block` - See discussion below
229
- - Returns the `view` that was created or passed to `layout`.
230
- - only the `view` arg is required. You can pass any combination of
231
- stylename, style_classes, and additional_styles (some, none, or all).
232
- * `subview(view|UIViewClass, stylename, style_classes, additional_styles, &block)`
233
- - Identical to `layout`, but adds the view to the current target
234
-
235
- The reason it is so easy to define view hierarchies in Teacup is because the
236
- `layout` and `subview` methods can be "nested" by passing a block.
237
-
238
- ```ruby
239
- subview(UIView, :container) do # create a UIView instance and give it the stylename :container
240
- subview(UIView, :inputs) do # create another container
241
- @email_input = subview(UITextField, :email_input)
242
- @password_input = subview(UITextField, :password_input)
243
- end
244
- subview(UIButton.buttonWithType(UIButtonTypeRoundedRect), :submit_button)
245
- end
246
- ```
247
-
248
- These methods are defined in the `Layout` module. And guess what!? It's easy
249
- to add your *own view helpers*! I refer to this as a "partials" system, but
250
- really it's just Ruby code (and isn't that the best system?).
251
-
252
- ```ruby
253
- # the methods you add here will be available in UIView/NSview,
254
- # UIViewController/NSViewController/NSWindowController, and any of your own
255
- # classes that `include Teacup::Layout`
256
- module Teacup::Layout
257
-
258
- # creates a button and assigns a default stylename
259
- def button(*args, &block)
260
- # apply a default stylename
261
- args = [:button] if args.empty?
262
-
263
- # instantiate a button and give it a style class
264
- subview(UIButton.buttonWithType(UIButtonTypeCustom), *args, &block)
265
- end
266
-
267
- # creates a button with an icon image and label
268
- def button_with_icon(icon, title)
269
- label = UILabel.new
270
- label.text = title
271
- label.sizeToFit
272
-
273
- image_view = UIImageView.new
274
- image_view.image = icon
275
- image_view.sizeToFit
276
-
277
- button = UIButton.buttonWithType(UIButtonTypeCustom)
278
- button.addSubview(image_view)
279
- button.addSubview(label)
280
-
281
- # code could go here to position the icon and label, or at could be handled
282
- # by the stylesheet
283
-
284
- subview(button)
285
- end
286
-
287
- end
288
- ```
289
- ###### example use of the helper methods
290
- ```
291
- class MyController < UIViewController
292
-
293
- layout do
294
- @button1 = button()
295
- @button2 = button(:blue_button)
296
- @button3 = button_with_icon(UIImage.imageNamed('email_icon'), 'Email')
297
- end
298
-
299
- end
300
- ```
301
-
302
- The `Controller##layout` method that has been used so far is going to be
303
- the first or second thing you add to a controller when you are building an app
304
- with Teacup. It's method signature is
305
-
306
- ```ruby
307
- # defined in teacup/teacup_controller.rb as Teacup::Controller module
308
- UIViewController.layout(stylename=nil, styles={}, &block)
309
- NSViewController.layout(stylename=nil, styles={}, &block)
310
- NSWindowController.layout(stylename=nil, styles={}, &block)
311
- ```
312
-
313
- * `stylename` is the stylename you want applied to your controller's `self.view`
314
- object.
315
- * `styles` are *rarely* applied here, but one common use case is when you assign
316
- a custom view in `loadView`, and you want to apply settings to it. I find it
317
- cleaner to move this code into the body of the `layout` block, though.
318
- * `&block` is the most important - it is the layout code that will be called
319
- during `viewDidLoad`.
320
-
321
- After the views have been added and styles have been applied Teacup calls the
322
- `layoutDidLoad` method. If you need to perform some additional initialization
323
- on your views, you should do it in this method. If you use the `layout` block
324
- the styles have not yet been applied. Frames will not be set, text and titles
325
- will be empty, and images will not have images. This all happens at the *end*
326
- of the `layout` block.
327
-
328
- Stylesheets
329
- -----------
330
-
331
- This is where you will store your styling-related code. Migrating code from your
332
- controller or custom view into a stylesheet is very straightforward. The method
333
- names map 1::1.
334
-
335
- ```ruby
336
- # classic Cocoa/UIKit
337
- def viewDidLoad
338
- self.view.backgroundColor = UIColor.grayColor
339
- # ^.............^
340
- end
341
-
342
- # in Teacup
343
- def viewDidLoad
344
- self.stylesheet = :main
345
- self.view.stylename = :root
346
- end
347
-
348
- Teacup::Stylesheet.new :main do
349
- style :root,
350
- backgroundColor: UIColor.grayColor
351
- # ^.............^
352
- end
353
- ```
354
-
355
- Nice! We turned three lines of code into nine! Well, obviously the benefits
356
- come in when we have *lots* of style code, and when you need to do app-wide
357
- styling.
358
-
359
- You can store stylesheets in any file. It is common to use `app/styles.rb` or
360
- `app/styles/main.rb`, if you have more than a few of 'em. The
361
- `Teacup::Stylesheet` constructor accepts a stylesheet name and a block, which
362
- will contain your style declarations.
363
-
364
- ```ruby
365
- Teacup::Stylesheet.new :main_menu do
366
- style :ready_to_play_button,
367
- backgroundColor: UIColor.blackColor,
368
- frame: [[20, 300], [50, 20]]
369
- end
370
-
371
- Teacup::Stylesheet[:main_menu] # returns this stylesheet
372
- ```
373
-
374
- Any method that accepts a single value can be assigned in a stylesheet. Please
375
- don't abuse this by hiding application logic in your stylesheets - these are
376
- meant for *design*, not behavior.
377
-
378
- ### Using and re-using styles in a Stylesheet
379
-
380
- - Styles are be applied via stylename (`style :label`) or class (`style UILabel`)
381
- - Styles can extend other styles (`style :big_button, extends: :button`)
382
- - A stylesheet can import other stylesheets (`import :app`)
383
- - The special Appearance stylesheet can be used to apply styles to `UIAppearance`
384
- (`Teacup::Appearance.new`)
385
-
386
- Let's look at each in turn.
387
-
388
- ### Style via Stylename
389
-
390
- This is the most common way to apply a style.
391
-
392
- ```ruby
393
- class MainController < UIViewController
394
-
395
- stylesheet :main # <= assigns the stylesheet named :main to this controller
396
-
397
- layout do
398
- subview(UILabel, :h1) # <= :h1 is the stylename
399
- end
400
-
401
- end
402
-
403
- Teacup::Stylesheet.new :main do # <= stylesheet name
404
-
405
- style :h1, # <= style name
406
- font: UIFont.systemFontOfSize(20) # <= and this style is applied
407
-
408
- end
409
- ```
410
-
411
- When the stylesheet is applied (at the end of the `layout` block, when all the
412
- views have been added), its `font` property will be assigned the value
413
- `UIFont.systemFontOfSize(20)`.
414
-
415
- But we didn't assign any text!
416
-
417
- We can tackle this a couple ways. You can apply "last-minute" styles in the
418
- `layout` and `subview` methods:
419
-
420
- ```ruby
421
- layout do
422
- subview(UILabel, :h1,
423
- # the `subview` and `layout` methods can apply styles
424
- text: "Omg, it's full of stars"
425
- )
426
- end
427
- ```
428
-
429
- In this case though we just have static text, so you can assign the text using
430
- the stylesheet:
431
-
432
- ```ruby
433
- Teacup::Stylesheet.new :main do
434
-
435
- style :h1,
436
- font: UIFont.systemFontOfSize(20)
437
-
438
- style :main_header,
439
- text: "Omg, it's full of stars",
440
- font: UIFont.systemFontOfSize(20)
441
-
442
- end
443
- ```
444
-
445
- ### Extending Styles
446
-
447
- Not very DRY though is it!? We have to use a new style (`:main_header`) because
448
- not all our labels say "OMG", but we want to use our font from the `:h1` style.
449
- We can tell the `:main_header` style that it `extends` the `:h1` style:
450
-
451
- ```ruby
452
- layout do
453
- subview(UILabel, :main_header)
454
- end
455
-
456
- Teacup::Stylesheet.new :main do
457
-
458
- style :h1,
459
- font: UIFont.systemFontOfSize(20)
460
-
461
- style :main_header, extends: :h1,
462
- text: "Omg, it's full of stars"
463
-
464
- end
465
- ```
466
-
467
- A common style when writing stylesheets is to use instance variables to store
468
- settings you want to tweak.
469
-
470
- ```ruby
471
- Teacup::Stylesheet.new :main do
472
- @hi_font = UIFont.systemFontOfSize(20)
473
-
474
- style :h1,
475
- font: @hi_font
476
- style :main_header, extends: :h1,
477
- text: "Omg, it's full of stars"
478
- end
479
- ```
480
-
481
- ### Style via View Class
482
-
483
- If you need to apply styles to *all* instances of a `UIView`/`NSView` subclass,
484
- you can do so by applying styles to a class name instead of a symbol. This
485
- feature is handy at times when you might otherwise use `UIAppearance` (which
486
- teacup also supports!).
487
-
488
- ```ruby
489
- Teacup::Stylesheet.new :app do
490
-
491
- style UILabel,
492
- font: UIFont.systemFontOfSize(20)
493
-
494
- style UITableView,
495
- backgroundColor: UIColor.blackColor
496
-
497
- end
498
- ```
499
-
500
- ### Importing stylesheets
501
-
502
- We've touched on the ability to write styles, extend styles, and apply styles to
503
- a class. Now we can introduce another feature that is even more useful for
504
- applying styles to your entire app: import a stylesheet.
505
-
506
- When you import a stylesheet, you receive all of its `style`s *and* you gain
507
- access to its instance variables. This way you can define colors and margins and
508
- such in a "parent" stylesheet.
509
-
510
- ```ruby
511
- Teacup::Stylesheet.new :app do
512
-
513
- @header_color = UIColor.colorWithRed(7/255.0, green:16/255.0, blue:95/255.0, alpha: 1)
514
- @background_color = UIColor.colorWithRed(216/255.0, green:226/255.0, blue:189/255.0, alpha: 1)
515
-
516
- style :root,
517
- backgroundColor: @background_color
518
-
519
- style :header,
520
- textColor: @header_color
521
-
522
- end
523
-
524
- Teacup::Stylesheet.new :main do
525
- import :app
526
-
527
- style :subheader, extends: :header # <= the :header style is imported from the :app stylesheet
528
-
529
- style :button,
530
- titleColor: @header_color # <= @header_color is imported, too
531
- end
532
- ```
533
-
534
- ### Style via UIAppearance
535
-
536
- *iOS only*
537
-
538
- And lastly, the `UIAppearance protocol` is supported by creating an instance of
539
- `Teacup::Appearance`. There is debatable benefit to using [UIAppearance][],
540
- because it will apply styles to views that are outside your control, like the
541
- camera/image pickers and email/message controllers.
542
-
543
- But, it does come in handy sometimes... so here it is!
544
-
545
- ```ruby
546
- Teacup::Appearance.new do
547
-
548
- # UINavigationBar.appearance.setTintColor(UIColor.blackColor)
549
- style UINavigationBar,
550
- tintColor: UIColor.blackColor
551
-
552
- # UINavigationBar.appearanceWhenContainedIn(UINavigationBar, nil).setTintColor(UIColor.blackColor)
553
- style UIBarButtonItem, when_contained_in: UINavigationBar,
554
- tintColor: UIColor.blackColor
555
-
556
- # UINavigationBar.appearanceWhenContainedIn(UIToolbar, UIPopoverController, nil).setTintColor(UIColor.blackColor)
557
- style UIBarButtonItem, when_contained_in: [UIToolbar, UIPopoverController],
558
- tintColor: UIColor.blackColor
559
-
560
- end
561
- ```
562
-
563
- In your AppDelegate you need to call `Teacup::Appearance.apply`. It will get
564
- called automatically using the `UIApplicationDidFinishLaunchingNotification`,
565
- but that notification is triggered *after* the method
566
- `AppDelegate#didFinishLaunching(withOptions:)` is called.
567
-
568
- ###### app_delegate.rb
569
- ```ruby
570
- class AppDelegate
571
- def didFinishLaunching(application, withOptions:options)
572
- Teacup::Appearance.apply
573
-
574
- @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
575
- ctlr = MainController.new
576
- @window.rootViewController = UINavigationController.alloc.initWithRootController(ctlr)
577
- @window.makeKeyAndVisible
578
-
579
- true
580
- end
581
-
582
- end
583
- ```
584
-
585
- That block is called using the `UIApplicationDidFinishLaunchingNotification`,
586
- but that notification is not called until the *end* of the
587
- `application(application,didFinishLaunchingWithOptions:launchOptions)` method.
588
- This is sometimes after your views have been created, and so they will not be
589
- styled. If that is the case, call `Teacup::Appearance.apply` before creating
590
- your `rootViewController`.
591
-
592
- ### Now go use Teacup!
593
-
594
- You have enough information *right now* to go play with Teacup. Check out the
595
- example apps, write your own, whatever. But read on to hear about why Teacup is
596
- more than just writing `layouts` and applying styles.
597
-
598
- Teacup as a utility
599
- -------------------
600
-
601
- When you are prototyping an app it is useful to bang out a bunch of code
602
- quickly, and here are some ways that Teacup might help.
603
-
604
- You can use all the methods above without having to rely on the entirety of
605
- Teacup's layout and stylesheet systems. By that I mean *any* time you are
606
- creating a view hierarchy don't be shy about using Teacup to do it.
607
-
608
- `UIView` and `NSView` have the `style` method, which can be used to group a
609
- bunch of customizations anywhere in your code. You don't *have* to pull out a
610
- stylesheet to do it.
611
-
612
- ```ruby
613
- # Custom Navigation Title created and styled by Teacup
614
- self.navigationItem.titleView = layout(UILabel,
615
- text:'Title',
616
- font: UIFont.systemFontOfSize(12),
617
- )
618
-
619
- # Customize contentView in a UITableViewCell dataSource method
620
- def tableView(table_view, cellForRowAtIndexPath:index_path)
621
- cell_identifier = 'MyController - cell'
622
- cell = table_view.dequeueReusableCellWithIdentifier(cell_identifier)
623
-
624
- unless cell
625
- cell = UITableViewCell.alloc.initWithStyle(UITableViewCellStyleDefault,
626
- reuseIdentifier: cell_identifier)
627
- layout(cell.contentView) do
628
- subview(UIImageView, :image)
629
- end
630
- end
631
-
632
- return cell
633
- end
634
-
635
- # Use the `style` method on a view to apply your styling. This is a one-shot
636
- # styling.
637
- @label.style(textColor: UIColor.blueColor, text: 'Blue Label')
638
- ```
639
-
640
- UITableViews
641
- ------------
642
-
643
- Teacup is designed to be used in coordination with the controller life cycle,
644
- but there are other life cycles that need to be considered as well.
645
- UITableViews maintain a "queue" of cells that can be reused, and they need to be
646
- restyled when the cell is created and re-used.
647
-
648
- The solution is to apply the styles and layout constraints inside the
649
- `tableView:willDisplayCell:forRowAtIndexPath:` delegate method. In your
650
- delegate, if you include the `Teacup::TableViewDelegate` module, you'll get this
651
- behavior for free, and if you override this method, you can call `super` to have
652
- the Teacup method run.
653
-
654
- ```ruby
655
- class TableViewController < UITableViewController
656
- include Teacup::TableViewDelegate
657
-
658
- stylesheet :table
659
-
660
- def tableView(table_view, cellForRowAtIndexPath:index_path)
661
- cell = table_view.dequeueReusableCellWithIdentifier('cell id')
662
-
663
- layout(cell.contentView, :root) do
664
- cell.title_label = subview(UILabel, :title_label, :text => "title #{index_path.row}")
665
- cell.details_label = subview(UILabel, :details_label, :text => "details #{index_path.row}")
666
- cell.other_label = subview(UILabel, :other_label, :text => "other #{index_path.row}")
667
- end
668
-
669
- return cell
670
- end
671
-
672
- # This method is implemented by the Teacup::TableViewDelegate. If you need
673
- # to implement it, be sure to call super.
674
- # def tableView(tableView, willDisplayCell:cell, forRowAtIndexPath:indexPath)
675
- # super
676
- # end
677
- end
678
- ```
679
-
680
- Constraints and styles get applied before the view appears, even if the cell is
681
- reused later.
682
-
683
- More Teacup features
684
- --------------------
685
-
686
- There are a few (OK, a bunch) more features that Teacup provides that deserve
687
- discussion:
688
-
689
- - Styling View Properties
690
- - Orientation Styles
691
- - View Class Additions
692
- - Style Handlers
693
- - Frame Calculations
694
- - Auto-Layout & [Motion-Layout][motion-layout]
695
- - Stylesheet Extensions
696
-
697
- ### Styling View Properties
698
-
699
- Styling a UIView is fun, but a UIView is often composed of many objects, like
700
- the `layer`, or maybe an `imageView` or `textLabel` and so on. You can style
701
- those, too!
702
-
703
- ```ruby
704
- # UITableViewCells have a contentView, a backgroundView, imageView, textLabel,
705
- # detailTextLabel, and a layer! whew!
706
- style :tablecell,
707
- layer: { # style the layer!
708
- shadowRadius: 3
709
- },
710
- backgroundView: { # style the background!
711
- backgroundColor: UIColor.blackColor
712
- },
713
- imageView: { # style the imageView!
714
- contentMode: UIViewContentModeScaleAspectFill
715
- }
716
- ```
717
-
718
- ### Orientation Styles
719
-
720
- *iOS only*
721
-
722
- There's more to stylesheets than just translating `UIView` setters. Teacup can
723
- also apply orientation-specific styles. These are applied when the view is
724
- created (using the current device orientation) and when a rotation occurs.
725
-
726
- ```ruby
727
- Teacup::Stylesheet.new :main do
728
-
729
- # this label hides when the orientation is landscape (left or right)
730
- style :label,
731
- landscape: {
732
- hidden: true
733
- },
734
- portrait: {
735
- hidden: false
736
- }
737
-
738
- end
739
- ```
740
-
741
- Combine these styles with [Frame Calculations][calculations] to have you view
742
- frame recalculated automatically.
743
-
744
- ### Animation additions
745
-
746
- We've already seen the Teacup related properties:
747
-
748
- - `stylename`, the primary style name
749
- - `style_classes`, secondary style names
750
- - `style`, apply styles directly
751
-
752
- Each of these has a corresponding method that you can use to facilitate
753
- animations.
754
-
755
- - `animate_to_stylename(stylename)`
756
- - `animate_to_styles(style_classes)`
757
- - `animate_to_style(properties)`
758
-
759
- On OS X you have to use the `view.animator` property to perform animations.
760
- This is supported, but it's kind of "hacky".
761
-
762
- ### Style Handlers
763
-
764
- *This feature is used extensively by [sweettea][] to make a more intuitive
765
- stylesheet DSL*
766
-
767
- Teacup is, by itself, pretty useful, but it really does little more than map
768
- Hash keys to `UIView` setters. That's great, because it keeps the system easy
769
- to understand. But there are some methods in UIKit that take more than one
770
- argument, or could benefit from some shorthands.
771
-
772
- This is where Teacup's style handlers come in. They are matched against a
773
- `UIView` subclass and one or more stylenames, and they are used to apply that
774
- style when you use it in your stylesheet.
775
-
776
- ```ruby
777
- # this handler adds a `:title` handler to the UIButton class (and subclasses).
778
- Teacup.handler UIButton, :title do |target, title|
779
- target.setTitle(title, forState: UIControlStateNormal)
780
- end
781
-
782
- # ...
783
- subview(UIButton,
784
- title: 'This is the title' # <= this will end up being passed to the handler above
785
- )
786
-
787
- layout(UINavigationItem,
788
- title: 'This is the title' # <= but this will not! the handler above is restricted to UIButton subclasses
789
- )
790
- ```
791
-
792
- [Other built-in handlers][other-handlers] are defined in `z_handlers.rb`.
793
- Another useful one is the ability to make view the same size as its parent, and
794
- located at the origin.
795
-
796
- ```ruby
797
- style :container,
798
- frame: :full # => [[0, 0], superview.frame.size]
799
- ```
800
-
801
- [other-handlers]: https://github.com/rubymotion/teacup/tree/master/lib/teacup/z_core_extensions/z_handlers.rb
802
-
803
- ### Frame Calculations
804
-
805
- *These are super cool, just don't forget your autoresizingMasks*
806
-
807
- When positioning views you will often have situations where you want to have a
808
- view centered, or 8 pixels to the right of center, or full width/height. All of
809
- these relationships can be described using the `Teacup.calculate` method, which
810
- is called automatically in any method that modifies the `frame` or `center`.
811
-
812
- frame, origin, size
813
- top/y, left/x, right, bottom, width, height
814
- center_x/middle_x, center_y/middle_y, center
815
-
816
- ```ruby
817
- Teacup::Stylesheet.new :main do
818
-
819
- style :button,
820
- left: 8, top: 8, # easy enough!
821
- width: '100% - 16', # woah! (O_o)
822
- height: 22
823
-
824
- style :top_half,
825
- frame: [[0, 0], ['100%', '50%']]
826
- style :bottom_half,
827
- frame: [[0, '50%'], ['100%', '50%']]
828
-
829
- end
830
- ```
831
-
832
- When this code executes, the string `'100% - 16'` is translated into the formula
833
- `1.00 * target.superview.frame.size.width - 16`. If the property is related to
834
- the height or y-position, it will be calculated based on the height.
835
-
836
- The frame calculations must be a string of the form `/[0-9]+% [+-] [0-9]+/`. If
837
- you need more "math-y-ness" than that, you can construct strings using interpolation.
838
-
839
- ```ruby
840
- margin = 8
841
-
842
- style :button,
843
- left: margin, top: margin,
844
- width: "100% - #{margin * 2}",
845
- height: 22
846
-
847
- # just for fun, let's see what it would take to add a margin between these two views.
848
- style :top_half,
849
- frame: [[0, 0], ['100%', "50% - #{margin / 2}"]]
850
- style :bottom_half,
851
- frame: [[0, "50% + #{margin / 2}"], ['100%', "50% - #{margin / 2}"]]
852
- ```
853
-
854
- One more example: The real power of the frame calculations comes when you
855
- remember to set springs and struts. You can have a view "pinned" to the bottom
856
- if you remember to set the `autoresizingMask`.
857
-
858
- ```ruby
859
- Teacup::Stylesheet.new :main do
860
-
861
- style :button,
862
- # fixed width / height
863
- height: 22, width: 200,
864
- center_x: '50%',
865
- top: '100% - 30', # includes an 8px margin from the bottom
866
- autoresizingMask: (UIViewAutoresizingFlexibleLeftMargin |
867
- UIViewAutoresizingFlexibleRightMargin |
868
- UIViewAutoresizingFlexibleTopMargin)
869
- # see the autoresizing extension below for an even better way to write this.
870
- end
871
- ```
872
-
873
- ### Auto-Layout
874
-
875
- *This is another much bigger topic than it is given space for here*
876
-
877
- Teacup includes an Auto-Layout constraint DSL that you can use in your
878
- stylesheets. These methods are added to the `Stylesheet` class, so unless you
879
- are in the context of a stylesheet, you will have to create your constraints in
880
- longhand (you can still use the `Teacup::Constraint` class to help you!).
881
-
882
- I won't sugar-coat it: Auto-Layout is hard. Much harder than using frames and
883
- springs and struts. And honestly, I recommend you try using the
884
- `Teacup.calculate` features mentioned above, they will take you far.
885
-
886
- But at the end of the day, once you really understand the auto-layout system
887
- that Apple released in iOS 6, you can build your UIs to be responsive to
888
- different devices, orientations, and sizes. UIs built with auto-layout do not
889
- usually need to adjust anything during a rotation. The constraints take *care*
890
- of it all. It's impressive.
891
-
892
- Here's a quick example that creates this shape. The edges are bound to the
893
- superview's frame.
894
-
895
- +-----+----------------+
896
- | | |
897
- | A | B |
898
- | | +-----| <\
899
- | | | C | |_ 50% of B's height, minus 10 pixels
900
- +-----+----------+-----+ </
901
- ^--+--^ ^--+--^
902
- |_fixed (100) |_fixed (100)
903
-
904
- ```ruby
905
- Teacup::Stylesheet.new do
906
- style :A,
907
- constraints: [
908
- # these first three are all fixed, so super easy
909
- constrain_left(0),
910
- constrain_width(100),
911
- constrain_top(0),
912
- # here we go, here's a real constraint
913
- constrain(:bottom).equals(:superview, :bottom),
914
- ]
915
-
916
- style :B,
917
- constraints: [
918
- # B.left == A.right
919
- constrain(:left).equals(:A, :right),
920
- # B.height == A.height
921
- constrain(:height).equals(:A, :height),
922
- constrain(:right).equals(:superview, :right),
923
- ]
924
-
925
- style :C, # <= this looks like a very grumpy style :C
926
- constraints: [
927
- constrain_width(100),
928
- # pin to bottom-right corner
929
- constrain(:right).equals(:superview, :right),
930
- constrain(:bottom).equals(:superview, :bottom),
931
- # 50% B.height - 10
932
- constrain(:height).equals(:B, :height).times(0.5).minus(10),
933
- ]
934
-
935
- end
936
- ```
937
-
938
- Writing views this way will either make your brain hurt, or make the math-nerd
939
- in you chuckle with glee. In this example you could go completely with just
940
- frame calculation formulas and springs and struts. Your frame code would still
941
- be cluttered, just cluttered in a different way.
942
-
943
- If you need to reset the list of constraints managed by Teacup, you can call
944
- `reset_constraints` before you add the new styles to a UIView. This can be
945
- useful when you need to define a new set of layout constraints for a dynamic
946
- set of views.
947
-
948
- This works on OS X and iOS, and you don't have to go changing the idea of "top"
949
- and "bottom" even though OS X uses reversed frames.
950
-
951
- ### Motion-Layout
952
-
953
- If you are using [Nick Quaranto][qrush]'s [motion-layout][] gem, you can use it
954
- from within any class that includes `Teacup::Layout`. Then benefit is that the
955
- Teacup stylenames assigned to your views will be used in the dictionary that the
956
- ASCII-based system relies on.
957
-
958
- ```ruby
959
- layout do
960
- subview(UIView, :view_a)
961
- subview(UIView, :view_b)
962
- subview(UIView, :view_c)
963
-
964
- # if you need to apply these to a different view, or if you want to assign
965
- # different names to use in the ASCII strings
966
- # auto(layout_view=self.view, layout_subviews={}, &layout_block)
967
-
968
- auto do
969
- metrics 'margin' => 20
970
- vertical "|-[view_a]-margin-[view_b]-margin-[view_c]-|"
971
- horizontal "|-margin-[view_a]-margin-|"
972
- horizontal "|-margin-[view_b]-margin-|"
973
- horizontal "|-margin-[view_c]-margin-|"
974
- end
975
- end
976
-
977
- ```
978
-
979
- ### Stylesheet extensions
980
-
981
- Auto-Layout is just one Stylesheet extension, there are a few others. And if
982
- you want to write your own, just open up the `Teacup::Stylesheet` class and
983
- start adding methods.
984
-
985
- #### Autoresizing Masks
986
-
987
- If you've used the SugarCube `uiautoresizingmask` methods, you'll recognize
988
- these. They are handy, and hopefully intuitive, shorthands for common springs
989
- and struts.
990
-
991
- In previous versions of Teacup these were available without needing the
992
- `autoresize` prefix. The old methods are still available, but deprecated.
993
-
994
- ```ruby
995
- # keeps the width and height in proportion to the parent view
996
- style :container,
997
- autoresizingMask: autoresize.flexible_width | autoresize.flexible_height
998
-
999
- # the same, but using block syntax
1000
- style :container,
1001
- autoresizingMask: autoresize { flexible_width | flexible_height }
1002
-
1003
- # the same again, using a shorthand
1004
- style :container,
1005
- autoresizingMask: autoresize.fill
1006
- ```
1007
-
1008
- The autoresize methods are grouped into four categories: `flexible, fill, fixed,
1009
- and float`. The flexible methods correspond 1::1 with the `UIViewAutoresizing*`
1010
- constants.
1011
-
1012
- The `fill` methods (`fill,fill_top,fill_bottom,fill_left,fill_right`) will
1013
- stretch the width, or height, or both. The location specifies where the view is
1014
- pinned, so `fill_top` will stretch the width and bottom margin, but keep it the
1015
- same distance from the top (not necessarily *at* the top, but a fixed distance).
1016
- `fill_right` will pin it to the right side, stretch the height, and have a
1017
- flexible left margin.
1018
-
1019
- The `fixed` methods pin the view to one of nine locations:
1020
-
1021
- top_left | top_middle | top_right
1022
- ------------+---------------+-------------
1023
- middle_left | middle | middle_right
1024
- ------------+---------------+-------------
1025
- bottom_left | bottom_middle | bottom_right
1026
-
1027
- e.g. fixed_top_left, fixed_middle, fixed_bottom_right
1028
-
1029
- The `float` methods fill in the last gap, when you don't want your view pinned
1030
- to any corner, and you don't want it to change size.
1031
-
1032
- # incidentally:
1033
- float_horizontal | float_vertical == fixed_middle
1034
-
1035
- #### Device detection
1036
-
1037
- *iOS only*
1038
-
1039
- Because the stylesheets are defined in a block, you can perform tests for device
1040
- and screen size before setting styles. For instance, on an ipad you might want
1041
- to have a larger margin than on the iphone.
1042
-
1043
- The `Stylesheet` device methods will help you create these conditions:
1044
-
1045
- ```ruby
1046
- Teacup::Stylesheet.new do
1047
- if device_is? iPhone
1048
- margin = 8
1049
- elsif device_is? iPad
1050
- margin = 20
1051
- end
1052
-
1053
- style :container,
1054
- frame: [[margin, margin], ["100% - #{margin * 2}", "100% * #{margin * 2}"]]
1055
- end
1056
- ```
1057
-
1058
- Multiple calls to `style` will *add* those styles, not replace. So this code
1059
- works just fine:
1060
-
1061
- ```ruby
1062
- Teacup::Stylesheet.new do
1063
- style :logo,
1064
- origin: [0, 0]
1065
-
1066
- if device_is? iPhone
1067
- style :logo, image: UIImage.imageNamed "small logo"
1068
- elsif device_is? iPad
1069
- style :logo, image: UIImage.imageNamed "big logo"
1070
- end
1071
- end
1072
- ```
1073
-
1074
- #### Rotation helpers
1075
-
1076
- *iOS only*
1077
-
1078
- Because you can animate changes to the stylename or style_classes, you can make
1079
- it pretty easy to apply rotation effects to a `UIView` or `CALayer`. The
1080
- `style_classes` property is especially useful for this purpose.
1081
-
1082
- ```ruby
1083
- style :container,
1084
- frame: :full
1085
-
1086
- # UIView transforms
1087
-
1088
- style :rotated,
1089
- transform: transform_view.rotate(pi / 2) # pi and transform_view are methods on Stylesheet
1090
-
1091
- style :not_rotated,
1092
- transform: transform_view.rotate(0)
1093
-
1094
- # CALayer transforms
1095
-
1096
- style :rotated,
1097
- layer: { transform: transform_layer.rotate(pi / 2) }
1098
-
1099
- style :not_rotated,
1100
- layer: { transform: transform_layer.rotate(0) }
1101
- ```
1102
-
1103
- These work even better when used with the [geomotion][] methods that extend
1104
- `CGAffineTransform` and `CATransform3D`.
1105
-
1106
- ```ruby
1107
- style :goofy,
1108
- transform: CGAffineTransform.rotate(pi / 2).translate(100, 0).scale(2)
1109
- style :regular,
1110
- transform: CGAffineTransform.identity
1111
-
1112
- # CALayer uses CATransform3D objects
1113
- style :regular,
1114
- layer: {
1115
- transform: CATransform3D.rotate(pi / 2)
1116
- }
1117
- ```
1118
-
1119
- ### Showdown
1120
-
1121
- As a recap, here is a translation of traditional Cocoa code done using Teacup.
1122
-
1123
- No cool tricks here, just some plain ol' Cocoa.
1124
-
1125
- ```ruby
1126
- #
1127
- # Traditional Cocoa
1128
- #
1129
- class SomeController < UIViewController
1130
-
1131
- def viewDidLoad
1132
- @field = UITextField.new
1133
- @field.frame = [[10, 10], [200, 50]]
1134
- @field.textColor = UIColor.redColor
1135
- view.addSubview(@field)
1136
-
1137
- @search = UITextField.new
1138
- @search.frame = [[10, 70], [200, 50]]
1139
- @search.placeholder = 'Find something...'
1140
- @search.textColor = UIColor.redColor
1141
- view.addSubview(@search)
1142
- end
1143
-
1144
- # perform the frame changes depending on orientation
1145
- def willAnimateRotationToInterfaceOrientation(orientation, duration:duration)
1146
- case orientation
1147
- when UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationLandscapeRight
1148
- @field.frame = [[10, 10], [360, 50]]
1149
- @search.frame = [[10, 70], [360, 50]]
1150
- else
1151
- @field.frame = [[10, 10], [200, 50]]
1152
- @search.frame = [[10, 70], [200, 50]]
1153
- end
1154
- end
1155
-
1156
- end
1157
-
1158
- #
1159
- # Teacup
1160
- #
1161
-
1162
- class SomeController < UIViewController
1163
-
1164
- stylesheet :some_view
1165
-
1166
- layout :root do
1167
- subview(UITextField, :field)
1168
- @search = subview(UITextField, :search)
1169
- end
1170
-
1171
- end
1172
-
1173
- Teacup::Stylesheet.new(:some_view) do
1174
-
1175
- style :root, # enable landscape rotation (otherwise only portrait is enabled)
1176
- landscape: true # this must be on the root-view, to indicate that this view is
1177
- # capable of handling rotations
1178
-
1179
- style :field,
1180
- left: 10,
1181
- top: 10,
1182
- width: 200,
1183
- height: 50,
1184
- landscape: {
1185
- width: 360 # make it wide in landscape view
1186
- }
1187
-
1188
- style :search, extends: :field,
1189
- left: 10,
1190
- top: 70,
1191
- placeholder: 'Find something...'
1192
-
1193
- style UITextField, # Defining styles based on view class instead
1194
- textColor: UIColor.redColor # of style name.
1195
-
1196
- end
1197
- ```
1198
-
1199
- The Nitty Gritty
1200
- ----------------
1201
-
1202
- #### Regarding Style Precedence
1203
-
1204
- You need to be careful when extending styles and using orientation styles
1205
- because the precedence rules take some getting used to. The goal is that you
1206
- can have all your style code in the stylesheets. But you also need to be able
1207
- to animate your views, and rotating the device should not go reseting
1208
- everything.
1209
-
1210
- So here's what happens.
1211
-
1212
- When your controller is loaded, `viewDidLoad` is called, and that's where Teacup
1213
- creates the view hierarchy and applies the styles. It is at the *end* of the
1214
- method that the styles are applied - not until all the views have been added.
1215
- The current device orientation will be used so that orientation-specific styles
1216
- will be applied.
1217
-
1218
- Now Teacup goes quiet for a while. Your app chugs along... until the user
1219
- rotates the device.
1220
-
1221
- If you have orientation-specific styles, they will get applied. But the
1222
- *original* styles (the "generic" styles) **will not**.
1223
-
1224
- However, there's a way around *that, too.* If you call `restyle!` on a
1225
- `UIView`, that will reapply all the original stylesheet styles - orientation
1226
- *and* generic styles.
1227
-
1228
- With me so far? Orientation styles are reapplied whenever the device is
1229
- rotated. But generic styles are only applied in `viewDidLoad` and when
1230
- `restyle!` is called explicitly.
1231
-
1232
- How does the `:extends` property affect things?
1233
-
1234
- If your stylesheet defines orientation-specific styles and "generic" styles, the
1235
- orientation-specific styles win. But if you *extend* a style that has
1236
- orientation-specific styles, your local generic styles will win.
1237
-
1238
- The more "local" styles always win - and that applies to styles that you add
1239
- using the `subview/layout` methods, too. The only time it doesn't really apply
1240
- is if you apply styles using `UIView#style` or `UIView#apply_stylename`. Those
1241
- are one-shot (they can get overwritten when `restyle!` is called).
1242
-
1243
- There are also times when you either want (or must) override (or add to) the
1244
- stylesheet styles. For instance, if you want to assign the `delegate` or
1245
- `dataSource` properties, this cannot be done from a `Stylesheet`. But that's
1246
- okay, because we have a chance to add these styles in the `subview` and `layout`
1247
- methods.
1248
-
1249
- ```ruby
1250
- layout do
1251
- subview(UITableView, delegate: self)
1252
- end
1253
- ```
1254
-
1255
- Styles applied here are one-shot. It is the exact same as assigning the
1256
- `stylename` and `style_classes` and then calling `style`. Because the
1257
- stylesheet is not necessarily applied immediately, these styles could be
1258
- overwritten before they take effect.
1259
-
1260
- ```ruby
1261
- layout do
1262
- table_view = subview(UITableView, :tableview, delegate: self,
1263
- font: UIFont.boldSystemFontOfSize(10) # the stylesheet could override this during rotation
1264
- )
1265
- end
1266
-
1267
- def layoutDidLoad
1268
- table_view.apply_stylename(:tableview_init) # this will only get applied once
1269
- end
1270
- ```
1271
-
1272
- The idea here is that the closer the style setting is to where the view is
1273
- instantiated, the higher the precedence.
1274
-
1275
- More examples!
1276
-
1277
- ```ruby
1278
- class MyController < UIViewController
1279
- stylesheet :my_sheet
1280
- layout do
1281
- subview(UILabel, :label, text: 'overrides')
1282
- end
1283
- end
1284
- Teacup::Stylesheet.new :my_sheet do
1285
- style :generic_label,
1286
- text: 'portrait',
1287
- # these get applied initially, but after being rotated they will not get
1288
- # applied again
1289
- font: UIFont.boldSystemFontOfSize(10),
1290
- textColor: UIColor.grayColor,
1291
- landscape: {
1292
- font: UIFont.boldSystemFontOfSize(12),
1293
- textColor: UIColor.whiteColor,
1294
- } # this style should add a `portrait` setting that restores the font and color
1295
-
1296
- style :label, extends: :generic_label,
1297
- font: UIFont.systemFontOfSize(10), # this will override all the font settings
1298
- end
1299
- ```
1300
-
1301
- Advanced Teacup Tricks
1302
- ----------------------
1303
-
1304
- There are times when you might wish teacup "just worked", but please remember:
1305
- Teacup is not a "blessed" framework built by Apple engineers. We have access to
1306
- the same APIs that you do. That said, here are some use-cases where you can most
1307
- definitely *use* teacup, but you'll need to do a little more leg work.
1308
-
1309
- ### Trust your parent view - by using springs and struts
1310
-
1311
- *...not autolayout*
1312
-
1313
- It's been mentioned a few times in this document that Teacup will create & style
1314
- views in the `viewDidLoad` method. That means that the `superview` property of
1315
- the controller's view will, necessarily, *not* be set yet. `viewDidLoad` is
1316
- called after the view is instantiated (in `loadView`), and it hasn't been added
1317
- as a subview yet.
1318
-
1319
- Auto-Layout is based on the relationship between two views - often a container
1320
- and child view. It's an amazing system, but if that parent view *isn't
1321
- available*, well, you're not gonna have much success.
1322
-
1323
- In the case of a UIViewController your "container" is the `self.view` property,
1324
- which by default has sensible springs setup so that it stretches to fill the
1325
- superview. It's not until you go messing with the `self.view` property, or are
1326
- not in the context of a `UIViewController` that things get hairy.
1327
-
1328
- If this is the case, you should get some pretty obvious warning messages,
1329
- something along the lines of `Could not find :superview`.
1330
-
1331
- ### Including `Teacup::Layout` on arbitrary classes
1332
-
1333
- I don't know about you, but I often write helper classes for tableviews that
1334
- appear on many screens in an app. You should not shy away from adding teacup's
1335
- `Layout` module to these helper classes.
1336
-
1337
- If you are using your controller as your table view dataSource, the `subview`
1338
- and `layout` methods continue to work as you expect them to. This is for the
1339
- case when you are using a helper class.
1340
-
1341
- ```ruby
1342
- class TableHelper
1343
- include Teacup::TableViewDelegate
1344
- include Teacup::Layout
1345
-
1346
- stylesheet :table_helper
1347
-
1348
- def tableView(table_view, cellForRowAtIndexPath:index_path)
1349
- cell_identifier = 'MyController - cell'
1350
- cell = table_view.dequeueReusableCellWithIdentifier(cell_identifier)
1351
-
1352
- unless cell
1353
- cell = UITableViewCell.alloc.initWithStyle(UITableViewCellStyleDefault
1354
- reuseIdentifier: cell_identifier)
1355
-
1356
- layout(cell.contentView) do
1357
- subview(UIImageView, :image)
1358
- end
1359
- # cell.contentView and all child classes will "inherit" the :table_helper stylesheet
1360
- end
1361
-
1362
- return cell
1363
- end
1364
-
1365
- end
1366
- ```
1367
-
1368
- ### [Sweettea][]
1369
-
1370
- *SugarCube + Teacup = Sweettea*
1371
-
1372
- SugarCube was born of a desire to make Teacup stylesheets more readable, less
1373
- cluttered with Apple's verbose method names and constants. Sweettea takes this
1374
- a step further, by implementing a wealth of Teacup handlers that translate
1375
- Symbols to constants and provide useful shorthands.
1376
-
1377
- ```ruby
1378
- style :button,
1379
- normal: { image: 'button-white' },
1380
- highlighted: { image: 'button-white-pressed' },
1381
- title: 'Submit',
1382
- shadow: {
1383
- opacity: 0.5,
1384
- radius: 3,
1385
- offset: [3, 3],
1386
- color: :black,
1387
- },
1388
- font: 'Comic Sans'
1389
-
1390
- style :label,
1391
- font: :bold,
1392
- alignment: :center,
1393
- color: :slateblue
1394
- ```
1395
-
1396
- Sweettea also offers some convenient styles that you can extend in your base
1397
- class. You might want to either specify the Sweettea version you are using in
1398
- your Gemfile, or copy the stylesheet so that changes to Sweettea don't affect
1399
- your project. Once that projet is at 1.0 you can rely on the styles not
1400
- changing.
1401
-
1402
- ```ruby
1403
- # buttons! :tan_button, :black_button, :green_button, :orange_button,
1404
- # :blue_button, :white_button, :gray_button
1405
- style :submit_button, extends: :white_button
1406
-
1407
- # label sets more sensible defaults than a "raw" UILabel (like clear background)
1408
- style :header, extends: :label
1409
-
1410
- # inputs! these are not styled, they just setup keyboard and autocomplete
1411
- # settings
1412
- # :name_input, :ascii_input, :email_input, :url_input, :number_input,
1413
- # :phone_input, :secure_input
1414
- style :login_input, extends: :email_input
1415
- style :password_input, extends: :secure_input
1416
- ```
1417
-
1418
- Misc notes
1419
- ----------
1420
-
1421
- Multiple calls to `style` with the same stylename combines styles, it doesn't
1422
- replace the styles.
1423
-
1424
- ------
1425
-
1426
- Styles are not necessarily applied immediately. They are applied at the end of
1427
- the outermost `layout/subview` method, including the `UIViewController##layout`
1428
- block. If you call `stylename=` or `stylesheet=` *outside* a `layout/subview`
1429
- block, your view will be restyled immediately.
1430
-
1431
- ------
1432
-
1433
- Restyling a view calls `restyle!` on all child views, all the way down the tree.
1434
- Much care has been taken to call this method sparingly within Teacup.
1435
-
1436
- ------
1437
-
1438
- Any styles that you apply in a `layout/subview` method are *not* retained, they
1439
- are applied immediately, and so the stylesheet can (and usually do) override
1440
- those styles if there is a conflict. Only styles stored in a stylesheet are
1441
- reapplied (during rotation or in `restyle!`).
1442
-
1443
- ------
1444
-
1445
- Stylesheets should not be modified once they are created - they cache styles by
1446
- name (per orientation).
1447
-
1448
- ------
1449
-
1450
- You can add and remove a `style_class` using `add_style_class` and
1451
- `remove_style_class`, which will call `restyle!` for you if `style_classes`
1452
- array was changed.
1453
-
1454
- ------
1455
-
1456
- If you need to do frame calculations outside of the stylesheet code, you should
1457
- do so in the `layoutDidLoad` method. This is not necessary, though! It is
1458
- usually cleaner to do the frame calculations in stylesheets, either using
1459
- [geomotion][], frame calculations, or auto-layout.
1460
-
1461
- ------
1462
-
1463
- Within a `subview/layout` block views are added to the last object in
1464
- `Layout#superview_chain`. Views are pushed and popped from this array in the
1465
- `Layout#layout` method, starting with the `top_level_view`. If you include
1466
- `Teacup::Layout` on your own class, you do not *have* to implement
1467
- `top_level_view` unless you want to use the `subview` method to add classes to a
1468
- "default" target.
1469
-
1470
- ------
1471
-
1472
- When `UIView` goes looking for its `stylesheet` it does so by going up the
1473
- responder chain. That means that if you define the stylesheet on a parent view
1474
- or controller, all the child views will use that same stylesheet by default. It
1475
- also means you can assign a stylesheet to a child view without worrying what the
1476
- parent view's stylesheet is.
1477
-
1478
- Caveat! If you implement a class that includes `Teacup::Layout`, you can assign
1479
- it a `stylesheet`. *That* stylesheet will be used by views created using
1480
- `layout` or `subview` even though your class is probably not part of the
1481
- responder chain. Saying that `UIView` inherits its `stylesheet` from the
1482
- responder chain is not accurate; it actually uses `teacup_responder`, which
1483
- defaults to `nextResponder`, but it is assigned to whatever object calls the
1484
- `layout` method on the view.
1485
-
1486
- ------
1487
-
1488
- If you use `Teacup::Appearance` but it is not styling the first screen of your
1489
- app (but, strangely, *does* style all other screens), try calling
1490
- `Teacup::Appearance.apply` before creating you create the `rootViewController`
1491
- (in your `AppDelegate`)..
1492
-
1493
- ------
1494
-
1495
- The Dummy
1496
- ---------
1497
-
1498
- If you get an error that looks like this:
1499
-
1500
- Objective-C stub for message `setHidesWhenStopped:' type `v@:c' not
1501
- precompiled. Make sure you properly link with the framework or library that
1502
- defines this message.
1503
-
1504
- You probably need to add your method to [dummy.rb][]. This is a compiler issue,
1505
- nothing we can do about it except build up a huge dummy.rb file that has just
1506
- about every method that you would want to style.
1507
-
1508
- # Teacup is a Community Project!
1509
-
1510
- Teacup was born out of the #rubymotion irc chatroom in the early days of
1511
- RubyMotion. Its design, direction, and priorities are all up for discussion!
1512
-
1513
- I'm [Colin T.A. Gray][colinta], the maintainer of the Teacup project. I hope this
1514
- tool helps you build great apps!
1515
-
1516
- [advanced]: https://github.com/rubymotion/teacup/#advanced-teacup-tricks
1517
- [calculations]: https://github.com/rubymotion/teacup/#frame-calculations
1518
- [dummy.rb]: https://github.com/rubymotion/teacup/tree/master/lib/dummy.rb
1519
-
1520
- [Pixate]: http://www.pixate.com
1521
- [NUI]: https://github.com/tombenner/nui
1522
- [geomotion]: https://github.com/clayallsopp/geomotion
1523
- [UIAppearance]: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIAppearance_Protocol/Reference/Reference.html#//apple_ref/occ/intf/UIAppearance
1524
- [motion-layout]: https://github.com/qrush/motion-layout
1525
- [sweettea]: https://github.com/colinta/sweettea
1526
- [qrush]: https://github.com/qrush
1527
- [colinta]: https://github.com/colinta