【发布时间】:2018-10-03 23:55:34
【问题描述】:
我的页面只有一个TextInput,我已经传入了autoFocus prop:autoFocus: true。
<TextInput
style={styles.textInput}
placeholder="Quiz Deck Title"
autoFocus={true}
value={this.state.title}
onChangeText={(title) => this.controlledTextInput(title)}
/>
我要避免的是要求用户在键盘弹出之前“单击”TextInput 框。
但我也希望软键盘也自动打开(如果设备没有硬件键盘)。
有没有办法在本机反应中实现这一点?我正在为 ios 和 android 开发。
如果重要,我的页面将通过 TabNavigator 导航到。
我之所以提到这一点,是因为对另一个类似 SO 问题的评论(见下文)表明他们在使用 StackNavigator 到达他们的页面时遇到了类似的问题.
关于类似 SO 问题的注意事项:
How to open keyboard automatically in React Native?
:没有提供解决方案,其他人的 cmets 建议的结果与我相同:输入已聚焦,但键盘不会自动打开。
Close/hide the Android Soft Keyboard
和Android: show soft keyboard automatically when focus is on an EditText
:正在使用本机android代码(java),而不是反应本机代码(javascript)。
注意:我正在使用 android 模拟器 Nexus 6P 和 android 23(推荐)和 ios 模拟器和 iPhone 6s 进行开发,因为我没有物理设备。
编辑:添加请求的代码
NewDeck.js(我希望键盘自动弹出的视图):
import React from 'react';
import { connect } from 'react-redux';
import { View, Text, TouchableOpacity,
TextInput, KeyboardAvoidingView,
StyleSheet, Platform,
} from 'react-native';
import StyledButton from '../components/StyledButton';
import { saveDeck } from '../store/decks/actionCreators';
import { getDeckList } from '../store/decks/selectors';
import { fetchDecks } from '../utils/api';
import { saveDeckTitle } from '../utils/api';
} from '../utils/colors';
import { titleCase, stripInvalidChars, makeStringUnique }
from '../utils/helpers';
import { white, gray, primaryColor, primaryColorDark, primaryColorLight,
class NewDeck extends React.Component {
state = {
title: '',
canSubmit: false,
}
componentDidMount () {
this.textInputRef.focus()
}
controlledTextInput(title){
title = titleCase(stripInvalidChars(title));
const canSubmit = this.isValidInput(title);
this.setState({ title, canSubmit });
}
isValidInput(text){
return text.trim() !== '';
}
onBlur(){
title = this.state.title.trim();
const unique = makeStringUnique(title, this.props.existingTitles);
this.setState({ title: unique });
}
onSubmit(){
let title = this.state.title.trim();
title = makeStringUnique(title, this.props.existingTitles)
saveDeckTitle(title)
this.props.navigation.navigate('Home');
}
render() {
return (
<View style={styles.container}>
<View style={[styles.cardContainer, {flex: 1}]}>
<Text style={styles.instructionsText}
>
Title for your New Quiz Deck
</Text>
<KeyboardAvoidingView {...keyboardAvoidingViewProps}>
<TextInput
style={styles.textInput}
placeholder="Quiz Deck Title"
value={this.state.title}
onChangeText={(title) => this.controlledTextInput(title)}
/* autoFocus={true} */
ref={ref => this.textInputRef = ref}
/>
</KeyboardAvoidingView>
</View>
<KeyboardAvoidingView
{...keyboardAvoidingViewProps}
style={[styles.buttonsContainer, styles.buttonContainer]}
>
<StyledButton
style={[styles.item, style={flex: 2}]}
onPress={() => this.onSubmit()}
disabled={!this.state.canSubmit}
>
<Text>
Submit
</Text>
</StyledButton>
</KeyboardAvoidingView>
</View>
);
}
}
const keyboardAvoidingViewProps = {
behavior: 'padding',
};
// ...styles definition here, - I posted it in a later code block, to minimize
// clutter, in the event that it is irrelevant to this issue
function mapStoreToProps(store){
const decks = getDeckList(store) || null;
// ensure titles are unique (better UX than if just make id unique)
const existingTitles = decks && decks.map(deck => {
return deck.title
}) || [];
return {
existingTitles,
}
}
export default connect(mapStoreToProps)(NewDeck);
TabNavigator 和 StackNavigator 代码(在 App.js 中):
// ... the TabNavigator I'm using:
import { TabNavigator, StackNavigator } from 'react-navigation';
//... the class's render method, uses StackNavigator (as MainNavigation)
render(){
return (
<Provider store={createStore(rootReducer)}>
<View style={{flex:1}}>
<AppStatusBar
backgroundColor={primaryColor}
barStyle="light-content"
/>
<MainNavigation />
</View>
</Provider>
);
}
}
// ...
const Tabs = TabNavigator(
{
DeckList: {
screen: DeckList,
navigationOptions: {
tabBarLabel: 'Quiz Decks',
tabBarIcon: ({ tintColor }) => // icons only show in ios
<Ionicons name='ios-bookmarks' size={30} color={tintColor} />
},
},
NewDeck: {
screen: NewDeck,
navigationOptions: {
tabBarLabel: 'Create New Deck',
tabBarIcon: ({ tintColor }) => // icons only show in ios
<FontAwesome name='plus-square' size={30} color={tintColor} />
},
},
},
{
navigationOptions: {
// do-not-display page headers for Tab Navigation
header: null
},
tabBarOptions: {
// ios icon and text color; android text color
activeTintColor: Platform.OS === 'ios' ? primaryColor : white,
pressColor: white,
indicatorStyle: {
backgroundColor: primaryColorDark,
height: 3,
},
style: {
height: 56,
backgroundColor: Platform.OS === 'ios' ? white : primaryColor,
shadowColor: 'rgba(0, 0, 0, 0.24)',
shadowOffset: {
width: 0,
height: 3
},
shadowRadius: 6,
shadowOpacity: 1
}
}
}
);
//... StackNavigator uses TabNavigator (as Tabs)
const stackScreenNavigationOptions = {
headerTintColor: white,
headerStyle: {
backgroundColor: primaryColor,
}
};
const MainNavigation = StackNavigator(
// RouteConfigs: This is analogous to defining Routes in a web app
{
Home: {
screen: Tabs, // Which also loads the first Tab (DeckList)
},
Deck: {
screen: Deck,
navigationOptions: stackScreenNavigationOptions,
},
Quiz: {
screen: Quiz,
navigationOptions: stackScreenNavigationOptions,
},
NewDeck: {
screen: NewDeck,
navigationOptions: stackScreenNavigationOptions,
},
NewCard: {
screen: NewCard,
navigationOptions: stackScreenNavigationOptions,
},
},
);
这是 NewDeck.js
的 styles 定义const styles = StyleSheet.create({
// CONTAINER styles
wrapper: {
// this was the previous container style
flex: 1,
backgroundColor: white,
alignItems: 'center',
justifyContent: 'center',
},
container: {
flex: 1,
backgroundColor: white,
alignItems: 'center',
justifyContent: 'space-between',
padding: 10,
paddingTop: 30,
paddingBottom: 5,
},
cardContainer: {
flex: 1,
justifyContent: 'flex-start',
alignSelf: 'stretch',
backgroundColor: '#fefefe',
padding: 20,
marginLeft: 30,
marginRight: 30,
marginTop: 10,
borderRadius: Platform.OS === 'ios' ? 20 : 10,
shadowRadius: 3,
shadowOpacity: 0.8,
shadowColor: 'rgba(0, 0, 0, 0.24)',
shadowOffset: {
width: 0,
height: 3,
},
marginBottom:20,
},
buttonsContainer: {
flex: 3,
alignSelf: 'stretch',
justifyContent: 'flex-start',
},
buttonContainer: {
justifyContent: 'center',
margin: 10,
},
// TEXT Styles
instructionsText: {
flex: 1,
fontSize: 20,
color: gray,
alignSelf: 'center',
textAlign: 'center',
},
// INPUTTEXT styles
textInput: {
fontSize: 27,
color: primaryColor,
alignSelf: 'stretch',
flexWrap: 'wrap',
textAlign: 'center',
marginTop: 10,
},
});
StyledButton.js(基本上,TouchableOpacity 具有特定于平台的样式,可在整个应用程序中普遍使用):
import React from 'react';
import { Text, TouchableOpacity, StyleSheet, Platform } from 'react-native';
import { white, gray, primaryColor, primaryColorLight, primaryColorDark} from '../utils/colors';
export default function TextButton({ children, onPress, customColor, disabled=false }) {
const disabledColor = disabled ? gray : null;
const backgroundColor = Platform.OS==='ios' ? white : disabledColor || customColor || primaryColorLight;
const borderColor = Platform.OS==='ios' ? disabledColor || customColor || primaryColorDark
const textColor = Platform.OS==='ios' ? disabledColor || customColor || primaryColor : white;
const btnStyle = Platform.OS==='ios' ? styles.iosBtn : styles.androidBtn;
const txtStyle = styles.txtDefault;
const btnColor = { backgroundColor, borderColor };
const txtColor = { color: textColor };
return (
<TouchableOpacity
onPress={onPress}
disabled={disabled}
style={[btnStyle, btnColor]}
>
<Text
style={[styles.txtDefault, txtColor]}
>
{children}
</Text>
</TouchableOpacity>
);
}
const styles = StyleSheet.create({
txtDefault: {
textAlign: 'center',
// because of bleeding of white text to colored background on android,
// enlarge text (or increase fontWeight) for better readability
fontSize: Platform.OS==='ios' ? 15 : 18,
padding: 10,
},
iosBtn: {
height: 45,
borderRadius: 7,
alignSelf: 'center',
justifyContent: 'center',
alignItems: 'center',
// ios only settings
borderColor: primaryColorDark,
borderWidth: 1,
borderRadius: 3,
paddingLeft: 25,
paddingRight: 25,
},
androidBtn: {
height: 45,
borderRadius: 5,
alignSelf: 'center',
justifyContent: 'center',
alignItems: 'center',
// android- only settings
// (padding accepts clicks, vs. margin === no-click zone)
padding: 20,
paddingLeft: 15,
paddingRight: 15,
},
});
// ios has white buttons with colored outlines and colored text
// android has colored buttons with white text
// Pass in a button color, or it defaults to the App's primary colors
【问题讨论】:
-
如果您只在模拟器上进行过测试,那么您可能只是默认隐藏了键盘。在ios模拟器中,按cmd + k 开启。
-
@MattAft - 是的,我确实碰巧找到了。很高兴您为未来的访问者提及它,因为这不是一个明显的要求。
-
@MattAft 目前在两个平台上,用户都需要在键盘出现之前“单击”文本字段。当我使用这样的应用程序时,我发现这是一个令人讨厌的功能。我更喜欢的是,当页面加载时键盘会自动弹出。
-
您可以在组件加载时将焦点添加到任何
textinput以使用它的引用显示键盘 -
@MattAft 我错了:键盘不会在 Android 中自动弹出,但在 iOS 中会弹出(cmd-k 已打开)。
标签: react-native react-navigation