onPress在Android上不触发,但在iOS上很好

时间:2018-11-20 20:35:06

标签: javascript android react-native

我已经编写了React Native应用,iOS是优先事项,因此我首先构建了该应用。它在App Store中并且运行完美,但是我刚刚开始在Android上工作,尽管所有似乎都可以正常工作,但触摸事件除外,这些事件根本不会触发。

所有可触摸元素都没有调用onPress回调,Button元素也没有。我什至尝试将应用程序彻底剥离,删除导航器,并在初始屏幕上添加大量可触摸元素,但onPress回调仍然没有触发。

下面是我的应用程序初始屏幕的代码,尽管我怀疑其中任何代码都会引起问题:

// @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 个答案:

答案 0 :(得分:1)

您需要将高度宽度赋予 TouchableOpacity

            <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>

我刚刚添加了 200 进行测试。

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>

答案 1 :(得分:0)

我找到了问题的原因。

简短回答:

我的应用程序根目录中有一个正在创建不可见叠加层的组件。发生这种情况是因为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>
  );
}

OptionsMenu内有一个覆盖屏幕的覆盖层,这样我们可以在菜单出现时使所有内容变暗。叠加层(最外面的Animated.View)具有position: 'absolute'display: 'none'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上,绝对定位将覆盖显示设置。因此解决方案是将绝对定位的组件包装在控制显示设置的组件内:

OptionsMenu / 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
  },

OptionsMenu / OptionsMenu.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}>