I'm using react-native-keyboard-spacer.
I want to implement the feature of automatically popping up the keyboard.
The documentation says onToggle method is called when when keyboard toggles. Two parameters passed through, keyboardState (boolean, true if keyboard shown) and keyboardSpace (height occupied by keyboard)
Can anyone show me an example of how to accomplish this?
onToggle() is only called after the keyboard is toggled. To achieve the functionality you desire, just use the built in method in TextInput to focus an input when a component finishes mounting:
componentDidMount() {
this._myTextInput.focus();
}
render() {
return (
<TextInput
style={{height: 40}}
ref={component => this._myTextInput = component}
/>
);
}
onToggle get's called when the keyboard is either shown or hidden. If you want to pop up the keyboard without the user clicking anything, then you would need to focus() on a textInput.
handleOnToggle(keyboardState, keyboardSpace) {
// Do whatever you want with keyboardState
}
render() {
return <View>
<KeyboardSpacer onToggle={this.handleOnToggle} />
</View>
}
Related
I implemented a custom react-native TextInput backed by a native library. It's working pretty well except that when I tap outside of the textfield, it doesn't blur automatically and the keyboard doesn't disappear. I also tried with Keyboard.dismiss(), it doesn't work either. I looked at the 'official' TextInput implementation to replicate it without any success.
I added this code in my custom implementation (componentDidMount)
if (this.context.focusEmitter) {
this._focusSubscription = this.context.focusEmitter.addListener(
'focus',
el => {
if (this === el) {
this.requestAnimationFrame(this.focus);
} else if (this.isFocused()) {
this.blur();
}
},
);
if (this.props.autoFocus) {
this.context.onFocusRequested(this);
}
} else {
if (this.props.autoFocus) {
this.requestAnimationFrame(this.focus);
}
}
and I also defined the required contextTypes
static contextTypes = {
focusEmitter: PropTypes.instanceOf(EventEmitter)
}
code from TextInput
The problem I have is that the focusEmitter is undefined in the context and I have no idea from where it's provided in the context nor if it's actually the way it works for the regular TextInput. The only occurence of focusEmitter I could find in the react-native repo is in NavigatorIOS which I don't even use in my app.
Could anyone clarify this to me?
The simpler way to do what you want is to use Keyboard.dismiss() on a TouchableWithoutFeedback just like following example:
import {Keyboard} from 'react-native';
...
render(){
return(
<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
<View>
// Return everything here
<TextInput />
</View>
</TouchableWithoutFeedback>
)
}
So when you tap outside the input it will dismiss keyboard and blur the TextInput.
I'd like to have a context menu triggered on long press different places using React Native.
I.e. in a dialer like the default dailer. You can long-click on any contact and get a 'copy number' menu. And also you can long-click on the name of the person once you've opened their 'contact card'.
The straight-forward way needs a lot of copy-pasted boilerplate, both components and handlers.
Is there a better pattern for doing this?
All Touchable components (TouchableWithoutFeedback, TouchableOpacity etc.) has a property called onLongPress. You can use this prop to listen for long presses and then show the context menu.
To eliminate code mess and doing lots of copy paste you can separate your context menu as a different component and call it when the long press happen. You can also use an ActionSheet library to show the desired options. React native has a native API for iOS called ActionSheetIOS. If you get a little bit more experience in react and react-native you can create a better logic for this but I'm going to try to give you an example below.
// file/that/contains/globally/used/functions.js
const openContextMenu = (event, user, callback) => {
ActionSheetIOS.showActionSheetWithOptions({
options: ['Copy Username', 'Call User', 'Add to favorites', 'Cancel'],
cancelButtonIndex: [3],
title: 'Hey',
message : 'What do you want to do now?'
}, (buttonIndexThatSelected) => {
// Do something with result
if(callback && typeof callback === 'function') callback();
});
};
export openContextMenu;
import { openContextMenu } from './file/that/contains/globally/used/functions';
export default class UserCard extends React.Component {
render() {
const { userObject } = this.props;
return(
<TouchableWithoutFeedback onLongPress={(event) => openContextMenu(event, userObject, () => console.log('Done')}>
<TouchableWithoutFeedback onLongPress={(event) => openContextMenu(event, userObject, () => console.log('Done'))}>
<Text>{userObject.name}</Text>
<Image source={{uri: userObject.profilePic }} />
</TouchableWithoutFeedback>
</TouchableWithoutFeedback>
);
}
}
Similarly as the previous answer combine onLongPress with imperative control for popup menu - something like
<TouchableWithoutFeedback onLongPress={()=>this.menu.open()}>
<View style={styles.card}>
<Text>My first contact name</Text>
<Menu ref={c => (this.menu = c)}>
<MenuTrigger text="..." />
<MenuOptions>
// ...
</MenuOptions>
</Menu>
</View>
</TouchableWithoutFeedback>
When it comes to a lot of boilerplate - in React you can do your own components that you can reuse everywhere thus reducing boilerplate (and copy&paste)
See full example on https://snack.expo.io/rJ5LBM-TZ
So that's what my render list looks like:
renderEvent(){
return this.props.eventList.map(listedEvent=>
<CardSection key={listedEvent._id}>
<EventListItem>
{listedEvent.eventName}
</EventListItem>
<DeleteButton
onClick={this.deleteEvent(listedEvent._id)}
key={listedEvent._id}
/>
</CardSection>
);
}
and here the rendering of the whole list
render(){
if (this.props.eventList !== undefined) {
return(
<Card>
{this.renderEvent()}
</Card>
)
}else{
return(
<View>
<Spinner/>
</View>
)
}
}
}
So far so good, the list and the delete button appear correctly, yet when I try to delete one line, it addresses all. I created my event handler which for now, only logs the passed id.
deleteEvent(eventID){
console.log(eventID)
}
Yet when called, it logs all the _ids on the list. What am I doing wrong? How can I make sure I'm passing one single id of the list item I'm clicking on?
Thank you!
Problem is that you are rather than passing a deleteEvent function to onClick prop you are executing it. This causes to deleteEvent fire for each item while rendering.
You can sort this out by changing this,
onPress={this.deleteEvent(listedEvent._id)}
to this
onPress={() => this.deleteEvent(listedEvent._id)}
This will also assure that deleteEvent is bind with this.
react-native-router-flux v3.37.0
react-native v0.42.0
I'm trying to update drawer navigation bar right image dynamically where I have used leftButtonImage, rightButtonImage, where once user read all the notification I want to change the button image.
I could not manage to re-render or update this button image, Is this feature not supported or is there something that I'm missing?
You can call Actions.refresh when you need to refresh the view, example:
Actions.refresh({key: 'profileView', renderRightButton: this.renderRightButton });
and also define renderRightButton:
renderRightButton() {
return (
<TouchableOpacity onPress={ console.log(this) } >
<Text>Logout</Text>
</TouchableOpacity>
)
}
and lastly don't forget to import Actions from react-native-router-flux
import {Actions} from 'react-native-router-flux';
You can re-render using props or states naturally.
Check the states you want, and apply image resource following the states.(or props)
let NotiImage = {
normal: require('../assets/image/notinormal.png');
new: require('../assets/image/new.png');
}
render() {
...
<Image source={ this.state.newNoti ? NotiImage.new : NotiImage.normal } />
...
}
My Problem is that I would like to navigateBack() from the BountyDetailsScreen to the LoyaltyScreen, but the navigateBack() function call does not trigger any action. When I log the function it says:
The only thing I notice is, that the navigationStack is empty. When I do the same with the navigateTo function it is working, but then I have a messed up navigation stack.
In my LoyaltyScreen.js I am displaying a ListView. It is a RN ListView (not imported from shoutem).
LoyaltyScreen.js
renderRow(bounty) {
return (
<ListBountiesView
key={bounty.id}
bounty={bounty}
onDetailPress={this.openDetailsScreen}
redeemBounty={this.redeemBounty}
/>
);
}
ListBountiesView.js
The ListBountiesView renders each ListView Row and opens a Detail Screen when clicked on the Row.
render() {
const { bounty } = this.props;
return (
<TouchableOpacity onPress={this.onDetailPress}>
{bounty.type == 0 ? this.renderInShopBounty() : this.renderContestBounty()}
<Divider styleName="line" />
</TouchableOpacity>
);
}
BountyDetailsScreen.js
In the BountyDetailsScreen I display detailed information and would like to navigateBack() to the Loyalty Screen when I press a button.
<Button styleName="full-width" onPress={() => this.onRedeemClick()}>
<Icon name="add-to-cart" />
<Text>Einlösen</Text>
</Button>
onRedeemClick() {
const { bounty, onRedeemPress } = this.props;
onRedeemPress(bounty);
navigateBack();
}
navigateBack is an action creator. You need to map it to props and read it from props in your redeemClick function. Just executing the imported action creator won't do anything since it's not connected to Redux.
Here's an example of you map it to props:
export default connect(mapStateToProps, { navigateBack })(SomeScreen));
Here's how you use it:
const { navigateBack } = this.props;
navigateBack();
I can see that airmiha's answer is what you're looking for, but I just wanted to add onto it.
You can also use hasHistory to set up your #shoutem/ui NavigationBar (if you're using it) with a simple back button that utilises navigateBack().
<NavigationBar
styleName="no-border"
hasHistory
title="The Orange Tabbies"
share={{
link: 'http://the-orange-tabbies.org',
text: 'I was underwhelmed by The Orange Tabbies, but then I looked at that
sweet, sweet back button on the Nav Bar.
#MakeNavBarsGreatAgain',
title: 'Nevermind the cats, check the Nav Bar!',
}}
/>
You can find more examples with the NavigationBar component here.