Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal : Improve Chain-ability #382

Closed
lastMove opened this issue Dec 26, 2016 · 4 comments
Closed

Proposal : Improve Chain-ability #382

lastMove opened this issue Dec 26, 2016 · 4 comments

Comments

@lastMove
Copy link
Member

lastMove commented Dec 26, 2016

The goals of this proposal is to improve the Chainability based on the existing with the less possible breaking changes. ( #14 )

Introduce AnimationConfiguration


One of the problems of Animatable’s Chainability is Animation Parameters.

AnimationType is not enough to describe an Animation.
The animation Parameters (Damping, Velocity, duration, force, delay) are stored directly in the View.

struct AnimationConfiguration {let damping: Double,
       let velocity: Double,let duration: Double,
       let delay: Double
}

Now when animating we can do
:
let conf = AnimationConfiguration(damping:0.9, velocity: 0.2, duration: 0.3, delay: 0) 
view.animate(.Pop, configuration: conf)
It’s not a breaking change since configuration is an optional Parameters, and if not specified or nil the old method will be used.

2 - Base the callback system on promises.

A good iOS promises library : Facebook’s Bolts

Welcome to AnimationPromise :

struct AnimationPromise {
	func completion(() -> Void)
	func then(AnimationType, AnimationConfiguration) -> AnimationPromise 
	func and(AnimationType, AnimationConfiguration) -> AnimationPromise
}

The animate method will now return an AnimationPromise, and will not take anymore in parameter the completion closure.

Before :

view.damping = 1
view.delay = 1 
view.duration = 2 

view.animate(.slide(.in, .left)) { 
	view.duration = 1
	view.damping = 0.2 
	
        view.animate(.pop) {
		view.duration = 2 
		view.damping = 1 
		view.delay = 0.5
		
               view.animate(.slide(.out, .left)) {
			self.label.text = "Done ;)" 
		}
	}}

After :

view.animate(.slide(.in, .left), AnimationConfiguration(duration: 2, damping: 1, delay: 1))
	.then(.pop, AnimationConfiguration(duration: 1, damping: 0.2))
	.then(.slide(.out, .left), AnimationConfiguration(duration: 2, damping: 1, delay: 0.5))
	.completion { 
		self.label.text = "Done ;)"; 
       }

It's still a work in progress, what do you think about this ?

@JakeLin
Copy link
Member

JakeLin commented Dec 28, 2016

@lastMove Thanks for starting the initiative.

The syntax animate.then.completion is very well structured and clean 👍

I have a few of ideas as below, they are not concrete, though.

I agree with you AnimationType is not enough to describe an Animation. I am still thinking shall we expose AnimationConfiguration to the user? It seems a little over for using AnimationConfiguration every time. Think about most of the times, the user may use the default value of damping, velocity and duration, we may put them as separate parameters with default values. like func them(animationType: AnimationType, duration: Double = 0.3, damping: Double = 0.7, damping: Dobule = 0.7 , then we create AnimationConfiguration internally for using in private methods.

Can we extract delay as a method instead of a parameter? It will create better readability like
animate(.slide(.in, .left)).delay(0.5).then(.pop)

For the chainable animations, shall we use the chain in an instance of Animatble elements e.g. AnimatableView and AnimatableButton OR a class method? For example.

Chainable animation on an instance

aView.animate(.slide(.in, .left)).delay(0.5).then(.pop)

Chainable animation on class methods

ChainableAnimator.animate {
  aView.animate(.slide(.in, .left))
  bButton.animate(.pop)
} 
.delay(0.5) 
.then {
  aView.animate(.pop)
  bButton.animate(.shake)
}
.run()

For the first one, we only specify the UI element (in this case, aView) once. For the second one, we can sync more than one UI elements (in this case, aView and bButton). But we have to write the UIElement every time. There is some similar implementation for the second approach https://medium.com/reid-chatham/animation-and-data-structures-in-ios-49cc69b8020c#.9ir8l6jp2. We may start with one approach first.

Just some initial ideas, any feedback are welcome 😁

@lastMove
Copy link
Member Author

lastMove commented Dec 30, 2016

we may put them as separate parameters with default values.

Yes, it's ok for me.

Can we extract delay as a method instead of a parameter? It will create better readability like
animate(.slide(.in, .left)).delay(0.5).then(.pop)

Great syntax 👍 And it's not complicated to implement :)

Personally I prefer the first approach seems it seems more natural and easier to read; but they are not exclusive.
We can maybe start by the first approach and after add the second one.

So it will be something like :

view.animate(.slide(.in, .left), duration: 2, damping: 1)
        .delay(1)
	.then(.pop, duration: 0.3)
        .delay(0.5)
	.then(.slide(.out, .left), duration: 2, damping: 1)
	.completion { 
		self.label.text = "Done ;)"; 
       }

@JakeLin
Copy link
Member

JakeLin commented Dec 30, 2016

@lastMove the syntax looks very good 👍

@lastMove
Copy link
Member Author

lastMove commented Jan 2, 2017

Ok nice, I will try to implement this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants