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: https://github.com/facebook/react-native/pull/21179 Differential Revision: D9928503 Pulled By: hramos fbshipit-source-id: b1b623334558093042fd94ac85e1b52dd16aa1a0
This commit is contained in:
parent
a0f7d6090f
commit
2191eecf54
|
@ -42,7 +42,7 @@
|
|||
|
||||
- (void)reactSetFrame:(CGRect)frame
|
||||
{
|
||||
[_inputAccessoryView setFrame:frame];
|
||||
[_inputAccessoryView reactSetFrame:frame];
|
||||
|
||||
if (_shouldBecomeFirstResponder) {
|
||||
_shouldBecomeFirstResponder = NO;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
@implementation RCTInputAccessoryViewContent
|
||||
{
|
||||
UIView *_safeAreaContainer;
|
||||
NSLayoutConstraint *_heightConstraint;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
|
@ -19,31 +20,48 @@
|
|||
if (self = [super init]) {
|
||||
_safeAreaContainer = [UIView new];
|
||||
[self addSubview:_safeAreaContainer];
|
||||
|
||||
// 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 (@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;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)didMoveToSuperview
|
||||
- (CGSize)intrinsicContentSize
|
||||
{
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// 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
|
||||
|
|
|
@ -58,6 +58,8 @@ class TextInputBar extends React.PureComponent<*, *> {
|
|||
}
|
||||
}
|
||||
|
||||
const BAR_HEIGHT = 44;
|
||||
|
||||
class InputAccessoryViewExample extends React.Component<*> {
|
||||
static title = '<InputAccessoryView>';
|
||||
static description =
|
||||
|
@ -65,8 +67,8 @@ class InputAccessoryViewExample extends React.Component<*> {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<ScrollView keyboardDismissMode="interactive">
|
||||
<>
|
||||
<ScrollView style={styles.fill} keyboardDismissMode="interactive">
|
||||
{Array(15)
|
||||
.fill()
|
||||
.map((_, i) => <Message key={i} />)}
|
||||
|
@ -74,14 +76,21 @@ class InputAccessoryViewExample extends React.Component<*> {
|
|||
<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,
|
||||
|
|
Loading…
Reference in New Issue