Skip to content

Commit 2191eec

Browse files
janicduplessisfacebook-github-bot
authored andcommitted
Fix InputAccessoryView safe area when not attached to a TextInput (#21179)
Summary: When using an InputAccessoryView attached to a TextInput the safe area insets are not applied properly. This uses different autolayout constraints that works in all cases I tested, roughly based on the technique used here https://github.com/stockx/SafeAreaInputAccessoryViewWrapperView/blob/master/SafeAreaInputAccessoryViewWrapperView/Classes/SafeAreaInputAccessoryViewWrapperView.swift#L38. Pull Request resolved: #21179 Differential Revision: D9928503 Pulled By: hramos fbshipit-source-id: b1b623334558093042fd94ac85e1b52dd16aa1a0
1 parent a0f7d60 commit 2191eec

File tree

3 files changed

+47
-20
lines changed

3 files changed

+47
-20
lines changed

Libraries/Text/TextInput/RCTInputAccessoryView.m

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ - (BOOL)canBecomeFirstResponder
4242

4343
- (void)reactSetFrame:(CGRect)frame
4444
{
45-
[_inputAccessoryView setFrame:frame];
45+
[_inputAccessoryView reactSetFrame:frame];
4646

4747
if (_shouldBecomeFirstResponder) {
4848
_shouldBecomeFirstResponder = NO;

Libraries/Text/TextInput/RCTInputAccessoryViewContent.m

+34-16
Original file line numberDiff line numberDiff line change
@@ -12,38 +12,56 @@
1212
@implementation RCTInputAccessoryViewContent
1313
{
1414
UIView *_safeAreaContainer;
15+
NSLayoutConstraint *_heightConstraint;
1516
}
1617

1718
- (instancetype)init
1819
{
1920
if (self = [super init]) {
2021
_safeAreaContainer = [UIView new];
2122
[self addSubview:_safeAreaContainer];
22-
}
23-
return self;
24-
}
2523

26-
- (void)didMoveToSuperview
27-
{
24+
// Use autolayout to position the view properly and take into account
25+
// safe area insets on iPhone X.
26+
// TODO: Support rotation, anchor to left and right without breaking frame x coordinate (T27974328).
27+
self.autoresizingMask = UIViewAutoresizingFlexibleHeight;
28+
_safeAreaContainer.translatesAutoresizingMaskIntoConstraints = NO;
29+
30+
_heightConstraint = [_safeAreaContainer.heightAnchor constraintEqualToConstant:0];
31+
_heightConstraint.active = YES;
2832

29-
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
30-
// Avoid the home pill (in portrait mode)
31-
// TODO: Support rotation, anchor to left and right without breaking frame x coordinate (T27974328).
32-
if (@available(iOS 11.0, *)) {
33-
if (self.window) {
34-
[_safeAreaContainer.bottomAnchor
35-
constraintLessThanOrEqualToSystemSpacingBelowAnchor:self.window.safeAreaLayoutGuide.bottomAnchor
36-
multiplier:1.0f].active = YES;
33+
if (@available(iOS 11.0, *)) {
34+
[_safeAreaContainer.bottomAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.bottomAnchor].active = YES;
35+
[_safeAreaContainer.topAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.topAnchor].active = YES;
36+
[_safeAreaContainer.leadingAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.leadingAnchor].active = YES;
37+
[_safeAreaContainer.trailingAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.trailingAnchor].active = YES;
38+
} else {
39+
[_safeAreaContainer.bottomAnchor constraintEqualToAnchor:self.bottomAnchor].active = YES;
40+
[_safeAreaContainer.topAnchor constraintEqualToAnchor:self.topAnchor].active = YES;
41+
[_safeAreaContainer.leadingAnchor constraintEqualToAnchor:self.leadingAnchor].active = YES;
42+
[_safeAreaContainer.trailingAnchor constraintEqualToAnchor:self.trailingAnchor].active = YES;
3743
}
3844
}
39-
#endif
45+
return self;
46+
}
4047

48+
- (CGSize)intrinsicContentSize
49+
{
50+
// This is needed so the view size is based on autolayout constraints.
51+
return CGSizeZero;
4152
}
4253

43-
- (void)setFrame:(CGRect)frame
54+
- (void)reactSetFrame:(CGRect)frame
4455
{
45-
[super setFrame:frame];
56+
// We still need to set the frame here, otherwise it won't be
57+
// measured until moved to the window during the keyboard opening
58+
// animation. If this happens, the height will be animated from 0 to
59+
// its actual size and we don't want that.
60+
[self setFrame:frame];
4661
[_safeAreaContainer setFrame:frame];
62+
63+
_heightConstraint.constant = frame.size.height;
64+
[self layoutIfNeeded];
4765
}
4866

4967
- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)index

RNTester/js/InputAccessoryViewExample.js

+12-3
Original file line numberDiff line numberDiff line change
@@ -58,30 +58,39 @@ class TextInputBar extends React.PureComponent<*, *> {
5858
}
5959
}
6060

61+
const BAR_HEIGHT = 44;
62+
6163
class InputAccessoryViewExample extends React.Component<*> {
6264
static title = '<InputAccessoryView>';
6365
static description =
6466
'Example showing how to use an InputAccessoryView to build an iMessage-like sticky text input';
6567

6668
render() {
6769
return (
68-
<View>
69-
<ScrollView keyboardDismissMode="interactive">
70+
<>
71+
<ScrollView style={styles.fill} keyboardDismissMode="interactive">
7072
{Array(15)
7173
.fill()
7274
.map((_, i) => <Message key={i} />)}
7375
</ScrollView>
7476
<InputAccessoryView backgroundColor="#fffffff7">
7577
<TextInputBar />
7678
</InputAccessoryView>
77-
</View>
79+
</>
7880
);
7981
}
8082
}
8183

8284
const styles = StyleSheet.create({
85+
fill: {
86+
flex: 1,
87+
},
8388
textInputContainer: {
8489
flexDirection: 'row',
90+
alignItems: 'center',
91+
borderTopWidth: 1,
92+
borderTopColor: '#eee',
93+
height: BAR_HEIGHT,
8594
},
8695
textInput: {
8796
flex: 1,

0 commit comments

Comments
 (0)