mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-09-03 19:30:09 +00:00
Properly consider node for responder methods (#1008)
* Properly consider node for responder methods * Add changelog
This commit is contained in:
parent
d28b17c87f
commit
6c487dd26c
@ -14,6 +14,7 @@
|
||||
- Optimize layout flattening, particularly reducing retain/release operations. [Adlai Holler](https://github.com/Adlai-Holler)
|
||||
- Create a method to transfer strong C-arrays into immutable NSArrays, reducing retain/release traffic. [Adlai Holler](https://github.com/Adlai-Holler)
|
||||
- Remove yoga layout spec, which has been superseded by tighter Yoga integration (`ASDisplayNode+Yoga.h`)
|
||||
- Properly consider node for responder methods [Michael Schneider](https://github.com/maicki)
|
||||
|
||||
## 2.7
|
||||
- Fix pager node for interface coalescing. [Max Wang](https://github.com/wsdwsd0829) [#877](https://github.com/TextureGroup/Texture/pull/877)
|
||||
|
@ -154,6 +154,8 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
ASDisplayNodeCAssertNotNil(c, @"class is required");
|
||||
|
||||
ASDisplayNodeMethodOverrides overrides = ASDisplayNodeMethodOverrideNone;
|
||||
|
||||
// Handling touches
|
||||
if (ASDisplayNodeSubclassOverridesSelector(c, @selector(touchesBegan:withEvent:))) {
|
||||
overrides |= ASDisplayNodeMethodOverrideTouchesBegan;
|
||||
}
|
||||
@ -166,13 +168,32 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
if (ASDisplayNodeSubclassOverridesSelector(c, @selector(touchesEnded:withEvent:))) {
|
||||
overrides |= ASDisplayNodeMethodOverrideTouchesEnded;
|
||||
}
|
||||
|
||||
// Responder chain
|
||||
if (ASDisplayNodeSubclassOverridesSelector(c, @selector(canBecomeFirstResponder))) {
|
||||
overrides |= ASDisplayNodeMethodOverrideCanBecomeFirstResponder;
|
||||
}
|
||||
if (ASDisplayNodeSubclassOverridesSelector(c, @selector(becomeFirstResponder))) {
|
||||
overrides |= ASDisplayNodeMethodOverrideBecomeFirstResponder;
|
||||
}
|
||||
if (ASDisplayNodeSubclassOverridesSelector(c, @selector(canResignFirstResponder))) {
|
||||
overrides |= ASDisplayNodeMethodOverrideCanResignFirstResponder;
|
||||
}
|
||||
if (ASDisplayNodeSubclassOverridesSelector(c, @selector(resignFirstResponder))) {
|
||||
overrides |= ASDisplayNodeMethodOverrideResignFirstResponder;
|
||||
}
|
||||
if (ASDisplayNodeSubclassOverridesSelector(c, @selector(isFirstResponder))) {
|
||||
overrides |= ASDisplayNodeMethodOverrideIsFirstResponder;
|
||||
}
|
||||
|
||||
// Layout related methods
|
||||
if (ASDisplayNodeSubclassOverridesSelector(c, @selector(layoutSpecThatFits:))) {
|
||||
overrides |= ASDisplayNodeMethodOverrideLayoutSpecThatFits;
|
||||
}
|
||||
if (ASDisplayNodeSubclassOverridesSelector(c, @selector(calculateLayoutThatFits:)) ||
|
||||
ASDisplayNodeSubclassOverridesSelector(c, @selector(calculateLayoutThatFits:
|
||||
restrictedToSize:
|
||||
relativeToParentSize:))) {
|
||||
restrictedToSize:
|
||||
relativeToParentSize:))) {
|
||||
overrides |= ASDisplayNodeMethodOverrideCalcLayoutThatFits;
|
||||
}
|
||||
if (ASDisplayNodeSubclassOverridesSelector(c, @selector(calculateSizeThatFits:))) {
|
||||
|
@ -29,6 +29,20 @@
|
||||
#import <AsyncDisplayKit/ASObjectDescriptionHelpers.h>
|
||||
#import <AsyncDisplayKit/ASViewController.h>
|
||||
|
||||
#pragma mark - ASDisplayNode
|
||||
|
||||
/**
|
||||
* Open access to the method overrides struct for ASDisplayView
|
||||
*/
|
||||
@implementation ASDisplayNode (ASDisplayNodeMethodOverrides_ASDisplayView)
|
||||
|
||||
- (ASDisplayNodeMethodOverrides)methodOverrides
|
||||
{
|
||||
return _methodOverrides;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - _ASDisplayViewMethodOverrides
|
||||
|
||||
typedef NS_OPTIONS(NSUInteger, _ASDisplayViewMethodOverrides)
|
||||
@ -452,25 +466,24 @@ static _ASDisplayViewMethodOverrides GetASDisplayViewMethodOverrides(Class c)
|
||||
|
||||
#pragma mark UIResponder Handling
|
||||
|
||||
#define IMPLEMENT_RESPONDER_METHOD(__sel, __methodOverride) \
|
||||
#define IMPLEMENT_RESPONDER_METHOD(__sel, __nodeMethodOverride, __viewMethodOverride) \
|
||||
- (BOOL)__sel\
|
||||
{\
|
||||
ASDisplayNode *node = _asyncdisplaykit_node; /* Create strong reference to weak ivar. */ \
|
||||
SEL sel = @selector(__sel); \
|
||||
/* Prevent an infinite loop in here if [super canBecomeFirstResponder] was called on a
|
||||
/ _ASDisplayView subclass */ \
|
||||
if (self->_methodOverrides & __methodOverride) { \
|
||||
/* Check if we can call through to ASDisplayNode subclass directly */ \
|
||||
if (ASDisplayNodeSubclassOverridesSelector([node class], sel)) { \
|
||||
return [node __sel]; \
|
||||
} else { \
|
||||
/* Call through to views superclass as we expect super was called from the
|
||||
_ASDisplayView subclass and a node subclass does not overwrite canBecomeFirstResponder */ \
|
||||
return [self __##__sel]; \
|
||||
} \
|
||||
/* Check if we can call through to ASDisplayNode subclass directly */ \
|
||||
if (node.methodOverrides & __nodeMethodOverride) { \
|
||||
return [node __sel]; \
|
||||
} else { \
|
||||
/* Call through to internal node __canBecomeFirstResponder that will consider the view in responding */ \
|
||||
return [node __##__sel]; \
|
||||
/* Prevent an infinite loop in here if [super __sel] was called on a \
|
||||
/ _ASDisplayView subclass */ \
|
||||
if (self->_methodOverrides & __viewMethodOverride) { \
|
||||
/* Call through to views superclass as we expect super was called from the
|
||||
_ASDisplayView subclass and a node subclass does not overwrite __sel */ \
|
||||
return [self __##__sel]; \
|
||||
} else { \
|
||||
/* Call through to internal node __sel method that will consider the view in responding */ \
|
||||
return [node __##__sel]; \
|
||||
} \
|
||||
} \
|
||||
}\
|
||||
/* All __ prefixed methods are called from ASDisplayNode to let the view decide in what UIResponder state they \
|
||||
@ -480,11 +493,21 @@ are not overridden by a ASDisplayNode subclass */ \
|
||||
return [super __sel]; \
|
||||
} \
|
||||
|
||||
IMPLEMENT_RESPONDER_METHOD(canBecomeFirstResponder, _ASDisplayViewMethodOverrideCanBecomeFirstResponder);
|
||||
IMPLEMENT_RESPONDER_METHOD(becomeFirstResponder, _ASDisplayViewMethodOverrideBecomeFirstResponder);
|
||||
IMPLEMENT_RESPONDER_METHOD(canResignFirstResponder, _ASDisplayViewMethodOverrideCanResignFirstResponder);
|
||||
IMPLEMENT_RESPONDER_METHOD(resignFirstResponder, _ASDisplayViewMethodOverrideResignFirstResponder);
|
||||
IMPLEMENT_RESPONDER_METHOD(isFirstResponder, _ASDisplayViewMethodOverrideIsFirstResponder);
|
||||
IMPLEMENT_RESPONDER_METHOD(canBecomeFirstResponder,
|
||||
ASDisplayNodeMethodOverrideCanBecomeFirstResponder,
|
||||
_ASDisplayViewMethodOverrideCanBecomeFirstResponder);
|
||||
IMPLEMENT_RESPONDER_METHOD(becomeFirstResponder,
|
||||
ASDisplayNodeMethodOverrideBecomeFirstResponder,
|
||||
_ASDisplayViewMethodOverrideBecomeFirstResponder);
|
||||
IMPLEMENT_RESPONDER_METHOD(canResignFirstResponder,
|
||||
ASDisplayNodeMethodOverrideCanResignFirstResponder,
|
||||
_ASDisplayViewMethodOverrideCanResignFirstResponder);
|
||||
IMPLEMENT_RESPONDER_METHOD(resignFirstResponder,
|
||||
ASDisplayNodeMethodOverrideResignFirstResponder,
|
||||
_ASDisplayViewMethodOverrideResignFirstResponder);
|
||||
IMPLEMENT_RESPONDER_METHOD(isFirstResponder,
|
||||
ASDisplayNodeMethodOverrideIsFirstResponder,
|
||||
_ASDisplayViewMethodOverrideIsFirstResponder);
|
||||
|
||||
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
|
||||
{
|
||||
|
@ -44,14 +44,19 @@ _ASPendingState * ASDisplayNodeGetPendingState(ASDisplayNode * node);
|
||||
|
||||
typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides)
|
||||
{
|
||||
ASDisplayNodeMethodOverrideNone = 0,
|
||||
ASDisplayNodeMethodOverrideTouchesBegan = 1 << 0,
|
||||
ASDisplayNodeMethodOverrideTouchesCancelled = 1 << 1,
|
||||
ASDisplayNodeMethodOverrideTouchesEnded = 1 << 2,
|
||||
ASDisplayNodeMethodOverrideTouchesMoved = 1 << 3,
|
||||
ASDisplayNodeMethodOverrideLayoutSpecThatFits = 1 << 4,
|
||||
ASDisplayNodeMethodOverrideCalcLayoutThatFits = 1 << 5,
|
||||
ASDisplayNodeMethodOverrideCalcSizeThatFits = 1 << 6,
|
||||
ASDisplayNodeMethodOverrideNone = 0,
|
||||
ASDisplayNodeMethodOverrideTouchesBegan = 1 << 0,
|
||||
ASDisplayNodeMethodOverrideTouchesCancelled = 1 << 1,
|
||||
ASDisplayNodeMethodOverrideTouchesEnded = 1 << 2,
|
||||
ASDisplayNodeMethodOverrideTouchesMoved = 1 << 3,
|
||||
ASDisplayNodeMethodOverrideLayoutSpecThatFits = 1 << 4,
|
||||
ASDisplayNodeMethodOverrideCalcLayoutThatFits = 1 << 5,
|
||||
ASDisplayNodeMethodOverrideCalcSizeThatFits = 1 << 6,
|
||||
ASDisplayNodeMethodOverrideCanBecomeFirstResponder= 1 << 7,
|
||||
ASDisplayNodeMethodOverrideBecomeFirstResponder = 1 << 8,
|
||||
ASDisplayNodeMethodOverrideCanResignFirstResponder= 1 << 9,
|
||||
ASDisplayNodeMethodOverrideResignFirstResponder = 1 << 10,
|
||||
ASDisplayNodeMethodOverrideIsFirstResponder = 1 << 11,
|
||||
};
|
||||
|
||||
typedef NS_OPTIONS(uint_least32_t, ASDisplayNodeAtomicFlags)
|
||||
|
@ -263,6 +263,14 @@ for (ASDisplayNode *n in @[ nodes ]) {\
|
||||
|
||||
@end
|
||||
|
||||
@interface ASTestResponderNodeWithOverride : ASDisplayNode
|
||||
@end
|
||||
@implementation ASTestResponderNodeWithOverride
|
||||
- (BOOL)canBecomeFirstResponder {
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface ASTestViewController: ASViewController<ASDisplayNode *>
|
||||
@end
|
||||
@implementation ASTestViewController
|
||||
@ -353,6 +361,21 @@ for (ASDisplayNode *n in @[ nodes ]) {\
|
||||
XCTAssertFalse([textNode.view isFirstResponder]);
|
||||
}
|
||||
|
||||
- (void)testResponderOverrrideCanBecomeFirstResponder
|
||||
{
|
||||
UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||
ASTestResponderNodeWithOverride *node = [[ASTestResponderNodeWithOverride alloc] init];
|
||||
|
||||
// We have to add the text node to a window otherwise the responder methods responses are undefined
|
||||
// This will also create the backing view of the node
|
||||
[window addSubnode:node];
|
||||
[window makeKeyAndVisible];
|
||||
|
||||
XCTAssertTrue([node canBecomeFirstResponder]);
|
||||
XCTAssertTrue([node becomeFirstResponder]);
|
||||
XCTAssertTrue([window firstResponder] == node.view);
|
||||
}
|
||||
|
||||
- (void)testUnsupportedResponderSetupWillThrow
|
||||
{
|
||||
ASTestResponderNode *node = [[ASTestResponderNode alloc] init];
|
||||
|
Loading…
x
Reference in New Issue
Block a user