How do I enable touch on multiple buttons simultaneously in react native? - javascript

I need that when I am touching and holding one button then I should also be able to touch on the button 1.
<View>
<View
onStartShouldSetResponder={()=>this.console("Button 2 Clicked")}>
<Text>BUTTON 2</Text>
</View>
<TouchableOpacity
onPressIn={()=>this.console('Button 1 pressed')}
onPressOut={()=>this.console('Button 1 released')}>
<View>
<Text>BUTTON 1</Text>
</View>
</TouchableOpacity>
</View>
Basically, I have a screen where I can record a video by tapping and holding the record button(Button 1). On the same screen, I have a flip camera button (Button 2). I want that I should be able to click on the flip camera button while I am recording the video.

This problem can easily be resolved using onTouchStart, onTouchEnd props of View component without using gesture responder methods.
So the modified code will look like
<View>
<View onTouchStart={()=>this.console("Button 2 Clicked")}>
<Text>BUTTON 2</Text>
</View>
<View
onTouchStart={()=>this.console('Button 1 pressed')}
onTouchEnd={()=>this.console('Button 1 released')}>
<Text>BUTTON 1</Text>
</View>
</View>

This is my solution for multiple buttons
import React, { Component } from 'react';
import {
View,
PanResponder,
} from 'react-native';
import ReactNativeComponentTree from'react-native/Libraries/Renderer/shims/ReactNativeComponentTree';
export default class MultiTouch extends Component{
constructor(props) {
super(props);
this.onTouchStart = this.onTouchStart.bind(this);
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchCancel = this.onTouchCancel.bind(this);
this.triggerEvent = this.triggerEvent.bind(this);
}
onTouchStart(event){
const element = ReactNativeComponentTree.getInstanceFromNode(event.target)._currentElement;
this.triggerEvent(element._owner, 'onPressIn');
}
onTouchEnd(event){
const element = ReactNativeComponentTree.getInstanceFromNode(event.target)._currentElement;
this.triggerEvent(element._owner, 'onPressOut');
}
onTouchCancel(event){
const element = ReactNativeComponentTree.getInstanceFromNode(event.target)._currentElement;
this.triggerEvent(element._owner, 'onPressOut');
}
onTouchMove(event){
// console.log(event);
}
triggerEvent(owner, event){ // Searching down the
if(!owner || !owner.hasOwnProperty('_instance')){
return;
}
if(owner._instance.hasOwnProperty(event)){
owner._instance[event]();
}else{
this.triggerEvent(owner._currentElement._owner, event);
}
}
render(){
return (
<View
onTouchStart={this.onTouchStart}
onTouchEnd={this.onTouchEnd}
onTouchCancel={this.onTouchCancel}
onTouchMove={this.onTouchMove}>
{this.props.children}
</View>
);
}
}
Then I simply wrap the buttons that needs to be pressed at the same time withe the component
<MultiTouch style={this.style.view}>
<UpDownButton />
<UpDownButton />
</MultiTouch>
Cheers!
UPDATE
Because of breaking changes in native react v.0.51, my previous solution does not work any more. But I manage to create a new one. Instead of using TouchableWithoutFeedback and onPress I use View and onTouch on each button that should have multitouch.
import React, { Component } from 'react';
import {
View,
} from 'react-native';
export default class RoundButtonPart extends Component{
constructor(props) {
super(props);
this.state = { active: false };
this.onTouchStart = this.onTouchStart.bind(this);
this.onTouchEnd = this.onTouchEnd.bind(this);
this.onTouchCancel = this.onTouchCancel.bind(this);
}
onTouchStart(event){
this.setState({ active: true });
this.props.onPressIn && this.props.onPressIn();
}
onTouchEnd(event){
this.setState({ active: false });
this.props.onPressOut && this.props.onPressOut();
}
onTouchCancel(event){
this.setState({ active: false });
this.props.onPressOut && this.props.onPressOut();
}
onTouchMove(event){
}
render(){
return (
<View
onTouchStart={this.onTouchStart}
onTouchEnd={this.onTouchEnd}
onTouchCancel={this.onTouchCancel}
onTouchMove={this.onTouchMove}>
{this.props.children}
</View>
);
}
}

I used react-native-gesture-handler. Install it and just replace
import { TouchableOpacity } from 'react-native';
with
import { TouchableOpacity } from 'react-native-gesture-handler';
Example
<View>
<TouchableOpacity
onPressIn={()=>this.console('Button 2 pressed')}
onPressOut={()=>this.console('Button 2 released')}>
<View>
<Text>BUTTON 2</Text>
</View>
</TouchableOpacity>
<TouchableOpacity
onPressIn={()=>this.console('Button 1 pressed')}
onPressOut={()=>this.console('Button 1 released')}>
<View>
<Text>BUTTON 1</Text>
</View>
</TouchableOpacity>
</View>
Link: https://software-mansion.github.io/react-native-gesture-handler/docs/component-touchables.html
This library also offers button components which can be directly used instead of wrapping Text with TouchableOpacity

Try:
import { TouchableOpacity } from 'react-native';
Instead of:
import { TouchableOpacity } from 'react-native-gesture-handler';
Will help you to multiple buttons.
For example, if you have a TouchableOpacity inside a TouchableWithoutFeedback, when TouchableOpacity is touched, it will only call TouchableOpacity's onPress, and will not be called onPress of TouchableWithoutFeedback.

Related

React Native: How to call a function from another component

I am making a simple app to practice using modals. I have my modal component in a separate file from App.js. I have a button inside the modal and outside of the modal that should toggle the visibility of the modal. To handle the visibility toggle, I have a method in App.js, setVisibility, that takes in a boolean arg and sets the isVisibility state. When I had the modal component defined within App.js earlier everything was working fine, but I'm not sure about accessing and setting the state of a component from another file.
My modal component:
import React, { Component } from "react";
import { View, Modal, TouchableHighlight, Text } from 'react-native';
export default class AppModal extends Component {
constructor(props) {
super(props);
this.state = {
isVisible: this.props.isVisible
}
this.toggleVisibility = this.toggleVisibility.bind(this);
}
toggleVisibility(show) {
this.props.setVisibility(show);
}
render() {
return (
<View>
<Modal
animationType='slide'
visible={this.state.isVisible}
onRequestClose={() => this.toggleVisibility(false)}
>
<View style={{alignItems: 'center', justifyContent: 'center', flex: 1}}>
<Text>Inside the modal</Text>
<TouchableHighlight style={{padding: 10}} onPress={() => this.toggleVisibility(false)} >
<Text>Press me</Text>
</TouchableHighlight>
</View>
</Modal>
</View>
)
}
}
My app.js:
import React, { Component } from 'react';
import { Text, View, TouchableHighlight } from 'react-native';
import AppModal from './AppModal'
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
isVisible: false
}
this.setVisibility = this.setVisibility.bind(this);
}
setVisibility(show) {
this.setState({
isVisible: show
})
}
render() {
return (
<View style={{flex: 1}}>
<AppModal toggle={this.setVisibility} isVisible={this.state.isVisible} />
<View style={{justifyContent: 'center', alignItems: 'center', flex: 1}}>
<Text>Outside of the modal</Text>
<TouchableHighlight style={{padding: 10}} onPress={() => {this.setVisibility(true); console.log(this.state);}} >
<Text>Press me</Text>
</TouchableHighlight>
</View>
</View>
)
}
}
Now I get an error when I press the button in the modal which tells me that 'this.props.setVisibility is not a function'.
Please let me know if I can explain my question better. Thank you in advance!
You send the toggling callback method as toggle={this.setVisibility}, not setVisibility={this.setVisibility}, so your callback must be:
toggleVisibility(show) {
this.props.toggle(show);
}

How to use password authentication before navigate to screens and adapt it with the bottom tab navigator in React Native?

This question is an extension of this question and it is from the same member who asked this.
First, his problem was, how to authenticate before navigating to screens. But then, he asked, how to adapt that navigated new screen to the particular tab in the bottom tab navigator (Let's say Tab1). That means, after it is navigated to a particular screen after authenticated, he wants to click on another tab (Let's say Tab2), and then click on the previous tab (Tab1) and the navigated screen should still display on that previous tab (Tab1).
I've provided my answer to this new question below...
This is the solution that I'm suggesting.
This answer is an extension of the answer in the first question.
Home.js
import React, { Component } from 'react';
import { Text, View, TouchableOpacity, ScrollView } from 'react-native';
import PasswordInputModal from './PasswordInputModal'
import HelderScreen from 'path/to/HelderScreen';
import LolsScreen from 'path/to/LolsScreen';
import AthleanScreen from 'path/to/AthleanScreen';
export default class HomeScreen extends Component {
constructor(props) {
super(props);
this.state = {
screen: null,
}
}
switchScreen = () => {
switch (this.state.screen) {
case 'Helder' : return <HelderScreen />;
case 'Lols' : return <LolsScreen />;
case 'Athlean': return <AthleanScreen />;
default : this.setState({ screen: null });
}
}
render() {
if(this.state.screen) { return this.switchScreen() }
return (
<View style={styles.container}>
<ScrollView style={styles.flatlist}>
<View style={styles.flatlist1}>
<TouchableOpacity onPress={() => this.PasswordInputModal.open('Helder')}>
<Text style={styles.item}>Empresa do Helder</Text>
</TouchableOpacity>
</View>
<View style={styles.flatlist1}>
<TouchableOpacity onPress={() => this.PasswordInputModal.open('Lols')}>
<Text style={styles.item}>Lols Inc</Text>
</TouchableOpacity>
</View>
<View style={styles.flatlist1}>
<TouchableOpacity onPress={() => this.PasswordInputModal.open('Athlean')}>
<Text style={styles.item}>Tesla Portugal</Text>
</TouchableOpacity>
</View>
</ScrollView>
<PasswordInputModal
ref={modal => this.PasswordInputModal = modal}
navigation={this.props.navigation}
onAuthentication={(screen) => this.setState({ screen })} />
</View>
);
}
}
Here, if the state called screen is set to the particular name of the screen, it will conditionally render that particular screen. Otherwise, it will render the buttons to go to those screens.
PasswordInputModal.js
import React, { Component } from 'react';
import { View, TextInput, Button } from 'react-native';
import Modal from 'react-native-modal';
export default class PasswordInputModal extends Component {
constructor(props) {
super(props);
this.state = {
password : '',
isVisible : false,
screen : null,
};
}
open = (screen) => this.setState({ isVisible: true, screen: screen });
close = () => this.setState({ isVisible: false });
onPressSubmitButton = () => {
//Use any authentication method you want according to your requirement.
//Here, it is taken as authenticated if and only if the input password is "12345".
const isAuthenticated = ("12345" == this.state.password); //If input password is '12345', isAuthenticated gets true boolean value and false otherwise.
if(isAuthenticated) {
this.props.onAuthentication(this.state.screen);
}
else {
console.log("Invalid password"); //Prompt an error alert or whatever you prefer.
}
this.close();
}
renderModalContent = () => (
<View>
<TextInput type={'password'} value={this.state.password} onChangeText={(password) => this.setState({ password })} />
<Button onPress={() => this.onPressSubmitButton()} title="Submit" color="#841584" />
</View>
);
render() {
return (
<Modal
isVisible={this.state.isVisible}
backdropColor="#000000"
backdropOpacity={0.9}
animationIn="zoomInDown"
animationOut="zoomOutUp"
animationInTiming={600}
animationOutTiming={600}
backdropTransitionInTiming={600}
backdropTransitionOutTiming={600}
>
{this.renderModalContent()}
</Modal>
);
}
}
What I've done here is, when the user is authenticated, a state called screen is set to the name of the screen which should be displayed. Actually, this is not something like navigating. This is actually called Conditional Rendering.
I didn't test this code myself. I hope this will help to the member who asked this question.

typeError: Cannt read property 'goBack' of undefined

So the scenario is, I want to implement a GoBack Icon at the top of my app,that leads back to previous page. I am using stack navigator and disabled the header. So I need a go back button. I decided to make a component for that, here is my code,
import { Ionicons } from '#expo/vector-icons';
function GoBack(){
return (
<Ionicons onPress={()=>this.props.navigation.goBack()} name="md-arrow-back" size={24} color="#0c85f3" />
);
}
export default GoBack;
if I do it like this then an it shows me a typeError: Cannt read property 'goBack' of undefined.but if I put onPress as props and implement the same line of code onPress={()=>this.props.navigation.goBack()} it works perfectly.
I can not apply onPress props everywhere. Its a app with a lot of screens. How do I apply it in the component itself?
I think I am in lack of deep understanding of React navigation. Please help me understand the solution too.
Here is how I am using the GoBack Component:
import React, { Component } from 'react';
import {View, StyleSheet, Text, FlatList} from 'react-native';
import TestRoomtData from '../../../testData';
import HistoryCard from '../../../components/cards/historyUserCard';
import GoBack from '../../../shared/goBackButton';
class UserHistory extends Component{
render(){
return(
<View style={styles.container}>
<View style={{flexDirection:"row",}}>
<GoBack />
<Text style={styles.title}>History</Text>
</View>
<Text style={styles.title01}>Past Patients</Text>
<FlatList
data={TestRoomtData}
renderItem={({item})=>([
<View>
<HistoryCard
prescription={item.prescription}
diagnosis={item.diagnosis}
date={item.date}
source={{
uri: item.uri
}}
btnText01="More"
btnText02="Edit"
onPressBtn2={()=> this.props.navigation.navigate('Edit History') }/>
</View>
]
)}
/>
</View>
);
}
}
It's a functional component,
First : so you can't use this. ,
Second : you forgot to get props
function GoBack(props){ // <---- HERE
return (
<Ionicons
onPress={props.navigation.goBack} // <---- HERE
name="md-arrow-back" size={24} color="#0c85f3" />
);
}
In functional component in react, you can't use this keyword to access props.
In the current situation you have to pass navigation prop in GoBack
something like this,
function Goback(props) {
const { navigation } = props;
return (
<Ionicons
onPress={() => navigation.goBack()}
name="md-arrow-back"
size={24}
color="#0c85f3"
/>
);
}
Now, call the GoBack component,
<GoBack
navigation={{ goBack: () => goBack() }}
/>

Using react-native-modalbox in ListView causes modalbox to only fill the list item space instead of full screen?

When I use the package react-native-modalbox with a FlatList (each list item can spawn a distinct modal when tapped), the modal that is spawned only fills the area of the list item instead of going full screen like it normally should.
A working snack that shows the issue is here:
https://snack.expo.io/BkICbjwWQ
For completeness I'll paste the code in here as well:
import React, { Component } from 'react';
import { Text, View, StyleSheet, FlatList, Button } from 'react-native';
import { Constants } from 'expo';
import Modal from "react-native-modalbox";
// You can import from local files
import AssetExample from './components/AssetExample';
// or any pure javascript modules available in npm
import { Card } from 'react-native-elements'; // Version can be specified in package.json
export default class App extends Component {
render() {
let myRefs = [];
return (
<View style={styles.container}>
<FlatList
data={[{key: 'a'}, {key: 'b'}]}
renderItem={({item}) => <View>
<Modal
style={[styles.modal]}
ref={(modalItem) => {myRefs[item.key] = modalItem;} }
swipeToClose={true}
onClosed={this.onClose}
onOpened={this.onOpen}
onClosingState={this.onClosingState}>
<Text style={styles.text}>Basic modal</Text>
</Modal><Text>{item.key}</Text><Button title="Basic Modal" onPress={() => myRefs[item.key].open()} style={styles.btn}>Basic modal</Button></View>}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
});
I basically have the same question/problem as (react-native-modalbox stuck in child component context) but there was no answer to that question and he did not provide enough details with a minimum working example.
Your modal component is inside the rendered item. This causes it to be bound to the item. Although you can fix this issue by using appropriate props or some custom styling, this is not efficient. You would have 1000 modal components if you had 1000 items in your list.
You should move out your modal component and make it sibling to the FlatList. This way you would have only single modal. You can change the contents of the modal with a state value.
Sample
export default class App extends Component {
render() {
let myRefs = [];
return (
<View style={styles.container}>
<Modal
style={[styles.modal]}
ref={modalItem => { myRefs['modal'] = modalItem; }}
swipeToClose={true}
onClosed={this.onClose}
onOpened={this.onOpen}
onClosingState={this.onClosingState}>
<Text style={styles.text}>Basic modal</Text>
</Modal>
<FlatList
data={[{ key: 'a' }, { key: 'b' }]}
renderItem={({ item }) => (
<View>
<Text>{item.key}</Text>
<Button
title="Basic Modal"
onPress={() => myRefs['modal'].open()}
style={styles.btn}>
Basic modal
</Button>
</View>
)}
/>
</View>
);
}
}

How to change text Value upon Button press in React Native?

I'm an iOS developer currently working on an experimental React Native app.
I have the following code which shows a button and sample text on the screen.
import React from 'react';
import { StyleSheet, Text, View , Button } from 'react-native';
export default class App extends React.Component {
constructor() {
super();
this.state = {sampleText: 'Initial Text'};
}
changeTextValue = () => {
this.setState({sampleText: 'Changed Text'});
}
_onPressButton() {
<Text onPress = {this.changeTextValue}>
{this.state.sampleText}
</Text>
}
render() {
return (
<View style={styles.container}>
<Text onPress = {this.changeTextValue}>
{this.state.sampleText}
</Text>
<View style={styles.buttonContainer}>
<Button
onPress={this._onPressButton}
title="Change Text!"
color="#00ced1"
/>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f5deb3',
alignItems: 'center',
justifyContent: 'center',
},
buttonContainer: {}
});
The above code displays text and a button.
However when I click the button, the app crashes instead of showing the new text which is to be shown.
I'm new to React Native, kindly guide me on how to solve the error.
You could use a state to keep your default text and then on press we update the state.
import React, { Component } from 'react'
import { View, Text, Button } from 'react-native'
export default class App extends Component {
state = {
textValue: 'Change me'
}
onPress = () => {
this.setState({
textValue: 'THE NEW TEXT GOES HERE'
})
}
render() {
return (
<View style={{paddingTop: 25}}>
<Text>{this.state.textValue}</Text>
<Button title="Change Text" onPress={this.onPress} />
</View>
)
}
}
You can use state for dynamically change the text
import React, {Component} from 'react';
import {Text, Button, View} from 'react-native';
export default class App extends Component{
constructor(){
super();
this.state = {
textValue: 'Temporary text'
}
this.onPressButton= this.onPressButton.bind(this);
}
onPressButton() {
this.setState({
textValue: 'Text has been changed'
})
}
render(){
return(
<View style={{paddingTop: 20}}>
<Text style={{color: 'red',fontSize:20}}> {this.state.textValue} </Text>
<Button title= 'Change Text' onPress= {this.onPressButton}/>
</View>
);
}
}
With hooks:
import React, {useState} from "react";
import {Button, Text, View} from "react-native";
const App = () => {
const [text, setText] = useState("Initial text");
const onPressHandler = event => setText("Changed text");
return (
<View>
<Text>{text}</Text>
<Button title="Change Text" onPress={onPressHandler} />
</View>
);
};
You better make sure what _onPressButton() is doing. You can simply setState() in this function and do nothing else, which can help you solve the problem. If you want to render something new, you have to add return() and wrap up Text.
You can use this approach for updating a value on click of a button
class App extends React.Component {
constructor() {
super();
this.state = { val: 0 }
this.update = this.update.bind(this)
}
update() {
this.setState({ val: this.state.val + 1 })
}
render() {
console.log('render');
return <button onClick={this.update}>{this.state.val}</button>
}
}
It's because your onPress function is a little weird, you want to invoke an action on press, not have jsx elements. Your changeTextValue is what should be passed into your button's onPress.
Set my text in state method then update state in pressed button, then set in text like this:
<Text>
{this.state.myText}
</Text>
import React, { useState } from "react";
import { View, Text } from "react-native";
const App = () => {
const [value, setValue] = useState("Mohd Sher Khan");
const hellod = () => {
setValue("value changed");
};
return (
<View>
<Text onPress={hellod}>{value}</Text>
</View>
);
};
export default App;

Categories

Resources