Changing Drawer left and right button image dynamically? - react-native

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

Related

How to make child prevent ScrollView from scrolling

Context:
I have a graph, where I allow a user to "scrub" their finger over the graph, and see a tooltip
This graph is nested inside a ScrollView
<ScrollView>
<Graph>
</ScrollView>
Problem:
I want to "disable" the scroll view when the touch is happening over that graph
I'm not sure how to do that.
function Graph() {
return (
<View onTouchStart={e => /* prevent ScrollView from scrolling */} />
)
}
I know about scrollEnabled on ScrollView, but it won't be easy for me to thread that prop. Is there a way I can just "stop propagation" for that touch event, inside Graph?
onTouchStart={(e) => e.stopPropagation()} does not do the trick
My current solution is the following:
import React, { createContext, useRef } from "react";
import { ScrollView } from "react-native";
export const ScrollEnabledContext = createContext(null);
export default function StoppableScrollView(props) {
const ref = useRef(null);
const setIsEnabled = (bool) => {
ref.current && ref.current.setNativeProps({ scrollEnabled: bool });
};
return (
<ScrollEnabledContext.Provider value={setIsEnabled}>
<ScrollView ref={ref} {...props} />
</ScrollEnabledContext.Provider>
);
}
By using setNativeProps, I prevent a render. I can reference ScrollEnabledContext in the child component to prevent scrolls. A bit brittle, but gets the job done. Would be fantastic if I didn't have to do this, and could use something like stopPropagation

Change SVG component on press with React Native

Background
Pretty simple question: I want to create a "like" button in RN. To do this I have to separate components which are SVG files. One is just the outline of a heart, the other one is filled.
The screen in which I'm trying to build this button is a Function component so I should use hooks. I know about state but don't know how to properly use it.
What I need
A Touchable Opacity component which holds an onPress method which changes the image component when pressed.
Thanks a lot in advance!
import React ,{useState} from 'react';
import {TouchableOpacity } from "react-native";
export default function Like() {
const [isLiked,setIsLiked]=useState(false) ;
const handleLikePress=()=>{
setIsLiked(!isLiked)
}
return (
<TouchableOpacity onPress={handleLikePress}>
{isLiked? <FilledHeartSVG/>: <OutlineHeartSVG/> }
</TouchableOpacity>
)
}
by default, we are showing an outline of a heart SVG
when press event trigger we are changing isLiked state value
if isLiked is true then show filled heart SVG
if isLiked is false then show outline of a heart SVG
FilledHeartSVG and OutlineHeartSVG is just example use your SVG there
You can do something like below, here i have made a toggle for the text but you can change it to your image component, also the callback prop can be used if you want to use that outside the LikeButton
const LikeButton = ({callback}) => {
const [liked, setLiked] = React.useState(false);
return (
<TouchableOpacity onPress={()=>{
setLiked(!liked);
if(callback)
{
callback();
}
}}>
<Text>{liked?"Liked":"Like"}</Text>
</TouchableOpacity>
);
};
You can tryout this snack which uses icons
https://snack.expo.io/#guruparan/likebutton

How to implement focus/blur response in a custom react-native TextInput

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.

Implement Hero animation like shoutem About extension

I try to implement the hero animation like in the shoutem About extension. Basically, I add animationName to NavigationBar and the Image like in the extension. I also had to add ScrollDriver because it would error-ed otherwise. But it seems the NavigationBar does not pass the driver down to its child components, so I still got this error. Is it possible to implement the hero animation like what was demonstrated here? https://medium.com/shoutem/declare-peace-with-react-native-animations-e947332fa9b1
Thanks,
import { ScrollDriver } from '#shoutem/animation';
getNavBarProps() {
const driver = new ScrollDriver();
return {
hasHistory: true,
driver: driver,
title: 'Title',
navigateBack: () => this.props.navigation.dispatch(NavigationActions.back()),
styleName: 'fade clear',
animationName: 'solidify',
};
}
render () {
const driver = new ScrollDriver();
return (
<Screen styleName=" paper">
<View style={{height:68}}>
<NavigationBar {...this.getNavBarProps()} />
</View>
<ScrollView style={styles.container}>
<Image
styleName="large"
source={require('../Images/spa2.jpg') }
defaultSource={require('../Images/image-fallback.png')}
driver={driver}
animationName="hero"
/>
...
I'm the author of the article, from you question, I'm not sure are you trying to create an extension on shoutem or you just want to recreate animation in any other React Native app.
If you are creating an extension or CardStack from #shoutem/ui/navigation, you don't event need to care for ScrollDriver. It would be pushed throught the context to the ScrollView (imported from #shoutem/ui) and NavigationBar (imported from #shoutem/ui/navigation).
If you are creating your own React Native project to be able to do it like in article I suggest the following. At the root component of your app:
import ScrollView from '#shoutem/ui';
class App extends Component {
...
render() {
return (
<ScrollView.DriverProvider>
<App />
</ScrollView.DriverProvider>
);
}
}
Then you don't have to take care of initialization of ScrollDriver on each screen, if you use our components and a ScrollView it will push the driver where it needs to be. :) So your screen at the end would look like this:
import {
ScrollView,
NavigationBar,
Image
} from '#shoutem/ui';
class MyScreen extends Class {
render() {
return (
<Screen>
<NavigationBar animationName="solidify" />
<ScrollView>
<Image animationName="hero" />
</ScrollView>
</Screen>
);
}
}
The whole working example is here https://github.com/shoutem/ui/tree/develop/examples/RestaurantsApp/app

React Native/Shoutem: navigateBack() not working

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.