teacup 2.1.13 → 2.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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