代码之家  ›  专栏  ›  技术社区  ›  JmJ

OnPress不是在Android上启动,但在iOS上很好

  •  2
  • JmJ  · 技术社区  · 7 年前

    我已经写了一个本地的反应应用程序,iOS是优先考虑的,所以我首先构建了它。它在应用程序商店中运行得很好,但是我刚开始在Android上工作,尽管一切 出现 正常工作,除了完全不触发的触摸事件。

    所有可触摸的元素都没有调用 onPress 回调,也不是 Button 元素。我甚至尝试完全剥离应用程序,删除导航器,并在初始屏幕上添加一堆可触摸的元素,但仍然没有一个 印刷机 回电开始了。

    以下是我的应用程序初始屏幕的代码,尽管我怀疑这些代码中的任何一个导致了问题:

    // @flow
    import React, { type Element } from 'react';
    import { View, Text, Image, TouchableOpacity } from 'react-native';
    import type { NavigatorScreenProps } from 'react-navigation';
    import i18n from '../../i18n';
    import style from './style';
    
    type Props = {
      navigation: NavigatorScreenProps
    }
    
    export default function SignIn ({ navigation }: Props): Element<typeof View> {
      return (
        <View style={style.container}>
          <View style={style.top}>
            <Image source={require('../../assets/images/purpleWithTransparentBackground.png')} style={style.logo} />
          </View>
          <View style={style.bottom}>
            <TouchableOpacity activeOpacity={0.97} onPressIn={() => console.log('in')} onPressOut={() => console.log('out')} onPress={() => { console.log('do something!'); navigation.navigate('EnterEmail'); }} style={[style.submit, { zIndex: 99999, elevation: 99999 }]}>
              <Text style={style.submitText}>
                {i18n.t('SIGN_IN')}
              </Text>
            </TouchableOpacity>
          </View>
          <Image source={require('../../assets/images/cityscapeGrey.png')} style={style.cityscape} />
        </View>
      );
    }
    

    组件样式:

    import { StyleSheet, Dimensions } from 'react-native';
    import defaultStyles from '../../style';
    
    const { width: screenWidth } = Dimensions.get('window');
    
    export default StyleSheet.create({
      container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: defaultStyles.white
      },
    
      top: {
        flex: 1,
        justifyContent: 'flex-end',
        alignItems: 'center',
        width: '100%'
      },
    
      bottom: {
        flex: 1,
        width: '100%'
      },
    
      animatedContainer: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
        width: '100%'
      },
    
      postcode: {
        padding: 12,
        height: 50,
        backgroundColor: 'white',
        width: '100%',
        borderRadius: 5,
        fontSize: 17
      },
    
      text: {
        width: 296,
        height: 44,
        fontFamily: 'SFProText-Light',
        fontSize: 16,
        fontWeight: '500',
        fontStyle: 'normal',
        lineHeight: 22,
        letterSpacing: 0,
        textAlign: 'center',
        color: defaultStyles.balticSea
      },
    
      logo: {
        marginBottom: 14
      },
    
      error: {
        color: defaultStyles.brickRed,
        marginVertical: 12,
        width: '100%',
        textAlign: 'center'
      },
    
      submit: {
        width: 311,
        height: 56,
        borderRadius: 4,
        backgroundColor: defaultStyles.mountainMeadow,
        justifyContent: 'center',
        alignItems: 'center',
        alignSelf: 'center',
        marginTop: 30
      },
    
      submitText: {
        width: 311,
        height: 21,
        fontFamily: 'SFProDisplay-Heavy',
        fontSize: 18,
        fontWeight: 'bold',
        fontStyle: 'normal',
        letterSpacing: 0,
        textAlign: 'center',
        color: defaultStyles.white
      },
    
      highlight: {
        color: defaultStyles.mountainMeadow
      },
    
      cityscape: {
        position: 'absolute',
        left: 0,
        bottom: 0,
        width: screenWidth,
        resizeMode: 'repeat'
      }
    });
    

    事先谢谢你的帮助。

    2 回复  |  直到 7 年前
        1
  •  1
  •   Nirmalsinh Rathod    7 年前

    你需要给予 高度 宽度 可触摸不透明度

                <TouchableOpacity
                    activeOpacity={0.97} 
                    onPressIn={() => console.log('in')} 
                    onPressOut={() => console.log('out')} 
                    onPress={() => { console.log('do something!'); navigation.navigate('EnterEmail'); }} 
                    style={[style.submit, { zIndex: 99999, elevation: 99999, height:200, width:200 }]}>
                    <Text style={style.submitText}>
                        {i18n.t('SIGN_IN')}
                    </Text>
                </TouchableOpacity>
    

    我只是加了一句 二百 用于测试。

    Android的工作代码:

    <View style={{ flex: 1, backgroundColor: 'red' }}> <View style={style.container}> <View style={style.top}> </View> <View style={style.bottom}> <TouchableOpacity activeOpacity={0.97} onPressIn={() => alert('in')} onPressOut={() => alert('out')} onPress={() => { alert('do something!'); }} style={[style.submit, { zIndex: 99999, elevation: 99999 }]}> <Text style={style.submitText}> GENERAL TEXT </Text> </TouchableOpacity> </View> </View> </View>

        2
  •  0
  •   JmJ    7 年前

    我找到了问题的原因。

    简短回答:

    我的应用程序根目录中有一个组件正在创建一个不可见的覆盖。这是因为 display: 'none' position: 'absolute' 如果应用于Android上的同一个元素,则不起作用。

    长回答:

    在我的根组件中,我有一个菜单,它从屏幕底部出现,名为 OptionsMenu :

    export default function App (): Element<typeof Provider> {
      return (
        <Provider store={store}>
          <ActionSheetProvider>
            <OptionsMenuContext.Provider>
              <>
                <Navigation uriPrefix={DEEP_LINK_URI_PREFIX} ref={setNavigator} />
                <Notification />
                <OptionsMenu />
              </>
            </OptionsMenuContext.Provider>
          </ActionSheetProvider>
        </Provider>
      );
    }
    

    里面 选择权 有一个覆盖屏幕的覆盖层,这样我们可以在菜单出现时使所有内容变暗。覆盖层(最外层 Animated.View 位置:“绝对” 以及 显示:“没有” . 这个 display 设置来自道具和 position 来自 style.container :

    function OptionsMenu ({ hideOptionsMenu, overlayDisplay, overlayOpacity, containerPositionBottom, options = [] }: Props): Element<typeof Animated.View> {
      return (
        <Animated.View style={[style.container, { display: overlayDisplay }]}>
          <TouchableWithoutFeedback onPress={hideOptionsMenu}>
            <Animated.View style={[style.overlay, { opacity: overlayOpacity }]} />
          </TouchableWithoutFeedback>
          <Animated.View style={[style.optionsContainer, { bottom: containerPositionBottom }]}>
            {options.map(({ icon, text, onPress, type, component: Component }: Option) => !Component
              ? (
                <TouchableOpacity activeOpacity={0.97} key={text} disabled={!onPress} onPress={onPress} style={style.optionContainer}>
                  {!!icon && (
                    <Image source={icon} style={[style.optionIcon, optionTypeTintMap[type]]} />
                  )}
                  <Text style={[style.optionText, optionTypeColorMap[type || 'neutralColor']]}>
                    {text}
                  </Text>
                </TouchableOpacity>
              ) : (
                <Component key={text} />
              ))}
          </Animated.View>
        </Animated.View>
      );
    }
    
    export default withOptionsContext(OptionsMenu);
    

    问题是在Android上,绝对定位将覆盖显示设置。因此,解决方案是将绝对定位的组件包装在控制显示设置的组件中:

    选项菜单/style.js:

    export default StyleSheet.create({
      container: {
        flex: 1,
        // Removed these:
        // position: 'absolute',
        // left: 0,
        // bottom: 0,
        // width: screenWidth,
        // height: screenHeight,
        // zIndex: 19,
        // elevation: 19
      },
    
      // Moved styles to new property:
      overlayContainer: {
        flex: 1,
        position: 'absolute',
        left: 0,
        bottom: 0,
        width: screenWidth,
        height: screenHeight,
        zIndex: 19,
        elevation: 19
      },
    

    选项菜单/选项菜单.js:

    function OptionsMenu ({ hideOptionsMenu, overlayDisplay, overlayOpacity, containerPositionBottom, options = [] }: Props): Element<typeof Animated.View> {
      return (
        // Added new <View /> to control display setting separately:
        <View style={[style.container, { display: overlayDisplay }]}>
          <Animated.View style={style.overlayContainer}>
    
    推荐文章