【问题标题】:React native: Android soft keyboard push the View upReact Native:Android 软键盘将 View 向上推
【发布时间】:2021-11-28 10:53:48
【问题描述】:

我制作了一张自定义动画底页。它有两个捕捉点。它从屏幕顶部开始,如果向下滚动动画卡片,它将来到屏幕中间,再次向下滚动卡片,它将来到屏幕底部。如果用户用力向下滚动动画卡片,那么它将一直向下滚动。我把这个组件做成了一个可重用的组件。

我制作了可重复使用的搜索组件

我将这两个组件都导入到 ma​​in-app 组件中。在 Animated-Bottom-sheet 中,我放置了 Search-component

我已经为 keyboardAnimated.View

设置了条件
  • 如果动画视图从屏幕中间移动到底部并搜索 onFocus(出现键盘),则 Keyboard 将关闭。

  • 如果动画视图位于屏幕底部并搜索输入onfocus(出现键盘),那么它会将动画视图移动到屏幕中间。对于这个逻辑,我做了Keyboard.addListener('keyboardDidHide',()=>{....})

我的这个逻辑在 IOS 中完美运行,但在 Android 中,它将所有元素推送到屏幕顶部。

有很多关于 KeyboardAvoidingView 的建议,但就我而言,它不起作用。

在 react-native 的 android 的 AndroidManifest.xml 文件中。我制作了android:windowSoftInputMode="adjustPan",它听Keyboard.addListener('keyboardDidHide'并将所有元素推到屏幕顶部,如果我制作android:windowSoftInputMode="adjustPan|adjustResize",那么它不会听Event-lister。结果,我的逻辑不起作用,它隐藏了 Android 键盘下的动画视图。根据RN-documentation,Event-lister 只听adjustResize or adjustPan

问题:

我真的不知道如何解决这个问题

Android 设备行为

DEMO

代码演示

expo-snacks

这是我的动画视图组件

import React, { useState } from "react";
import { StyleSheet, Dimensions, Platform, View, Keyboard } from "react-native";
import {
  PanGestureHandler,
  PanGestureHandlerGestureEvent,
} from "react-native-gesture-handler";

import Animated, {
  useAnimatedGestureHandler,
  useAnimatedStyle,
  useSharedValue,
  withTiming,
  withSpring,
  runOnJS,
  Easing,
} from "react-native-reanimated";
import styled from "styled-components/native";

interface Props {
  children: React.ReactNode;
}

const { height: SCREEN_HEIGHT } = Dimensions.get("screen");

const IPHONE_DEVICE_MIDDLE_SCREEN = Platform.OS === "ios" ? 4 : 4;
const IPHONE_DEVICE_BOTTOM_SCREEN = Platform.OS === "ios" ? 7.6 : 7.36;
const ANIMATED_DURATION = 300;

const LoadingContainer = styled.View`
  height: ${SCREEN_HEIGHT - 300}px;
  background-color: #fff;
  justify-content: center;
`;

const ScrollBottomSheet = ({ children }: Props) => {
  const contentTop = useSharedValue(SCREEN_HEIGHT);
  const [bottomSheetState, setBottomSheetState] = useState("top");
  // Event-listener
  Keyboard.addListener("keyboardDidShow", () => {
    if (bottomSheetState === "bottom") {
      contentTop.value = withSpring(
        SCREEN_HEIGHT * IPHONE_DEVICE_MIDDLE_SCREEN
      );
    }
  });
  const animatedStyle = useAnimatedStyle(() => {
    "worklet";
    return {
      top: contentTop.value * 0.1,
      bottom: 0,
    };
  });

  const gestureHandler = useAnimatedGestureHandler(
    {
      onStart(_, context) {
        context.translateY = contentTop.value;
      },
      onActive(event, context) {
        contentTop.value = context.translateY + event.translationY;
      },
      onEnd(event, _) {
        if (event.y > 0 && event.y < 200) {
          // MIDDLE SCREEN LOGIC
          contentTop.value = withTiming(
            SCREEN_HEIGHT * IPHONE_DEVICE_MIDDLE_SCREEN,
            {
              duration: ANIMATED_DURATION,
              easing: Easing.inOut(Easing.ease),
            }
          );
          runOnJS(setBottomSheetState)("middle");
          runOnJS(Keyboard.dismiss)(); // dismiss Keyboard
        } else if (event.y > 200) {
          // BOTTOM SCREEN LOGIC
          contentTop.value = withTiming(
            SCREEN_HEIGHT * IPHONE_DEVICE_BOTTOM_SCREEN,
            {
              duration: ANIMATED_DURATION,
              easing: Easing.inOut(Easing.ease),
            }
          ); 
         runOnJS(Keyboard.dismiss)();
          runOnJS(setBottomSheetState)("bottom");
        } else if (event.translationY < 0) {
          contentTop.value = withTiming(SCREEN_HEIGHT, {
            duration: ANIMATED_DURATION,
            easing: Easing.inOut(Easing.ease),
          });
          runOnJS(setBottomSheetState)("top");
        }
      },
    },
    [contentTop]
  );

  return (
    <PanGestureHandler onGestureEvent={gestureHandler}>
      <Animated.View style={[styles.container, animatedStyle]}>
        <View style={styles.grbber} />
        {children}
      </Animated.View>
    </PanGestureHandler>
  );
};

export default ScrollBottomSheet;

const styles = StyleSheet.create({
  container: {
    position: "absolute",
    left: 0,
    right: 0,
    top: 0,
    backgroundColor: "#fff",
    shadowOffset: {
      height: -6,
      width: 0,
    },
    shadowOpacity: 0.1,
    shadowRadius: 5,
    borderTopEndRadius: 15,
    borderTopLeftRadius: 15,
  },
  grbber: {
    width: 80,
    height: 5,
    marginBottom: 4,
    alignSelf: "center",
    marginTop: 5,
    borderTopWidth: 5,
    borderTopColor: "#aaa",
  },
});

搜索组件

import React, { useRef, useEffect } from "react";
import {
  Animated,
  KeyboardTypeOptions,
  TextInputProps,
  TextInput,
  Text,
  Keyboard,
} from "react-native";

import styled from "styled-components/native";

type Props = TextInputProps & {
  text: string,
  hint: string,
  onChangeText?: ((text: string) => void) | undefined,
  onClearText: () => void,
  animatedStyle?: { height: Animated.AnimatedInterpolation },
  keyboardType?: KeyboardTypeOptions,

  autoFocus?: boolean,
};

const Container = styled(Animated.View)`
  flex-direction: row;
  background-color: grey;
  border-radius: 6px;
  align-items: center;
`;

const IconTouchableOpacity = styled.TouchableOpacity`
  padding: 16px;
`;

const SearchInput = styled.TextInput`
  flex: 1;
  padding-right: 16px;
  color: #fff;
  font-size: 16px;
  line-height: 20px;
  height: 44px;
`;

const SearchBar = ({
  text,
  hint,
  onChangeText,
  onClearText,
  animatedStyle,
  keyboardType,
  maxLength,
  autoFocus,
}: Props) => {
  const searchInput = useRef(null);

  const onSearchPress = () => {
    searchInput?.current?.focus();
  };

  useEffect(() => {
    if (autoFocus) {
      onSearchPress();
    }
  }, [autoFocus]);

  return (
    <Container accessible={false} style={animatedStyle}>
      <SearchInput
        ref={searchInput}
        onChangeText={onChangeText}
        value={text}
        placeholder={hint}
        maxLength={maxLength}
        underlineColorAndroid={"transparent"}
        placeholderTextColor={"grey"}
        keyboardType={keyboardType}
        autoFocus={autoFocus}
        onKeyPress={() => hideKeyBoard}
      />
    </Container>
  );
};

export default SearchBar;

**应用组件

import React, { useState, useEffect } from "react";
import { StyleSheet, Button } from "react-native";
import { TouchableHighlight } from "react-native-gesture-handler";
import MapView from "react-native-maps";
import styled from "styled-components";
import ScrollBottomSheet from "./components/ActionSheet";
import SearchBar from "./components/SearchBar";

const initialRegion = {
  latitudeDelta: 15,
  longitudeDelta: 15,
  latitude: 60.1098678,
  longitude: 24.7385084,
};

export default function App() {
  return (
    <>
      <MapView style={styles.mapStyle} initialRegion={initialRegion} />
      <ScrollBottomSheet>
        <SearchContainer>
          <SearchBar hint={"search"} />
        </SearchContainer>
      </ScrollBottomSheet>
    </>
  );
}

const styles = StyleSheet.create({
  mapStyle: {
    height: "100%",
  },
});

const SearchContainer = styled.View`
  padding: 10px;
`;

【问题讨论】:

  • 您如何尝试使用KeyboardAvoidingView?你定义了什么行为?我遇到了类似的问题,它帮助我将行为属性定义为高度 - &lt;KeyboardAvoidingView behavior={'height'} enable={true}&gt;{/*...*/}&lt;/KeyboardAvoidingView&gt;
  • KeyboardTypeOptions from 'react-native' ?

标签: android react-native keyboard react-native-textinput


【解决方案1】:

您是否尝试过使用 Animated.ScrollView 代替 Animated.View?

【讨论】:

  • 不,我没有使用Animated.ScrollView。对我有什么帮助
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-11
  • 2017-01-13
  • 1970-01-01
相关资源
最近更新 更多