Skip to content

Commit

Permalink
Fix InputAccessoryView safe area when not attached to a TextInput (#2…
Browse files Browse the repository at this point in the history
…1179)

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
  • Loading branch information
janicduplessis authored and facebook-github-bot committed Sep 19, 2018
1 parent a0f7d60 commit 2191eec
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 20 deletions.
2 changes: 1 addition & 1 deletion Libraries/Text/TextInput/RCTInputAccessoryView.m
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ - (BOOL)canBecomeFirstResponder

- (void)reactSetFrame:(CGRect)frame
{
[_inputAccessoryView setFrame:frame];
[_inputAccessoryView reactSetFrame:frame];

if (_shouldBecomeFirstResponder) {
_shouldBecomeFirstResponder = NO;
Expand Down
50 changes: 34 additions & 16 deletions Libraries/Text/TextInput/RCTInputAccessoryViewContent.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,38 +12,56 @@
@implementation RCTInputAccessoryViewContent
{
UIView *_safeAreaContainer;
NSLayoutConstraint *_heightConstraint;
}

- (instancetype)init
{
if (self = [super init]) {
_safeAreaContainer = [UIView new];
[self addSubview:_safeAreaContainer];
}
return self;
}

- (void)didMoveToSuperview
{
// Use autolayout to position the view properly and take into account
// safe area insets on iPhone X.
// TODO: Support rotation, anchor to left and right without breaking frame x coordinate (T27974328).
self.autoresizingMask = UIViewAutoresizingFlexibleHeight;
_safeAreaContainer.translatesAutoresizingMaskIntoConstraints = NO;

_heightConstraint = [_safeAreaContainer.heightAnchor constraintEqualToConstant:0];
_heightConstraint.active = YES;

#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
// Avoid the home pill (in portrait mode)
// TODO: Support rotation, anchor to left and right without breaking frame x coordinate (T27974328).
if (@available(iOS 11.0, *)) {
if (self.window) {
[_safeAreaContainer.bottomAnchor
constraintLessThanOrEqualToSystemSpacingBelowAnchor:self.window.safeAreaLayoutGuide.bottomAnchor
multiplier:1.0f].active = YES;
if (@available(iOS 11.0, *)) {
[_safeAreaContainer.bottomAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.bottomAnchor].active = YES;
[_safeAreaContainer.topAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.topAnchor].active = YES;
[_safeAreaContainer.leadingAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.leadingAnchor].active = YES;
[_safeAreaContainer.trailingAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.trailingAnchor].active = YES;
} else {
[_safeAreaContainer.bottomAnchor constraintEqualToAnchor:self.bottomAnchor].active = YES;
[_safeAreaContainer.topAnchor constraintEqualToAnchor:self.topAnchor].active = YES;
[_safeAreaContainer.leadingAnchor constraintEqualToAnchor:self.leadingAnchor].active = YES;
[_safeAreaContainer.trailingAnchor constraintEqualToAnchor:self.trailingAnchor].active = YES;
}
}
#endif
return self;
}

- (CGSize)intrinsicContentSize
{
// This is needed so the view size is based on autolayout constraints.
return CGSizeZero;
}

- (void)setFrame:(CGRect)frame
- (void)reactSetFrame:(CGRect)frame
{
[super setFrame:frame];
// We still need to set the frame here, otherwise it won't be
// measured until moved to the window during the keyboard opening
// animation. If this happens, the height will be animated from 0 to
// its actual size and we don't want that.
[self setFrame:frame];
[_safeAreaContainer setFrame:frame];

_heightConstraint.constant = frame.size.height;
[self layoutIfNeeded];
}

- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)index
Expand Down
15 changes: 12 additions & 3 deletions RNTester/js/InputAccessoryViewExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,30 +58,39 @@ class TextInputBar extends React.PureComponent<*, *> {
}
}

const BAR_HEIGHT = 44;

class InputAccessoryViewExample extends React.Component<*> {
static title = '<InputAccessoryView>';
static description =
'Example showing how to use an InputAccessoryView to build an iMessage-like sticky text input';

render() {
return (
<View>
<ScrollView keyboardDismissMode="interactive">
<>
<ScrollView style={styles.fill} keyboardDismissMode="interactive">
{Array(15)
.fill()
.map((_, i) => <Message key={i} />)}
</ScrollView>
<InputAccessoryView backgroundColor="#fffffff7">
<TextInputBar />
</InputAccessoryView>
</View>
</>
);
}
}

const styles = StyleSheet.create({
fill: {
flex: 1,
},
textInputContainer: {
flexDirection: 'row',
alignItems: 'center',
borderTopWidth: 1,
borderTopColor: '#eee',
height: BAR_HEIGHT,
},
textInput: {
flex: 1,
Expand Down

0 comments on commit 2191eec

Please sign in to comment.