Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
GMBase
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
gengmeiios
GMBase
Commits
15216f38
Commit
15216f38
authored
Sep 09, 2020
by
jz
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update 手势
parent
1d64b246
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
392 additions
and
9 deletions
+392
-9
Podfile.lock
Example/Podfile.lock
+2
-2
UINavigationController+FDFullscreenPopGesture.h
...opGesture/UINavigationController+FDFullscreenPopGesture.h
+71
-0
UINavigationController+FDFullscreenPopGesture.m
...opGesture/UINavigationController+FDFullscreenPopGesture.m
+288
-0
GMCustomNavigationAnimationProtocol.h
GMBase/Classes/GMCustomNavigationAnimationProtocol.h
+2
-0
GMNavigationController.m
GMBase/Classes/GMNavigationController.m
+5
-0
GMPresentAnimation.h
GMBase/Classes/GMPresentAnimation.h
+2
-0
GMPresentAnimation.m
GMBase/Classes/GMPresentAnimation.m
+22
-7
No files found.
Example/Podfile.lock
View file @
15216f38
...
...
@@ -18,7 +18,7 @@ PODS:
- BDOpenSDKKit (1.0.0)
- DouyinOpenSDK (1.4.1):
- BDOpenSDKKit (~> 1.0.0)
- GMBase (1.2.
2
):
- GMBase (1.2.
3
):
- GMFoundation
- GMHud
- GMJSONModel
...
...
@@ -154,7 +154,7 @@ SPEC CHECKSUMS:
Alamofire: 907e0a98eb68cdb7f9d1f541a563d6ac5dc77b25
BDOpenSDKKit: 3fb530ce73f85a7d6ee69e7fd3d9158444c5bd09
DouyinOpenSDK: 5ba83de22963ba7a3ba70c8ff11dfcb2885ecc2b
GMBase:
da7fd8da4aa82a442ce38e9c1373a5ce9ffd63cd
GMBase:
02a392993e6c88f11b03136ccd49f4192637da54
GMCache: b78d8e46db864405e91d226ce640cc80d966c611
GMFoundation: e9f7fd9c6e5f133e09009b0ee5de4fce60ac5682
GMHud: 18d41f4900a204f27be14e9504fcee2060ae3b2c
...
...
GMBase/Classes/FDFullscreenPopGesture/UINavigationController+FDFullscreenPopGesture.h
0 → 100755
View file @
15216f38
// The MIT License (MIT)
//
// Copyright (c) 2015-2016 forkingdog ( https://github.com/forkingdog )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#import <UIKit/UIKit.h>
/// "UINavigation+FDFullscreenPopGesture" extends UINavigationController's swipe-
/// to-pop behavior in iOS 7+ by supporting fullscreen pan gesture. Instead of
/// screen edge, you can now swipe from any place on the screen and the onboard
/// interactive pop transition works seamlessly.
///
/// Adding the implementation file of this category to your target will
/// automatically patch UINavigationController with this feature.
@interface
UINavigationController
(
FDFullscreenPopGesture
)
/// The gesture recognizer that actually handles interactive pop.
@property
(
nonatomic
,
strong
,
readonly
)
UIPanGestureRecognizer
*
fd_fullscreenPopGestureRecognizer
;
/// A view controller is able to control navigation bar's appearance by itself,
/// rather than a global way, checking "fd_prefersNavigationBarHidden" property.
/// Default to YES, disable it if you don't want so.
@property
(
nonatomic
,
assign
)
BOOL
fd_viewControllerBasedNavigationBarAppearanceEnabled
;
@end
/// Allows any view controller to disable interactive pop gesture, which might
/// be necessary when the view controller itself handles pan gesture in some
/// cases.
@interface
UIViewController
(
FDFullscreenPopGesture
)
/// Whether the interactive pop gesture is disabled when contained in a navigation
/// stack.
@property
(
nonatomic
,
assign
)
BOOL
fd_interactivePopDisabled
;
/// Indicate this view controller prefers its navigation bar hidden or not,
/// checked when view controller based navigation bar's appearance is enabled.
/// Default to NO, bars are more likely to show.
@property
(
nonatomic
,
assign
)
BOOL
fd_prefersNavigationBarHidden
;
/// Max allowed initial distance to left edge when you begin the interactive pop
/// gesture. 0 by default, which means it will ignore this limit.
@property
(
nonatomic
,
assign
)
CGFloat
fd_interactivePopMaxAllowedInitialDistanceToLeftEdge
;
@end
typedef
void
(
^
_FDViewControllerWillAppearInjectBlock
)(
UIViewController
*
viewController
,
BOOL
animated
);
@interface
UIViewController
(
FDFullscreenPopGesturePrivate
)
@property
(
nonatomic
,
copy
)
_FDViewControllerWillAppearInjectBlock
fd_willAppearInjectBlock
;
@end
GMBase/Classes/FDFullscreenPopGesture/UINavigationController+FDFullscreenPopGesture.m
0 → 100755
View file @
15216f38
// The MIT License (MIT)
//
// Copyright (c) 2015-2016 forkingdog ( https://github.com/forkingdog )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#import "UINavigationController+FDFullscreenPopGesture.h"
#import "GMPresentAnimation.h"
#import <objc/runtime.h>
@interface
_FDFullscreenPopGestureRecognizerDelegate
:
NSObject
<
UIGestureRecognizerDelegate
>
@property
(
nonatomic
,
weak
)
UINavigationController
*
navigationController
;
@end
@implementation
_FDFullscreenPopGestureRecognizerDelegate
-
(
BOOL
)
gestureRecognizerShouldBegin
:(
UIPanGestureRecognizer
*
)
gestureRecognizer
{
// Ignore when no view controller is pushed into the navigation stack.
if
(
self
.
navigationController
.
viewControllers
.
count
<=
1
)
{
return
NO
;
}
// Ignore when the active view controller doesn't allow interactive pop.
UIViewController
*
topViewController
=
self
.
navigationController
.
viewControllers
.
lastObject
;
if
(
topViewController
.
fd_interactivePopDisabled
)
{
return
NO
;
}
// Ignore when the beginning location is beyond max allowed initial distance to left edge.
CGPoint
beginningLocation
=
[
gestureRecognizer
locationInView
:
gestureRecognizer
.
view
];
CGFloat
maxAllowedInitialDistance
=
topViewController
.
fd_interactivePopMaxAllowedInitialDistanceToLeftEdge
;
if
(
maxAllowedInitialDistance
>
0
&&
beginningLocation
.
x
>
maxAllowedInitialDistance
)
{
return
NO
;
}
// Ignore pan gesture when the navigation controller is currently in transition.
if
([[
self
.
navigationController
valueForKey
:
@"_isTransitioning"
]
boolValue
])
{
return
NO
;
}
// Prevent calling the handler when the gesture begins in an opposite direction.
CGPoint
translation
=
[
gestureRecognizer
translationInView
:
gestureRecognizer
.
view
];
BOOL
isLeftToRight
=
[
UIApplication
sharedApplication
].
userInterfaceLayoutDirection
==
UIUserInterfaceLayoutDirectionLeftToRight
;
CGFloat
multiplier
=
isLeftToRight
?
1
:
-
1
;
if
((
translation
.
x
*
multiplier
)
<=
0
)
{
return
NO
;
}
if
([
topViewController
conformsToProtocol
:
@protocol
(
GMCustomNavigationAnimationProtocol
)])
{
id
<
GMCustomNavigationAnimationProtocol
>
controller
=
(
id
<
GMCustomNavigationAnimationProtocol
>
)
topViewController
;
id
<
GMControllerAnimatedTransitioning
>
animation
=
controller
.
navigationAnimation
;
[
animation
removeMaskWith
:
topViewController
];
}
return
YES
;
}
@end
@implementation
UIViewController
(
FDFullscreenPopGesturePrivate
)
+
(
void
)
load
{
static
dispatch_once_t
onceToken
;
dispatch_once
(
&
onceToken
,
^
{
Method
viewWillAppear_originalMethod
=
class_getInstanceMethod
(
self
,
@selector
(
viewWillAppear
:
));
Method
viewWillAppear_swizzledMethod
=
class_getInstanceMethod
(
self
,
@selector
(
fd_viewWillAppear
:
));
method_exchangeImplementations
(
viewWillAppear_originalMethod
,
viewWillAppear_swizzledMethod
);
// Method viewWillDisappear_originalMethod = class_getInstanceMethod(self, @selector(viewWillDisappear:));
// Method viewWillDisappear_swizzledMethod = class_getInstanceMethod(self, @selector(fd_viewWillDisappear:));
// method_exchangeImplementations(viewWillDisappear_originalMethod, viewWillDisappear_swizzledMethod);
});
}
-
(
void
)
fd_viewWillAppear
:
(
BOOL
)
animated
{
// Forward to primary implementation.
[
self
fd_viewWillAppear
:
animated
];
if
(
self
.
fd_willAppearInjectBlock
)
{
self
.
fd_willAppearInjectBlock
(
self
,
animated
);
}
}
//- (void)fd_viewWillDisappear:(BOOL)animated
//{
// // Forward to primary implementation.
// [self fd_viewWillDisappear:animated];
//
// dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// UIViewController *viewController = self.navigationController.viewControllers.lastObject;
// if (viewController && !viewController.fd_prefersNavigationBarHidden) {
// [self.navigationController setNavigationBarHidden:NO animated:NO];
// }
// });
//}
-
(
_FDViewControllerWillAppearInjectBlock
)
fd_willAppearInjectBlock
{
return
objc_getAssociatedObject
(
self
,
_cmd
);
}
-
(
void
)
setFd_willAppearInjectBlock
:
(
_FDViewControllerWillAppearInjectBlock
)
block
{
objc_setAssociatedObject
(
self
,
@selector
(
fd_willAppearInjectBlock
),
block
,
OBJC_ASSOCIATION_COPY_NONATOMIC
);
}
@end
@implementation
UINavigationController
(
FDFullscreenPopGesture
)
+
(
void
)
load
{
// Inject "-pushViewController:animated:"
static
dispatch_once_t
onceToken
;
dispatch_once
(
&
onceToken
,
^
{
Class
class
=
[
self
class
];
SEL
originalSelector
=
@selector
(
pushViewController
:
animated
:
);
SEL
swizzledSelector
=
@selector
(
fd_pushViewController
:
animated
:
);
Method
originalMethod
=
class_getInstanceMethod
(
class
,
originalSelector
);
Method
swizzledMethod
=
class_getInstanceMethod
(
class
,
swizzledSelector
);
BOOL
success
=
class_addMethod
(
class
,
originalSelector
,
method_getImplementation
(
swizzledMethod
),
method_getTypeEncoding
(
swizzledMethod
));
if
(
success
)
{
class_replaceMethod
(
class
,
swizzledSelector
,
method_getImplementation
(
originalMethod
),
method_getTypeEncoding
(
originalMethod
));
}
else
{
method_exchangeImplementations
(
originalMethod
,
swizzledMethod
);
}
});
}
-
(
void
)
fd_pushViewController
:
(
UIViewController
*
)
viewController
animated
:
(
BOOL
)
animated
{
if
(
!
[
self
.
interactivePopGestureRecognizer
.
view
.
gestureRecognizers
containsObject
:
self
.
fd_fullscreenPopGestureRecognizer
])
{
// Add our own gesture recognizer to where the onboard screen edge pan gesture recognizer is attached to.
[
self
.
interactivePopGestureRecognizer
.
view
addGestureRecognizer
:
self
.
fd_fullscreenPopGestureRecognizer
];
// Forward the gesture events to the private handler of the onboard gesture recognizer.
NSArray
*
internalTargets
=
[
self
.
interactivePopGestureRecognizer
valueForKey
:
@"targets"
];
id
internalTarget
=
[
internalTargets
.
firstObject
valueForKey
:
@"target"
];
SEL
internalAction
=
NSSelectorFromString
(
@"handleNavigationTransition:"
);
self
.
fd_fullscreenPopGestureRecognizer
.
delegate
=
self
.
fd_popGestureRecognizerDelegate
;
[
self
.
fd_fullscreenPopGestureRecognizer
addTarget
:
internalTarget
action
:
internalAction
];
// Disable the onboard gesture recognizer.
self
.
interactivePopGestureRecognizer
.
enabled
=
NO
;
}
// Handle perferred navigation bar appearance.
[
self
fd_setupViewControllerBasedNavigationBarAppearanceIfNeeded
:
viewController
];
// Forward to primary implementation.
if
(
!
[
self
.
viewControllers
containsObject
:
viewController
])
{
[
self
fd_pushViewController
:
viewController
animated
:
animated
];
}
}
-
(
void
)
fd_setupViewControllerBasedNavigationBarAppearanceIfNeeded
:
(
UIViewController
*
)
appearingViewController
{
if
(
!
self
.
fd_viewControllerBasedNavigationBarAppearanceEnabled
)
{
return
;
}
__weak
typeof
(
self
)
weakSelf
=
self
;
_FDViewControllerWillAppearInjectBlock
block
=
^
(
UIViewController
*
viewController
,
BOOL
animated
)
{
__strong
typeof
(
weakSelf
)
strongSelf
=
weakSelf
;
if
(
strongSelf
)
{
//这个不需要重复设置了 GMBase已经设置过了
// [strongSelf setNavigationBarHidden:YES animated:animated];
}
};
// Setup will appear inject block to appearing view controller.
// Setup disappearing view controller as well, because not every view controller is added into
// stack by pushing, maybe by "-setViewControllers:".
appearingViewController
.
fd_willAppearInjectBlock
=
block
;
UIViewController
*
disappearingViewController
=
self
.
viewControllers
.
lastObject
;
if
(
disappearingViewController
&&
!
disappearingViewController
.
fd_willAppearInjectBlock
)
{
disappearingViewController
.
fd_willAppearInjectBlock
=
block
;
}
}
-
(
_FDFullscreenPopGestureRecognizerDelegate
*
)
fd_popGestureRecognizerDelegate
{
_FDFullscreenPopGestureRecognizerDelegate
*
delegate
=
objc_getAssociatedObject
(
self
,
_cmd
);
if
(
!
delegate
)
{
delegate
=
[[
_FDFullscreenPopGestureRecognizerDelegate
alloc
]
init
];
delegate
.
navigationController
=
self
;
objc_setAssociatedObject
(
self
,
_cmd
,
delegate
,
OBJC_ASSOCIATION_RETAIN_NONATOMIC
);
}
return
delegate
;
}
-
(
UIPanGestureRecognizer
*
)
fd_fullscreenPopGestureRecognizer
{
UIPanGestureRecognizer
*
panGestureRecognizer
=
objc_getAssociatedObject
(
self
,
_cmd
);
if
(
!
panGestureRecognizer
)
{
panGestureRecognizer
=
[[
UIPanGestureRecognizer
alloc
]
init
];
panGestureRecognizer
.
maximumNumberOfTouches
=
1
;
objc_setAssociatedObject
(
self
,
_cmd
,
panGestureRecognizer
,
OBJC_ASSOCIATION_RETAIN_NONATOMIC
);
}
return
panGestureRecognizer
;
}
-
(
BOOL
)
fd_viewControllerBasedNavigationBarAppearanceEnabled
{
NSNumber
*
number
=
objc_getAssociatedObject
(
self
,
_cmd
);
if
(
number
)
{
return
number
.
boolValue
;
}
self
.
fd_viewControllerBasedNavigationBarAppearanceEnabled
=
YES
;
return
YES
;
}
-
(
void
)
setFd_viewControllerBasedNavigationBarAppearanceEnabled
:
(
BOOL
)
enabled
{
SEL
key
=
@selector
(
fd_viewControllerBasedNavigationBarAppearanceEnabled
);
objc_setAssociatedObject
(
self
,
key
,
@
(
enabled
),
OBJC_ASSOCIATION_RETAIN_NONATOMIC
);
}
@end
@implementation
UIViewController
(
FDFullscreenPopGesture
)
-
(
BOOL
)
fd_interactivePopDisabled
{
return
[
objc_getAssociatedObject
(
self
,
_cmd
)
boolValue
];
}
-
(
void
)
setFd_interactivePopDisabled
:
(
BOOL
)
disabled
{
objc_setAssociatedObject
(
self
,
@selector
(
fd_interactivePopDisabled
),
@
(
disabled
),
OBJC_ASSOCIATION_RETAIN_NONATOMIC
);
}
-
(
BOOL
)
fd_prefersNavigationBarHidden
{
return
[
objc_getAssociatedObject
(
self
,
_cmd
)
boolValue
];
}
-
(
void
)
setFd_prefersNavigationBarHidden
:
(
BOOL
)
hidden
{
objc_setAssociatedObject
(
self
,
@selector
(
fd_prefersNavigationBarHidden
),
@
(
hidden
),
OBJC_ASSOCIATION_RETAIN_NONATOMIC
);
}
-
(
CGFloat
)
fd_interactivePopMaxAllowedInitialDistanceToLeftEdge
{
#if CGFLOAT_IS_DOUBLE
return
[
objc_getAssociatedObject
(
self
,
_cmd
)
doubleValue
];
#else
return
[
objc_getAssociatedObject
(
self
,
_cmd
)
floatValue
];
#endif
}
-
(
void
)
setFd_interactivePopMaxAllowedInitialDistanceToLeftEdge
:
(
CGFloat
)
distance
{
SEL
key
=
@selector
(
fd_interactivePopMaxAllowedInitialDistanceToLeftEdge
);
objc_setAssociatedObject
(
self
,
key
,
@
(
MAX
(
0
,
distance
)),
OBJC_ASSOCIATION_RETAIN_NONATOMIC
);
}
@end
GMBase/Classes/GMCustomNavigationAnimationProtocol.h
View file @
15216f38
...
...
@@ -13,6 +13,8 @@
/// 自定义 navigation 动画类需要知道某一时刻是 push还是pop。
@property
(
nonatomic
,
assign
)
UINavigationControllerOperation
transitionType
;
@optional
-
(
void
)
removeMaskWith
:
(
UIViewController
*
)
topVc
;
@end
/// 对于想要使用自定义 push、pop 动画的 controller,需要实现该协议。
...
...
GMBase/Classes/GMNavigationController.m
View file @
15216f38
...
...
@@ -43,6 +43,11 @@
return
nil
;
}
//- (UIViewController *)popViewControllerAnimated:(BOOL)animated {
// [super popViewControllerAnimated:animated];
//}
// 依据supportedInterfaceOrientations文档,控制旋转的代码需要写在root view controller,或者全屏的presenting controller
// app的root view controller就是这个GMNavigationController,所以相关控制代码在这里。
-
(
BOOL
)
shouldAutorotate
{
...
...
GMBase/Classes/GMPresentAnimation.h
View file @
15216f38
...
...
@@ -20,4 +20,6 @@ typedef NS_ENUM(NSUInteger, GMCustomAnimationType) {
@property
(
nonatomic
,
assign
)
BOOL
needMask
;
@property
(
nonatomic
,
assign
)
GMCustomAnimationType
animationType
;
-
(
void
)
removeMaskWith
:(
UIViewController
*
)
topVc
;
@end
GMBase/Classes/GMPresentAnimation.m
View file @
15216f38
...
...
@@ -19,6 +19,7 @@
-
(
instancetype
)
init
{
if
(
self
=
[
super
init
])
{
self
.
animationType
=
GMCustomAnimationTypePresent
;
self
.
duration
=
0
.
3
;
self
.
needMask
=
NO
;
}
...
...
@@ -83,18 +84,20 @@
[[
transitionContext
containerView
]
insertSubview
:
toView
belowSubview
:
toVC
.
snapshot
];
CGRect
newFrame
=
fromView
.
frame
;
if
(
self
.
animationType
==
GMCustomAnimationTypePresent
)
{
newFrame
.
origin
.
y
=
CGRectGetHeight
(
bound
);
}
else
{
newFrame
.
origin
.
x
=
CGRectGetWidth
(
bound
);
}
// toView.frame = newFrame;
[
UIView
animateWithDuration
:[
self
transitionDuration
:
transitionContext
]
animations
:
^
{
fromView
.
frame
=
newFrame
;
_mask
.
alpha
=
0
;
}
completion
:^
(
BOOL
finished
)
{
if
(
_mask
.
superview
)
{
[
_mask
removeFromSuperview
];
}
// 动画结束后移除toVC.snapshot,留着会挡住toVC,用户无法交互
[
toVC
.
snapshot
removeFromSuperview
];
// 需要将toVC.snapshot清空,下一次弹窗时再重新生成 snapshot,确保每一次 snapshot 为最新画面
toVC
.
snapshot
=
nil
;
[
self
removeMaskWith
:
toVC
];
[
transitionContext
completeTransition
:
!
[
transitionContext
transitionWasCancelled
]];
}];
}
...
...
@@ -111,4 +114,16 @@
}
}
-
(
void
)
removeMaskWith
:
(
UIViewController
*
)
topVc
{
if
(
_mask
.
superview
)
{
[
_mask
removeFromSuperview
];
}
// 动画结束后移除toVC.snapshot,留着会挡住toVC,用户无法交互
[
topVc
.
snapshot
removeFromSuperview
];
// 需要将toVC.snapshot清空,下一次弹窗时再重新生成 snapshot,确保每一次 snapshot 为最新画面
topVc
.
snapshot
=
nil
;
}
@end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment