JWStackTransition is a library that provides transition animations for navigation controllers, offering various transition effects such as clocks, fences, flips, and folds.
Its principle is provide transition classes that comply with the UIViewControlAnimatedTransitioning protocol for the delegate method navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) of UINavigationController.
It currently has many different kind of transition animation types, most of them can be customized.
This library was inspired by VCTransitionsLibrary and RetroTransition
The library currently contains the following animations, contents:
- AntiClockWise
- Barrier
- ClockWise
- Cube
- Door
- Expand
- Explode
- Fence
- Flip
- Fold
- MultiCircle
- Multinest
- NatGeo
- Official
- Pan
- Particle
- Puzzle
- Rectangler
- Roll
- Rotate
- Serrate
- ShiftLine
- Shrink
- Split
- Swing
- TiledFlip
-
antiClockWise - default case which is the same as
antiClockWiseCustomized(1.5). -
antiClockWiseCustomized(_ startAngle: Double) - default animation start angle is
1.5, angle range is[0.0, 2.0].
![]() |
![]() |
![]() |
![]() |
![]() |
| start angle is 0.0 | start angle is 0.5 | start angle is 1.0 | start angle is 1.5 | start angle is 2.0 |
|---|
-
barrier - default case which is the same as
barrierCustomized(.toTop, width: 20.0). -
barrierCustomized(_ type: JWStackTransitionAnimationBarrierFadeDirectionType, width: CGFloat) - default animation type is
toTop, default barrier width is20.0.
![]() |
![]() |
![]() |
| toTop, width is 20 | toLeft, width is 5 | toRight, width is 10 |
|---|
![]() |
![]() |
![]() |
| toBottom, width is 15 | toVerticalCenter, width is 20 | toHorizontalCenter, width is 25 |
|---|
-
clockWise - default case which is the same as
clockWiseCustomized(0.5). -
clockWiseCustomized(_ startAngle: Double) - default animation start angle is
0.5, angle range is[0.0, 2.0].
![]() |
![]() |
![]() |
![]() |
![]() |
| start angle is 0.0 | start angle is 0.5 | start angle is 1.0 | start angle is 1.5 | start angle is 2.0 |
|---|
-
cube - default case which is the same as
cubeCustomized(.fromLeftToRight) -
cubeCustomized(_ type: JWStackTransitionAnimationCubeType) - default animation case is
fromLeftToRight.
![]() |
![]() |
![]() |
![]() |
| fromLeftToRight | fromRightToLeft | fromTopToBottom | fromBottomToTop |
|---|
-
door - default case which is the same as
doorCustomized(.horizontalOpen, scale: 0.8) -
doorCustomized(_ type: JWStackTransitionAnimationDoorType, scale: CGFloat?) - default animation case is
horizontalOpen, default animation scale is0.8and range is(0.0, 1.0].
![]() |
![]() |
![]() |
| horizontalOpen, scale is 0.8 | horizontalClose, scale is 0.6 | verticalOpen, scale is 0.4 |
|---|
![]() |
![]() |
![]() |
| verticalClose, scale is 0.2 | horizontal, scale is nil | vertical, scale is nil |
|---|
-
expand - default case which is the same as
expandCustomized(.zero) -
expandCustomized(_ fromRect: CGRect) - default from rect is
CGRect.zero.
let a = UIScreen.main.bounds.width
let b = UIScreen.main.bounds.height
let c = a / 2
let d = b / 2
![]() |
![]() |
![]() |
![]() |
| x: 0, y: 0, width: 0, height: 0 | x: a, y: 0, width: 0, height: 0 | x: a, y: b, width: 0, height: 0 | x: 0, y: b, width: 0, height: 0 |
|---|
![]() |
![]() |
![]() |
![]() |
| x: c, y: 0, width: 0, height: 0 | x: a, y: d, width: 0, height: 0 | x: c, y: b, width: 0, height: 0 | x: 0, y: d, width: 0, height: 0 |
|---|
![]() |
![]() |
![]() |
![]() |
| x: c, y: d, width: 0, height: 0 | x: c-50, y: d-50, width: 100, height: 100 | x: a*2, y: b*2, width: 100, height: 100 | x: -a, y: -b, width: 100, height: 100 |
|---|
-
explode - default case which is the same as
explodeCustomized(CGSize(width: 50, height: 100)) -
explodeCustomized(_ pieceSize: CGSize) - default explode piece width is 50 and height is 100.
let aa = UIScreen.main.bounds.width / 2
let bb = UIScreen.main.bounds.height / 2
![]() |
![]() |
![]() |
![]() |
| width is 50, height is 100 | width is 10, height is 10 | width is aa, height is 10 | width is 10, height is bb |
|---|
-
fence - default case which is the same as
fenceCustomized(.verticalLeft, width: 20.0) -
fenceCustomized(_ type: JWStackTransitionAnimationFenceType, width: CGFloat) - default animation type is
verticalLeft, default fence width is20.0.
![]() |
![]() |
![]() |
| verticalLeft, width is 20.0 | verticalRight, width is 5.0 | verticalCross, width is 10 |
|---|
![]() |
![]() |
![]() |
| horizontalTop, width is 15.0 | horizontalBottom, width is 20 | horizontalCross, width is 25 |
|---|
-
flip - default case which is the same as
flipCustomized(.fromLeftToRight) -
flipCustomized(_ type: JWStackTransitionAnimationFoldType) - default animation type is
fromLeftToRight.
![]() |
![]() |
| fromLeftToRight | fromRightToLeft |
|---|
-
fold - default case which is the same as
foldCustomized(.fromLeftToRight, foldNum: 2) -
foldCustomized(_ type: JWStackTransitionAnimationFoldType, foldNum: Int) - default animation type is
fromLeftToRight, default fold number is2.
![]() |
![]() |
![]() |
![]() |
| fromLeftToRight, fold number is 2 | fromLeftToRight, fold number is 4 | fromRightToLeft, fold number is 6 | fromRightToLeft, fold number is 8 |
|---|
-
multiCircle - default case which is the same as
multiCircleCustomized(20.0) -
multiCircleCustomized(_ diameter: CGFloat) - default single circle diameter is
20.0, diameter range is(0, 100].
![]() |
![]() |
![]() |
![]() |
| diameter is 20.0 | diameter is 40.0 | diameter is 60.0 | diameter is 5.0 |
|---|
- multinest
-
natGeo - default case which is the same as
natGeoCustomized(.geoLeft) -
natGeoCustomized(_ type: JWStackTransitionAnimationNatGeoType) - default animation type is
geoLeft.
![]() |
![]() |
| geoLeft | geoRight |
|---|
-
official - default case which is the same as
officialCustomized(.crossDissolve) -
officialCustomized(_ type: JWStackTransitionAnimationOfficialType) - default animation type is
crossDissolve.
![]() |
![]() |
![]() |
| crossDissolve | curlUp | curlDown |
|---|
![]() |
![]() |
![]() |
![]() |
| flipFromLeft | flipFromRight | flipFromTop | flipFromBottom |
|---|
-
pan - default case which is the same as
panCustomized(.panLeft) -
panCustomized(_ type: JWStackTransitionAnimationPanType) - default animation type is
panLeft.
![]() |
![]() |
![]() |
![]() |
| panLeft | panRight | panTop | panBottom |
|---|
![]() |
![]() |
![]() |
![]() |
| panLeftWithShake | panRightWithShake | panTopWithShake | panBottomWithShake |
|---|
-
particle - default case which is the same as
particleCustomized(.zero, size: CGSize(width: 20, height: 20)) -
particleCustomized(_ from: CGPoint, size: CGSize) - default particle ejected from point is
CGPoint.zero, particle width is20and height is20.
let aa = UIScreen.main.bounds.width / 2
let bb = UIScreen.main.bounds.height / 2
![]() |
![]() |
![]() |
![]() |
| width is 20, height is 20 | width is 10, height is 20 | width is 20, height is 10 | width is 10, height is 10 |
|---|
![]() |
![]() |
![]() |
![]() |
| width is 5, height is 20 | width is 50, height is 50 | width is aa, height is 15 | width is 15, height is bb |
|---|
-
puzzle - default case which is the same as
puzzleCustomized(.random, column: 5, row: 10) -
puzzleCustomized(_ type: JWStackTransitionAnimationPuzzleType, column: Int, row: Int) - default animation type is
random, column is5and row is10.
![]() |
![]() |
![]() |
![]() |
![]() |
| random | fromLeft | fromRight | fromTop | fromBottom |
|---|
![]() |
![]() |
![]() |
![]() |
| fromTopLeft | fromTopRight | fromBottomLeft | fromBottomRight |
|---|
![]() |
![]() |
![]() |
![]() |
![]() |
| horizontal | vertical | fromHorBoth | fromVerBoth | quadrant |
|---|
-
rectangler - default case which is the same as
rectanglerCustomized(.waveIn) -
rectanglerCustomized(_ wave: JWStackTransitionAnimationRectanglerWave) - default animation type is
waveIn.
![]() |
![]() |
| waveIn | waveOut |
|---|
-
roll - default case which is the same as
rollCustomized(.y) -
rollCustomized(_ axis: JWStackTransitionAnimationRollAxis) - default animation roll axis is
y.
![]() |
![]() |
![]() |
| x | y | z |
|---|
-
rotate - default case which is the same as
rotateCustomized(.clockWise, rotateAngle: 0.99) -
rotateCustomized(_ type: JWStackTransitionAnimationRotateType, rotateAngle: Double) - default animation rotate type is
clockWise, default rotate angle is0.99, angle range is(0.0, 1.0).
![]() |
![]() |
![]() |
![]() |
| clockWise, rotate angle is 0.99 | clockWise, rotate angle is 0.5 | antiClockWise, rotate angle is 0.99 | antiClockWise, rotate angle is 0.5 |
|---|
-
serrate - default case which is the same as
serrateCustomized(.horizontal, count: 7) -
serrateCustomized(_ type: JWStackTransitionAnimationSerrateType, count: Int) - default animation type is
horizontaland default serrate count is7.
![]() |
![]() |
![]() |
![]() |
| horizontal, serrate count is 7 | horizontal, serrate count is 20 | vertical, serrate count is 5 | vertical, serrate count is 10 |
|---|
-
shiftLine - default case which is the same as
shiftLineCustomized(.toRight) -
shiftLineCustomized(_ type: JWStackTransitionAnimationShiftLineType) - default animation type is
toRight.
![]() |
![]() |
![]() |
![]() |
| toRight | toTop | toBottom | toLeft |
|---|
![]() |
![]() |
![]() |
![]() |
| toTopRight | toBottomRight | toBottomLeft | toTopLeft |
|---|
-
shrink - default case which is the same as
shrinkCustomized(.zero) -
shrinkCustomized(_ fromRect: CGRect) - default from rect is
CGRect.zero.
let a = UIScreen.main.bounds.width
let b = UIScreen.main.bounds.height
let c = a / 2
let d = b / 2
![]() |
![]() |
![]() |
![]() |
| x: 0, y: 0, width: 0, height: 0 | x: a, y: 0, width: 0, height: 0 | x: a, y: b, width: 0, height: 0 | x: 0, y: b, width: 0, height: 0 |
|---|
![]() |
![]() |
![]() |
![]() |
| x: c, y: 0, width: 0, height: 0 | x: a, y: d, width: 0, height: 0 | x: c, y: b, width: 0, height: 0 | x: 0, y: d, width: 0, height: 0 |
|---|
![]() |
![]() |
![]() |
![]() |
| x: c, y: d, width: 0, height: 0 | x: c-50, y: d-50, width: 100, height: 100 | x: a*2, y: b*2, width: 100, height: 100 | x: -a, y: -b, width: 100, height: 100 |
|---|
-
split - default case which is the same as
splitCustomized(.horizontal) -
splitCustomized(_ type: JWStackTransitionAnimationSplitType) - default split type is
horizontal.
![]() |
![]() |
![]() |
![]() |
| horizontal | vertical | diamondHorizontal | diamondVertical |
|---|
![]() |
![]() |
![]() |
![]() |
| cross | leftDiagonal | rightDiagonal | crossDiagonal |
|---|
-
swing - default case which is the same as
swingCustomized(.left) -
swingCustomized(_ edge: JWStackTransitionAnimationRectEdge) - default animation rect edge is
left.
![]() |
![]() |
![]() |
![]() |
| left | right | top | bottom |
|---|
-
tiledFlip - default case which is the same as
tiledFlipCustomized(.flipFromRight, tiledRow: 10, tiledColumn: 5) -
tiledFlipCustomized(_ type: JWStackTransitionAnimationOfficialType, tiledRow: Int, tiledColumn: Int) - default animation type is
flipFromRight, default tiled row is10and range is(0, 20], default tiled column is5and range is(0, 10].
![]() |
![]() |
![]() |
![]() |
| flipFromRight | flipFromLeft | flipFromTop | flipFromBottom |
|---|
![]() |
![]() |
![]() |
| crossDissolve | curlUp | curlDown |
|---|
Directory structure of JWStackTransition:
also, DeepWiki may help you better understand JWStackTransition.
- iOS 12.0 or later
- Swift 5.9.2
- Xcode 15.1
JWStackTransition is available through CocoaPods. To install it, simply add the following line to your Podfile:
pod 'JWStackTransition'Install and import JWStackTransition
import JWStackTransitionJWStackTransition extends the push and pop methods of UINavigationController, so it can be used as follows:
/// push
self.navigationController?.push(vc, type: type, duration: 1.0)
#another way
// self.navigationController?.push(vc, transition: JWStackTransition(type: type, duration: 1.0))
/// pop
self.navigationController?.pop(.antiClockWise, duration: 1.0)
#another way
self.navigationController?.pop(JWStackTransition(type: .antiClockWise, duration: 1.0))2025.07.23, 0.1.6
- add new transition animations and fix bug
2025.07.08, 0.1.4
- add new transition animations
2025.05.20, 0.1.1
- Initial version
Please make an issue or pull request if you have any request.
Bug reports, Documentation, or tests, are always welcome as well.
Sfh03031, sfh894645252@163.com
JWStackTransition is available under the MIT license. See the LICENSE file for more info.






















































































































































