motion-wizard 0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +74 -0
- data/Rakefile +1 -0
- data/lib/motion-wizard.rb +9 -0
- data/lib/motion-wizard/animation_strategy/base_animation_strategy.rb +25 -0
- data/lib/motion-wizard/animation_strategy/ios7_slide_left_to_right.rb +18 -0
- data/lib/motion-wizard/animation_strategy/ios7_slide_right_to_left.rb +18 -0
- data/lib/motion-wizard/animation_strategy/left_to_right.rb +10 -0
- data/lib/motion-wizard/animation_strategy/none.rb +11 -0
- data/lib/motion-wizard/animation_strategy/right_to_left.rb +10 -0
- data/lib/motion-wizard/animation_strategy/slide_animation.rb +21 -0
- data/lib/motion-wizard/controllers/content_controller.rb +17 -0
- data/lib/motion-wizard/controllers/wizard_view_controller.rb +143 -0
- data/lib/motion-wizard/lib/forwardable.rb +12 -0
- data/lib/motion-wizard/views/index_item_view.rb +53 -0
- data/lib/motion-wizard/views/wizard_navigation_bar.rb +55 -0
- data/motion-wizard.gemspec +22 -0
- data/samples/wizard-1/.gitignore +16 -0
- data/samples/wizard-1/Gemfile +8 -0
- data/samples/wizard-1/Rakefile +18 -0
- data/samples/wizard-1/app/app_delegate.rb +8 -0
- data/samples/wizard-1/app/controllers/steps_view_controller.rb +92 -0
- data/samples/wizard-1/app/controllers/wizard_1_view_controller.rb +28 -0
- data/samples/wizard-1/app/views/styles/steps.rb +128 -0
- data/samples/wizard-1/app/views/styles/wizard_1_view_controller.rb +42 -0
- data/samples/wizard-1/resources/Default-568h@2x.png +0 -0
- data/samples/wizard-1/spec/main_spec.rb +9 -0
- data/samples/wizard-2/.gitignore +16 -0
- data/samples/wizard-2/Gemfile +8 -0
- data/samples/wizard-2/Rakefile +22 -0
- data/samples/wizard-2/app/app_delegate.rb +10 -0
- data/samples/wizard-2/app/controllers/steps_view_controller.rb +59 -0
- data/samples/wizard-2/app/controllers/wizard_2_view_controller.rb +29 -0
- data/samples/wizard-2/app/views/my_custom_index_item_view.rb +25 -0
- data/samples/wizard-2/app/views/styles/handlers.rb +7 -0
- data/samples/wizard-2/app/views/styles/index_item.rb +36 -0
- data/samples/wizard-2/app/views/styles/steps.rb +67 -0
- data/samples/wizard-2/app/views/styles/wizard_view_controller.rb +4 -0
- data/samples/wizard-2/resources/Default-568h@2x.png +0 -0
- data/samples/wizard-2/resources/background-568h@2x.png +0 -0
- data/samples/wizard-2/resources/background.png +0 -0
- data/samples/wizard-2/resources/background@2x.png +0 -0
- data/samples/wizard-2/resources/button.png +0 -0
- data/samples/wizard-2/spec/main_spec.rb +9 -0
- data/wizard-1.gif +0 -0
- data/wizard-2.gif +0 -0
- metadata +120 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0b0eb05108f916b5e4a2379147a5517ab4f181dd
|
4
|
+
data.tar.gz: afcfe23fb17888d3afd67cb0170b0cf45cc6386b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ebdb9eb94f462dcddf59ad992f40dff1adc1f1b6384e313ecb03f15cbfd6e2ee61fbff466d1cc9c1a25949e15561d2a93db945525470df763b02c2f23b6b9066
|
7
|
+
data.tar.gz: e19250b87f2322a6f8f16c6a5f8e543f739a9d349359b733fffd4cc75300d8e388ee234f6b7a5051fde87c7ef85b3e8e9e058b35db8e08b0a02b524fc50b22de
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Ignacio Piantanida
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Motion-Wizard
|
2
|
+
|
3
|
+
A small gem to create clean wizard-like views
|
4
|
+
|
5
|
+

|
6
|
+

|
7
|
+
|
8
|
+
#Installation
|
9
|
+
#How to use it
|
10
|
+
Your custom wizard view controller will inherit from `MotionWizard::WizardViewController`.
|
11
|
+
|
12
|
+
With the `steps` class method, you specify which view controllers will describe your wizard.
|
13
|
+
|
14
|
+
``` ruby
|
15
|
+
class Wizard1ViewController < MotionWizard::WizardViewController
|
16
|
+
steps Step1ViewController,
|
17
|
+
Step2ViewController,
|
18
|
+
Step3ViewController,
|
19
|
+
Step4ViewController
|
20
|
+
end
|
21
|
+
```
|
22
|
+
##Moving through steps
|
23
|
+
The `WizardViewController` will create instances of your steps controllers which will then be extended with the `MotionWizard::ContentController` module. This module gives you the following methods which can be used inside your steps:
|
24
|
+
* **#next(data)**: Will move to the next step. It will call `#finish` if there is no following step.
|
25
|
+
* **#previous(data)**: Will move to the previous step. If already on the first step, this method will do nothing.
|
26
|
+
* **#go_to_step(step_number, data)**: Will go to the selected step.
|
27
|
+
* **#finish(data)**: Will call the `#when_finished` method on the wizard view controller
|
28
|
+
|
29
|
+
When moving through steps, you can pass an optional hash parameter with custom data that will get merged into a common wizard hash. You can access this hash inside your steps with the `#wizard_data` method.
|
30
|
+
|
31
|
+
``` ruby
|
32
|
+
class Step1ViewController
|
33
|
+
...
|
34
|
+
|
35
|
+
def viewWillAppear(animated)
|
36
|
+
super
|
37
|
+
@button.on(:touch){ self.next(step_1_text: "Awesome!") }
|
38
|
+
end
|
39
|
+
|
40
|
+
...
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
Your wizard view controller class can define a `#when_finished` method that will get called when any of the steps view controller call `#finish` or `#next` when already on the last step. Within this method you have also access to `wizard_data`.
|
45
|
+
|
46
|
+
``` ruby
|
47
|
+
class Wizard1ViewController < MotionWizard::WizardViewController
|
48
|
+
def when_finished
|
49
|
+
NSLog "You can access your data here #{wizard_data}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
##Customizing Index Views
|
55
|
+
By default, index views will be instances of `MotionWizard::IndexItem`. This view has a `label_wrapper` (`UIView`) subview, which has a `label` (`UILabel`) subview.
|
56
|
+
|
57
|
+
It also defines two methods `when_selected` and `when_unselected` that allow to subscribe a block to be called whenever the current step changes.
|
58
|
+
|
59
|
+
You can customize the default index view appearance and behaviour by defining the `set_up_index_item_at(index_item, index)` method inside your `WizardViewController` subclass ([see sample Nr 1](samples/wizard-1)).
|
60
|
+
|
61
|
+
``` ruby
|
62
|
+
class Wizard1ViewController < MotionWizard::WizardViewController
|
63
|
+
def setup_index_item_at(index_item, index)
|
64
|
+
layout(index_item, :index_item)
|
65
|
+
index_item.label.text = "ABCD"[index]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
```
|
69
|
+
|
70
|
+
If you would rather use a custom index item class instead of the default one, you can register it using the `index_item_view_class` class method inside your `WizardViewController` subclass definition.
|
71
|
+
|
72
|
+
Your custom class can define the methods `#select` and `#unselect` to be called whenever the wizard changes the current step.
|
73
|
+
|
74
|
+
([see sample Nr 2](samples/wizard-2))
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,9 @@
|
|
1
|
+
unless defined?(Motion::Project::Config)
|
2
|
+
raise "This file must be required within a RubyMotion project Rakefile."
|
3
|
+
end
|
4
|
+
|
5
|
+
Motion::Project::App.setup do |app|
|
6
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'motion-wizard/**/*.rb')).reverse.each do |file|
|
7
|
+
app.files.unshift file
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module MotionWizard
|
2
|
+
module AnimationStrategy
|
3
|
+
class BaseAnimationStrategy
|
4
|
+
attr_accessor :already_on_final_position, :duration
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@duration = 0.5
|
8
|
+
end
|
9
|
+
|
10
|
+
def show_view(view, &after_block)
|
11
|
+
@show_view = view
|
12
|
+
@show_view_after_block = after_block
|
13
|
+
end
|
14
|
+
|
15
|
+
def hide_view(view, &after_block)
|
16
|
+
@hide_view = view
|
17
|
+
@hide_view_after_block = after_block
|
18
|
+
end
|
19
|
+
|
20
|
+
def animate
|
21
|
+
raise "Subclass responsability"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module MotionWizard
|
2
|
+
module AnimationStrategy
|
3
|
+
class Ios7SlideLeftToRight < SlideAnimation
|
4
|
+
def initialize
|
5
|
+
super
|
6
|
+
@duration = 0.25
|
7
|
+
end
|
8
|
+
|
9
|
+
def animate
|
10
|
+
show_view_index = @show_view.superview.subviews.index(@show_view)
|
11
|
+
hide_view_index = @show_view.superview.subviews.index(@hide_view)
|
12
|
+
@show_view.superview.exchangeSubviewAtIndex(hide_view_index, withSubviewAtIndex: show_view_index) if show_view_index > hide_view_index
|
13
|
+
do_slide_animation(@show_view, -70, 0, @show_view_after_block)
|
14
|
+
do_slide_animation(@hide_view, 0, App.frame.size.width, @hide_view_after_block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module MotionWizard
|
2
|
+
module AnimationStrategy
|
3
|
+
class Ios7SlideRightToLeft < SlideAnimation
|
4
|
+
def initialize
|
5
|
+
super
|
6
|
+
@duration = 0.25
|
7
|
+
end
|
8
|
+
|
9
|
+
def animate
|
10
|
+
show_view_index = @show_view.superview.subviews.index(@show_view)
|
11
|
+
hide_view_index = @show_view.superview.subviews.index(@hide_view)
|
12
|
+
@show_view.superview.exchangeSubviewAtIndex(hide_view_index, withSubviewAtIndex: show_view_index) if show_view_index < hide_view_index
|
13
|
+
do_slide_animation(@show_view, App.frame.size.width, 0, @show_view_after_block)
|
14
|
+
do_slide_animation(@hide_view, 0, -70, @hide_view_after_block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module MotionWizard
|
2
|
+
module AnimationStrategy
|
3
|
+
class SlideAnimation < BaseAnimationStrategy
|
4
|
+
attr_accessor :direction
|
5
|
+
|
6
|
+
def animate
|
7
|
+
do_slide_animation(@show_view, @direction*App.frame.size.width, 0, @show_view_after_block)
|
8
|
+
do_slide_animation(@hide_view, 0, -@direction*App.frame.size.width, @hide_view_after_block)
|
9
|
+
end
|
10
|
+
|
11
|
+
def do_slide_animation(view, initial_position, final_position, after_block)
|
12
|
+
view.origin = [initial_position, view.origin.y]
|
13
|
+
UIView.animateWithDuration(@duration, animations: -> {
|
14
|
+
view.origin = [final_position, view.origin.y]
|
15
|
+
},completion: ->(finished) {
|
16
|
+
after_block.call(view) if after_block
|
17
|
+
})
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module MotionWizard
|
2
|
+
module ContentController
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
attr_reader :wizard_view_controller
|
6
|
+
delegate :@wizard_view_controller, :next, :previous, :go_to_step, :wizard_data, :reset!, :finish
|
7
|
+
|
8
|
+
def viewDidLoad
|
9
|
+
super
|
10
|
+
self.view.clipsToBounds = true
|
11
|
+
end
|
12
|
+
|
13
|
+
def wizard_view_controller=(wizard_view_controller)
|
14
|
+
@wizard_view_controller = WeakRef.new(wizard_view_controller)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module MotionWizard
|
2
|
+
class WizardViewController < UIViewController
|
3
|
+
attr_reader :navigation_bar_view, :content_view, :wizard_data
|
4
|
+
|
5
|
+
DEFAULT_NAVIGATION_BAR_HEIGHT = 44
|
6
|
+
|
7
|
+
def self.steps(*steps)
|
8
|
+
@_wizard_steps = steps
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.forward_animation_strategy(animation_strategy_class)
|
12
|
+
@_forward_animation_strategy_class = animation_strategy_class
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.backward_animation_strategy(animation_strategy_class)
|
16
|
+
@_backward_animation_strategy_class = animation_strategy_class
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.index_item_view_class(index_item_view_class)
|
20
|
+
@_index_item_view_class = index_item_view_class
|
21
|
+
end
|
22
|
+
|
23
|
+
def init
|
24
|
+
super
|
25
|
+
@steps_controllers_classes = self.class.instance_variable_get(:@_wizard_steps) || []
|
26
|
+
@forward_animation_strategy_class = self.class.instance_variable_get(:@_forward_animation_strategy_class) || AnimationStrategy::RightToLeft
|
27
|
+
@backward_animation_strategy_class = self.class.instance_variable_get(:@_backward_animation_strategy_class) || AnimationStrategy::LeftToRight
|
28
|
+
@index_item_view_class = self.class.instance_variable_get(:@_index_item_view_class) || IndexItem
|
29
|
+
@current_step = 0
|
30
|
+
@wizard_data = {}
|
31
|
+
@steps_controllers = []
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def viewDidLoad
|
36
|
+
super
|
37
|
+
|
38
|
+
@content_view = UIView.alloc.init
|
39
|
+
@content_view.origin = [0,0]
|
40
|
+
@content_view.size = self.view.size
|
41
|
+
self.view.addSubview(@content_view)
|
42
|
+
|
43
|
+
@navigation_bar_view = WizardNavigationBar.alloc.init_with_number_of_steps(number_of_steps, self)
|
44
|
+
@navigation_bar_view.origin = [0,0]
|
45
|
+
@navigation_bar_view.size = [self.view.size.width, DEFAULT_NAVIGATION_BAR_HEIGHT]
|
46
|
+
self.view.addSubview(navigation_bar_view)
|
47
|
+
|
48
|
+
add_new_step_view(AnimationStrategy::None.new)
|
49
|
+
end
|
50
|
+
|
51
|
+
def reset!
|
52
|
+
@wizard_data = {}
|
53
|
+
@steps_controllers = []
|
54
|
+
@navigation_bar_view.reset!
|
55
|
+
navigation_bar_view.select(@current_step)
|
56
|
+
end
|
57
|
+
|
58
|
+
def add_new_step_view(animation_strategy)
|
59
|
+
@current_view_controller = get_current_step_view_controller
|
60
|
+
self.addChildViewController(@current_view_controller)
|
61
|
+
@content_view.addSubview(@current_view_controller.view)
|
62
|
+
|
63
|
+
@current_view_controller.view.origin = [0,0]
|
64
|
+
animation_strategy.show_view(@current_view_controller.view)
|
65
|
+
navigation_bar_view.select(@current_step)
|
66
|
+
end
|
67
|
+
|
68
|
+
def get_current_step_view_controller
|
69
|
+
@steps_controllers[@current_step] ||= begin
|
70
|
+
new_view_controller = @steps_controllers_classes[@current_step].alloc.init
|
71
|
+
new_view_controller.extend(MotionWizard::ContentController)
|
72
|
+
new_view_controller.wizard_view_controller = self
|
73
|
+
new_view_controller.view.size = @content_view.size
|
74
|
+
new_view_controller
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def remove_current_step_view(animation_strategy)
|
79
|
+
current_local_view = @current_view_controller
|
80
|
+
animation_strategy.hide_view(@current_view_controller.view) do |view|
|
81
|
+
view.removeFromSuperview
|
82
|
+
current_local_view.removeFromParentViewController
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def number_of_steps
|
87
|
+
@steps_controllers_classes.size
|
88
|
+
end
|
89
|
+
|
90
|
+
def next(data = {})
|
91
|
+
@wizard_data.merge! data
|
92
|
+
@current_step+=1
|
93
|
+
if @current_step >= number_of_steps
|
94
|
+
@current_step = number_of_steps - 1
|
95
|
+
self.finish
|
96
|
+
return
|
97
|
+
end
|
98
|
+
change_step_view(@forward_animation_strategy_class)
|
99
|
+
self
|
100
|
+
end
|
101
|
+
|
102
|
+
def previous(data = {})
|
103
|
+
@wizard_data.merge! data
|
104
|
+
@current_step-=1
|
105
|
+
return if @current_step < 0
|
106
|
+
change_step_view(@backward_animation_strategy_class)
|
107
|
+
self
|
108
|
+
end
|
109
|
+
|
110
|
+
def go_to_step(step_number, data = {})
|
111
|
+
@wizard_data.merge! data
|
112
|
+
animation_klass = @current_step > step_number ? @backward_animation_strategy_class : @forward_animation_strategy_class
|
113
|
+
@current_step = step_number
|
114
|
+
change_step_view(animation_klass)
|
115
|
+
self
|
116
|
+
end
|
117
|
+
|
118
|
+
def finish(data = {})
|
119
|
+
@wizard_data.merge! data
|
120
|
+
self.when_finished
|
121
|
+
end
|
122
|
+
|
123
|
+
def change_step_view(animation_strategy_klass)
|
124
|
+
animation_strategy = animation_strategy_klass.new
|
125
|
+
remove_current_step_view(animation_strategy)
|
126
|
+
add_new_step_view(animation_strategy)
|
127
|
+
animation_strategy.animate
|
128
|
+
end
|
129
|
+
|
130
|
+
def create_index_item_at(index)
|
131
|
+
index_item = @index_item_view_class.alloc.init
|
132
|
+
index_item.label.text = "%02d" % (index+1)
|
133
|
+
index_item
|
134
|
+
end
|
135
|
+
|
136
|
+
def setup_index_item_at(index_item, index)
|
137
|
+
index_item.label_wrapper.size = index_item.size
|
138
|
+
index_item.label.size = index_item.size
|
139
|
+
end
|
140
|
+
|
141
|
+
def when_finished;end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module MotionWizard
|
2
|
+
module Forwardable
|
3
|
+
def delegate(*methods)
|
4
|
+
to = methods.shift
|
5
|
+
methods.each do |method_name|
|
6
|
+
define_method(method_name) do |*args, &block|
|
7
|
+
self.instance_variable_get(to).send(method_name, *args, &block)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|