Related
I'm with a problem with TouchableOpacity and Negative Margins inside a FlatList. On iOS works well, but on Android, when I click at the TouchableOpacity in the front of other TochableOpacity, the TouchableOpacity from behind fires. I don't know how to solve this.
iOS Image
I clicked at "Proposta 70" but fires "Proposta 78" from behind.
Android Image
The FlatList code
<View style={styles.containerList}>
<FlatList
data={proposalsList}
keyExtractor={item => item.proposta_id}
renderItem={({ item, index }) => (
<RenderItem
item={item}
index={index}
isLoweredCard={
openedCardIndex !== null && index === openedCardIndex + 1
}
changeOpenedCardIndex={changeOpenedCardIndex}
/>
)}
refreshing={loading}
onRefresh={() => getProposalsAndNotifications()}
/>
</View>
The RenderItem code
<TouchableOpacity
style={styles.container(index, isLoweredCard)}
onPress={() => changeOpenedCardIndex(index)}
>
<>
<View
style={[
styles.lineContainer,
{ marginBottom: metrics.padding * 1.5 },
]}
>
<View
style={{
width: '50%',
}}
>
<Text style={styles.proposalId}>
{`Proposta ${item.proposta_id}`}
</Text>
<Text style={styles.proposalDate}>
{dayjs(item?.proposta_data_criacao).format('DD.MM.YYYY')}
</Text>
</View>
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'flex-end',
}}
>
<View style={styles.statusContainer}>
<Text style={{ fontSize: wp(4), fontWeight: 'bold' }}>
<TypeStatus status={item?.proposta_status} />
</Text>
</View>
</View>
</View>
<View style={styles.lineContainer}>
<Text style={styles.proposalDetailLabel}>Valor solicitado</Text>
<Text style={styles.proposalDetailValue}>
{formatCurrency(item?.proposta_valor_financiado)}
</Text>
</View>
<View style={styles.lineContainer}>
<Text style={styles.proposalDetailLabel}>Valor liberado</Text>
<Text style={styles.proposalDetailValue}>
{formatCurrency(item?.proposta_valor_financiado)}
</Text>
</View>
<View style={styles.lineContainer}>
<Text style={styles.proposalDetailLabel}>Parcelas</Text>
<Text style={styles.proposalDetailValue}>
{`${item?.proposta_valor_prazo}x`}
</Text>
</View>
<View style={styles.lineContainer}>
<Text style={styles.proposalDetailLabel}>Valor da parcela</Text>
<Text style={styles.proposalDetailValue}>
{formatCurrency(item?.proposta_valor_parcela)}
</Text>
</View>
<View style={styles.buttonContainer}>
<Button
onPress={goToDetails}
title="Ver detalhes"
titleStyle={styles.proposalButtonText}
style={styles.button}
/>
</View>
</>
</TouchableOpacity>
And the style of items
import {
widthPercentageToDP as wp,
heightPercentageToDP as hp,
} from 'react-native-responsive-screen';
import { metrics, colors } from '../../../../constants';
const styles = StyleSheet.create({
container: (index, isLoweredCard) => ({
backgroundColor: `#00${index}F${index}C`,
marginTop: !isLoweredCard && index !== 0 ? -wp(53) : metrics.padding,
marginHorizontal: metrics.padding,
alignContent: 'center',
padding: metrics.padding,
borderRadius: metrics.radius,
zIndex: -(index + 999),
}),
lineContainer: {
width: '100%',
justifyContent: 'space-between',
flexDirection: 'row',
marginBottom: metrics.padding / 2,
},
statusContainer: {
backgroundColor: colors.white,
borderRadius: 20,
width: '70%',
paddingVertical: 3,
alignItems: 'center',
justifyContent: 'center',
},
proposalId: {
color: colors.white,
fontWeight: 'bold',
fontSize: wp(4.5),
},
proposalDate: {
color: 'rgba(0, 0, 0, 0.5)',
fontWeight: 'bold',
fontSize: wp(3.5),
},
proposalDetailLabel: {
fontSize: wp(4),
color: 'rgba(0, 0, 0, 0.9)',
},
proposalDetailValue: {
fontSize: wp(4.5),
color: colors.white,
fontWeight: 'bold',
},
proposalButtonText: {
color: colors.white,
fontWeight: 'bold',
fontSize: wp(4),
},
button: {
borderRadius: metrics.radius,
backgroundColor: '#002F6C',
paddingHorizontal: metrics.padding * 3,
},
buttonContainer: {
width: '100%',
marginTop: metrics.padding,
alignItems: 'center',
},
});
export default styles;
I encountered exactly the same problem on Android. My FlatList rendered items with negative margin to superimpose them on each other. The touchable on iOS is perfect but on Android it press the lowest item behind.
Finally I solved this by replacing
import { TouchableOpacity } from 'react-native';
with
import { TouchableOpacity } from 'react-native-gesture-handler';
Using react-native 0.63.4 and react-native-gesture-handler 1.9.0 in my case.
The only solution for my case was inverting the negative margin (top / bottom).
In my case the View component was with negative marginBottom and the touchable part that I wanted was on the bottom as well, so I inverted it and put the View inside the next component and gave a negative marginTop. So the part that I wanted to be touchable worked fine.
A little strange but for me it worked out well...
import {Swipeable} from 'react-native-gesture-handler' not working in android (expo Cli). I've tried everything, ejected expo cli, edited MainActivity.java file but nothing works. There are a couple of threads but none of them works. Please help as I'm stuck with this issue for a long time. Thanks
Here is my code.
import React from 'react';
import { View, Text, StyleSheet, Keyboard,SafeAreaView, TouchableOpacity, FlatList, KeyboardAvoidingView, TextInput, Animated } from 'react-native';
import { AntDesign, Ionicons } from "#expo/vector-icons";
import { SwipeListView } from 'react-native-swipe-list-view';
import Swipeable from 'react-native-gesture-handler/Swipeable';
import { Colors } from 'react-native/Libraries/NewAppScreen';
export default class TodoModal extends React.Component {
state = {
newTodo: ""
};
toggleTodoCompleted = index => {
let list = this.props.list;
list.todos[index].completed = !list.todos[index].completed;
this.props.updateList(list);
};
addTodo = () => {
let list = this.props.list;
list.todos.push({ title: this.state.newTodo, completed: false });
this.props.updateList(list);
this.setState({ newTodo: ""});
Keyboard.dismiss();
};
renderTodo = (todo, index) => {
return (
<Swipeable renderRightActions={(_, dragX) => this.rightActions(dragX, index)}>
<View style={styles.todoContainer}>
<TouchableOpacity onPress={() => this.toggleTodoCompleted(index)}>
<Ionicons
name={todo.completed ? "ios-square" : "ios-square-outline"}
size={24}
color={"#A4A4A4"}
style={{ width: 32 }}
/>
</TouchableOpacity>
<Text
style={[
styles.todo,
{
textDecorationLine: todo.completed ? "line-through" : "none",
color: todo.completed ? "#A4A4A4" : "#2D3436"
}
]}
>
{todo.title}
</Text>
</View>
</Swipeable>
);
};
rightActions = (dragX, index) => {
return (
<TouchableOpacity>
<Animated.View style={styles.deleteButton}>
<Animated.Text>Delete</Animated.Text>
</Animated.View>
</TouchableOpacity>
);
};
render() {
const list = this.props.list;
const taskCount = list.todos.length;
const completedCount = list.todos.filter(todo => todo.completed).length;
return (
<KeyboardAvoidingView style={{flex: 1}} behavior={Platform.OS === 'ios' ? 'padding' : null}>
<SafeAreaView style={styles.container}>
<TouchableOpacity
style={{ position: "absolute", top: 64, right: 32, zIndex: 10}}
onPress={this.props.closeModal}
>
<AntDesign name="close" size={24} color="#2D3436" />
</TouchableOpacity>
<View style={[styles.section, styles.header, { borderBottomColor: list.color }]}>
<View>
<Text style={styles.title}>{list.name}</Text>
<Text style={styles.taskCount}>
{completedCount} of {taskCount} tasks
</Text>
</View>
</View>
<View style={[styles.section, { flex: 2 }]}>
<FlatList
data={list.todos}
renderItem={({ item, index }) => this.renderTodo(item, index)}
keyExtractor={(_, index) => index.toString()}
contentContainerStyle={{ paddingHorizontal: 32, paddingVertical: 64 }}
showsVerticalScrollIndicator={false}
/>
</View>
<View style={[styles.section, styles.footer]} >
<TextInput
style={[styles.input, {borderColor: list.color}]}
onChangeText={text => this.setState({ newTodo: text })}
value={this.state.newTodo}
/>
<TouchableOpacity style={[styles.addTodo, {backgroundColor: list.color}]} onPress={() => this.addTodo()}>
<AntDesign name="plus" size={16} color="#FFFFFF" />
</TouchableOpacity>
</View>
</SafeAreaView>
</KeyboardAvoidingView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center"
},
section: {
flex: 1,
alignSelf: "stretch"
},
header: {
justifyContent: 'flex-end',
marginLeft: 64,
borderBottomWidth: 3
},
title: {
fontSize: 30,
fontWeight: "800",
color: "#2D3436"
},
taskCount: {
marginTop: 4,
marginBottom: 16,
color: "#A4A4A4",
fontWeight: "600"
},
footer: {
paddingHorizontal: 32,
flexDirection: "row",
alignItems: "center"
},
input: {
flex: 1,
height: 48,
borderWidth: StyleSheet.hairlineWidth,
borderRadius: 6,
marginRight: 8,
paddingHorizontal: 8
},
addTodo: {
borderRadius: 4,
padding: 16,
alignItems: "center",
justifyContent: "center"
},
todoContainer: {
paddingVertical: 16,
flexDirection: "row",
alignItems: "center"
},
todo: {
color: "#2D3436",
fontWeight: "700",
fontSize: 16
},
deleteButton: {
flex: 1,
backgroundColor: Colors.red,
justifyContent: "center",
alignItems: "center",
width: 80
}
});
You have to wrap the swipeable in a gestureHandlerRootView
import { GestureHandlerRootView, Swipeable } from "react-native-gesture-handler";
<GestureHandlerRootView>
<Swipeable renderRightActions={(_, dragX) => this.rightActions(dragX, index)}>
<View style={styles.todoContainer}>
<TouchableOpacity onPress={() => this.toggleTodoCompleted(index)}>
<Ionicons
name={todo.completed ? "ios-square" : "ios-square-outline"}
size={24}
color={"#A4A4A4"}
style={{ width: 32 }}
/>
</TouchableOpacity>
<Text
style={[
styles.todo,
{
textDecorationLine: todo.completed ? "line-through" : "none",
color: todo.completed ? "#A4A4A4" : "#2D3436"
}
]}
>
{todo.title}
</Text>
</View>
</Swipeable>
</Swipeable>
ListView scrolling working perfect on Android but on IOS when i try to scroll down from bottom of screen it is not recognising touch and not scrolling down while scrolling from top of listView is working. Below is code snippet.
render()
{
return(
<View style={styles.MainContainerViewCamp}>
<View>
<View>
<TextInput />
</View>
<View>
<TouchableOpacity>
</TouchableOpacity>
</View>
</View>
<View style = {{ flex:1 }}>
<ScrollView horizontal={true}>
<ListView
...
renderRow {(rowData) =>
<View style={{ flex: 1, flexDirection: 'row' }}>
</View>
}
/>
</ScrollView>
</View>
</View>
);
}
const styles = StyleSheet.create({
MainContainerViewCamp:
{
justifyContent: 'center',
flex: 1,
paddingTop: (Platform.OS === 'ios') ? 20 : 20,
padding: 5,
},
});
I have applied {flex:1} to the root views and all other possible solutions like adding {flex:1} or {height} to listView/ScrollView. But nothing is working. Please help.
Edited: I am adding entire code for better understanding. One more thing to know that my datasource has more than 200 entries.
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, TextInput,Keyboard,TouchableWithoutFeedback, ActivityIndicator, Switch, ListView, Text, View,
Alert, Platform, TouchableHighlight, Image, TouchableOpacity, ScrollView} from 'react-native';
import FontAwesomeIcon from 'react-native-vector-icons/FontAwesome';
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
import EntypoIcon from 'react-native-vector-icons/Entypo';
import FoundationIcon from 'react-native-vector-icons/Foundation';
import { StackNavigator } from 'react-navigation';
//import { add_campaign } from './add_campaign';
class view_camp extends Component {
static navigationOptions = {
title: 'View Campaigns',
headerLeft : null,
};
listViewRef;
constructor(props) {
super(props);
this.state = {
isLoading: true,
text: '',
stat: '',
isPopupMenu : false,
menu_camp_id : '',
menu_status : '',
menu_camp_name : '',
enableScrollViewScroll : true,
}
this.setEnableScrollViewScroll = this.setEnableScrollViewScroll.bind(this);
this.onStartShouldSetResponderCapture = this.onStartShouldSetResponderCapture.bind(this);
this.arrayholder = [];
}
setEnableScrollViewScroll(value) {
// we need to manually handle the ScrollView scrollEnabled to allow child ListView to scroll in there parent
this.setState({ enableScrollViewScroll: value });
}
onStartShouldSetResponderCapture() {
// when there is scroll in the result list - we set the parent's ScrollView scrollEnabled to false
// so the child ListView can handle the scroll events
this.props.setEnableScrollViewScroll(false);
// if the scroll is out of the ListView we reset the parent's ScrollView scrollEnabled to true
if (this.listViewRef.scrollProperties.offset === 0 && this.state.enableScrollViewScroll === false) {
this.setEnableScrollViewScroll(true);
}
}
componentDidMount() {
const base64 = require('base-64');
return fetch('APIURL', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
"Authorization": "Basic " + base64.encode("demo:QZMW]C")
}
}).then((response) => response.json())
.then((responseJson) => {
let ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
this.setState({
isLoading: false,
dataSource: ds.cloneWithRows(responseJson),
}, function () {
this.arrayholder = responseJson;
});
})
.catch((error) => {
console.error(error);
});
}
_onSearchFilterFunction(text) {
const newData = this.arrayholder.filter(function (item) {
const itemData = item.Ad_name.toUpperCase()
const textData = text.toUpperCase()
return itemData.indexOf(textData) > -1
})
this.setState({
dataSource: this.state.dataSource.cloneWithRows(newData),
text: text
})
}
_onPressButton = () => {
this.props.navigation.navigate('Third', { ClientId: this.props.navigation.state.params.ClientId });
}
ListViewItemSeparator = () => {
return (
<View
style={{
height: .5,
width: "100%",
backgroundColor: "#000",
}}
/>
);
}
RenderListViewHeader = () => {
var header = (
<View style={{ flex: 1, flexDirection: 'row' }} >
<ScrollView horizontal={true}>
<Text style={styles.stickyTextViewContainer} >Ad Name</Text>
<Text style={styles.stickyTextViewContainer} >Ad Type</Text>
<Text style={styles.stickyTextViewContainer} >CPR</Text>
<Text style={styles.stickyTextViewContainer} >CPM</Text>
<Text style={styles.stickyTextViewContainer} >Budget</Text>
<Text style={styles.stickyTextViewContainer} >Daily Budget</Text>
<Text style={styles.stickyTextViewContainer} >Total Budget Spent</Text>
<Text style={styles.stickyTextViewContainer} >Imps</Text>
<Text style={styles.stickyTextViewContainer} >Recalls</Text>
<Text style={styles.stickyTextViewContainer} >Correct Recalls</Text>
<Text style={styles.stickyTextViewContainer} >Clicks</Text>
<Text style={styles.stickyTextViewContainer} >Start Date</Text>
<Text style={styles.stickyTextViewContainer} >End Date</Text>
<Text style={styles.stickyTextViewContainer} >Status</Text>
{/* <Text style={styles.stickyActionTextViewContainer} >Action</Text> */}
</ScrollView>
</View>
);
return header;
};
getMenuParams = (camp_id,status,camp_name) =>
{
//console.log("camp_id: "+camp_id +" status: "+status+" camp_name: "+camp_name);
this.setState({
isPopupMenu : true,
menu_camp_id : camp_id,
menu_status : status,
menu_camp_name : camp_name
});
//console.log("ispopupmenu: "+this.state.isPopupMenu+" menu_camp_id: "+this.state.menu_camp_id +" menu_status: "+this.state.menu_status+" menu_camp_name: "+this.state.menu_camp_name);
}
toggleCancel = () =>
{
this.setState({
isPopupMenu:false,
});
}
setMenuRef = ref => {
this._menu = ref;
this.showMenu();
};
hideMenu = () => {
this._menu.hide();
};
showMenu = () => { //console.log("start");
this._menu.show();
//console.log("end");
};
render() {
const { navigate } = this.props.navigation;
//const screenHeight = Dimensions.get('window').height;
if (this.state.isLoading) {
return (
<View style={{ flex: 1, paddingTop: 20 }}>
<ActivityIndicator />
</View>
);
}
return (
<View style={styles.MainContainerViewCamp}
// when scrolling the parent scroll view we reset the enableScroll to true
onStartShouldSetResponderCapture={() =>{this.setEnableScrollViewScroll(true);}}
>
<Text style={{ padding: 5, fontSize: 35, backgroundColor: '#00BCD4' }}>All Campaigns</Text>
<View style={styles.OuterSectionStyle}>
<View style={styles.SectionStyle}>
<FontAwesomeIcon name='search' style={styles.icon} />
<TextInput
onChangeText={(text) => this._onSearchFilterFunction(text)}
value={this.state.text}
style={{ flex: 1 }}
placeholder="Search Here"
underlineColorAndroid="transparent"
/>
</View>
<TouchableOpacity
style={styles.SubmitButtonStyle}
activeOpacity={.5}
onPress={this._onPressButton}>
<MaterialIcon name='add-box' style={styles.icon} />
</TouchableOpacity>
</View>
<ScrollView horizontal={true}
// enable ScrollView scroll according to state's value
scrollEnabled = {this.state.enableScrollViewScroll}
>
<ListView
onRef={(ref) => this.listViewRef = ref}
onStartShouldSetResponderCapture={this.onStartShouldSetResponderCapture}
enableEmptySections={true}
dataSource={this.state.dataSource}
stickyHeaderIndices={[0]}
renderHeader={this.RenderListViewHeader}
renderSeparator={this.ListViewItemSeparator}
renderRow={(rowData) =>
<View style={{ flex: 1, flexDirection: 'row'}}>
<TouchableOpacity
//style={styles.showMenuContainer}
activeOpacity={.5}
onPress={this.getMenuParams.bind(this,rowData.campaign_id,rowData.Status,rowData.Ad_name)}
>
<Text style={styles.textViewContainer}> {rowData.Ad_name} </Text>
</TouchableOpacity>
{/* <Text style={styles.textViewContainer} >{rowData.Ad_name}</Text> */}
<TouchableOpacity
//style={styles.showMenuContainer}
activeOpacity={.5}
onPress={this.getMenuParams.bind(this,rowData.campaign_id,rowData.Status,rowData.Ad_name)}
>
<Text style={styles.textViewContainer} >{rowData.Ad_type}</Text>
</TouchableOpacity>
<TouchableOpacity
//style={styles.showMenuContainer}
activeOpacity={.5}
onPress={this.getMenuParams.bind(this,rowData.campaign_id,rowData.Status,rowData.Ad_name)}
>
<Text style={styles.textViewContainer} >{rowData.CPR}</Text>
</TouchableOpacity>
<TouchableOpacity
//style={styles.showMenuContainer}
activeOpacity={.5}
onPress={this.getMenuParams.bind(this,rowData.campaign_id,rowData.Status,rowData.Ad_name)}
>
<Text style={styles.textViewContainer} >{rowData.CPM}</Text>
</TouchableOpacity>
<TouchableOpacity
//style={styles.showMenuContainer}
activeOpacity={.5}
onPress={this.getMenuParams.bind(this,rowData.campaign_id,rowData.Status,rowData.Ad_name)}
>
<Text style={styles.textViewContainer} >{rowData.Budget}</Text>
</TouchableOpacity>
<TouchableOpacity
//style={styles.showMenuContainer}
activeOpacity={.5}
onPress={this.getMenuParams.bind(this,rowData.campaign_id,rowData.Status,rowData.Ad_name)}
>
<Text style={styles.textViewContainer} >{rowData.Daily_budget}</Text>
</TouchableOpacity>
<TouchableOpacity
//style={styles.showMenuContainer}
activeOpacity={.5}
onPress={this.getMenuParams.bind(this,rowData.campaign_id,rowData.Status,rowData.Ad_name)}
>
<Text style={styles.textViewContainer} >{rowData.Total_budget_spent}</Text>
</TouchableOpacity>
<TouchableOpacity
//style={styles.showMenuContainer}
activeOpacity={.5}
onPress={this.getMenuParams.bind(this,rowData.campaign_id,rowData.Status,rowData.Ad_name)}
>
<Text style={styles.textViewContainer} >{rowData.Imps}</Text>
</TouchableOpacity>
<TouchableOpacity
//style={styles.showMenuContainer}
activeOpacity={.5}
onPress={this.getMenuParams.bind(this,rowData.campaign_id,rowData.Status,rowData.Ad_name)}
>
<Text style={styles.textViewContainer} >{rowData.Recalls}</Text>
</TouchableOpacity>
<TouchableOpacity
//style={styles.showMenuContainer}
activeOpacity={.5}
onPress={this.getMenuParams.bind(this,rowData.campaign_id,rowData.Status,rowData.Ad_name)}
>
<Text style={styles.textViewContainer} >{rowData.Correct_recalls}</Text>
</TouchableOpacity>
<TouchableOpacity
//style={styles.showMenuContainer}
activeOpacity={.5}
onPress={this.getMenuParams.bind(this,rowData.campaign_id,rowData.Status,rowData.Ad_name)}
>
<Text style={styles.textViewContainer} >{rowData.Clicks}</Text>
</TouchableOpacity>
<TouchableOpacity
//style={styles.showMenuContainer}
activeOpacity={.5}
onPress={this.getMenuParams.bind(this,rowData.campaign_id,rowData.Status,rowData.Ad_name)}
>
<Text style={styles.textViewContainer} >{rowData.Start_date}</Text>
</TouchableOpacity>
<TouchableOpacity
//style={styles.showMenuContainer}
activeOpacity={.5}
onPress={this.getMenuParams.bind(this,rowData.campaign_id,rowData.Status,rowData.Ad_name)}
>
<Text style={styles.textViewContainer} >{rowData.End_date}</Text>
</TouchableOpacity>
{rowData.Status == '0' ?
<View style={styles.SwitchOuterSectionStyle}>
<Text style={styles.textWithSwitch}>
Inactive </Text>
<Switch
onValueChange={this.onStatusButtonPressed.bind(this, rowData.Status, rowData.campaign_id)}
value={false} />
</View>
:
<View style={styles.SwitchOuterSectionStyle}>
<Text style={styles.textWithSwitch}>
Active </Text>
<Switch
onValueChange={this.onStatusButtonPressed.bind(this, rowData.Status, rowData.campaign_id)}
value={true} />
</View>}
</View>
}
/>
</ScrollView>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
MainContainerViewCamp: {
// Setting up View inside content in Vertically center.
justifyContent: 'center',
flex: 1,
paddingTop: (Platform.OS === 'ios') ? 20 : 20,
padding: 5,
},
textViewContainer: {
textAlignVertical: 'center',
padding: 7,
borderWidth: 1,
borderColor: '#87ceeb',
fontSize: 13,
width: 150,
},
stickyTextViewContainer: {
textAlignVertical: 'center',
fontSize: 17,
fontWeight: 'bold',
padding: 7,
height: 45,
backgroundColor: '#00BFFF',
borderWidth: 1,
borderColor: '#87ceeb',
fontSize: 13,
width: 150,
marginBottom: 3,
},
stickyActionTextViewContainer: {
textAlignVertical: 'center',
textAlign: 'center',
fontSize: 17,
fontWeight: 'bold',
padding: 7,
justifyContent: 'center',
alignItems: 'center',
height: 45,
backgroundColor: '#00BFFF',
borderWidth: 1,
borderColor: '#87ceeb',
fontSize: 13,
width: 550,
},
textWithSwitch: {
fontSize: 13,
},
imageClass: {
height: 40,
width: 40,
marginLeft: 25,
borderRadius: 7,
},
SubmitButtonStyle: {
marginTop: 10,
marginLeft: 10,
marginBottom: 5,
backgroundColor: '#D6EAF8',
borderRadius: 10,
borderWidth: 1,
borderColor: '#fff'
},
TextStyle: {
color: '#fff',
textAlign: 'center',
},
icon: {
fontSize: 30,
padding: 5
},
TextInputStyleClass: {
textAlign: 'center',
height: 40,
borderWidth: 1,
borderColor: '#009688',
borderRadius: 7,
backgroundColor: "#FFFFFF"
},
OuterSectionStyle: {
flexWrap: 'wrap',
alignItems: 'flex-start',
flexDirection: 'row',
margin: 10,
height: 50,
},
SwitchOuterSectionStyle: {
flexWrap: 'wrap',
padding: 7,
alignItems: 'center',
flexDirection: 'row',
justifyContent: 'center',
width: 150,
borderWidth: 1,
borderColor: '#87ceeb',
},
IconOuterSectionStyle: {
flexWrap: 'wrap',
padding: 7,
alignItems: 'flex-start',
flexDirection: 'row',
justifyContent: 'center',
width: 550,
borderWidth: 1,
borderColor: '#87ceeb',
},
SectionStyle: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
borderWidth: .5,
borderColor: '#000',
height: 40,
width: 220,
borderRadius: 5,
margin: 10
},
});
module.exports = view_camp;
The ListView is not scrolling probably according to this React Native issue.
The following works very well on IOS and Android both, scrolls the ListView if the touch is on List and else it scrolls the ScrollView.
Try change your code as following:
class MainContainerViewCamp extends React.Component {
listViewRef; // hold list view reference
constructor() {
this.state={ enableScrollViewScroll: true};
this.setEnableScrollViewScroll = this.setEnableScrollViewScroll.bind(this);
this.onStartShouldSetResponderCapture = this.onStartShouldSetResponderCapture.bind(this);
}
setEnableScrollViewScroll(value) {
// we need to manually handle the ScrollView scrollEnabled to allow child ListView to scroll in there parent
this.setState({ enableScrollViewScroll: value });
}
onStartShouldSetResponderCapture() {
// when there is scroll in the result list - we set the parent's ScrollView scrollEnabled to false
// so the child ListView can handle the scroll events
this.props.setEnableScrollViewScroll(false);
// if the scroll is out of the ListView we reset the parent's ScrollView scrollEnabled to true
if (this.listViewRef.scrollProperties.offset === 0 && this.state.enableScrollViewScroll === false) {
this.setEnableScrollViewScroll(true);
}
}
render() {
...
<View style = {{ flex:1 }}
// when scrolling the parent scroll view we reset the enableScroll to true
onStartShouldSetResponderCapture={() =>{this.setEnableScrollViewScroll(true);}>
<ScrollView
horizontal={true}
// enable ScrollView scroll according to state's value
scrollEnabled={this.state.enableScrollViewScroll}
>
<ListView
...
onRef={(ref) => this.listViewRef = ref}
onStartShouldSetResponderCapture={this.onStartShouldSetResponderCapture}
renderRow {(rowData) =>
<View style={{ flex: 1, flexDirection: 'row' }}>
</View>
}
/>
</ScrollView>
</View>
...
}
}
I am currently working with React Native and the new React Navigation. but there is an error: Currently having an error in one screen.
Navigation is as follows
MainScreen->Login takes to Splash Screen
Splash -> click on a button takes to Home Screen
HomeScreen->Logout Should take to Main Screen
MainScreen to Home is working fine But Home Screen to Main is not working.
Below is the error coming
' Main' should declare a screen
//Code for the Main screen
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
TextInput,
TouchableOpacity,
Image,
Alert
} from 'react-native';
import Splash from './Splash';
import Signin from './signin';
import Forget from './forget';
import { StackNavigator } from 'react-navigation';
class Main extends Component {
constructor(props) {
super(props)
this.state = {
txt_input_email: '',
txt_input_password: '',
};
}
//=======navigation optionpane========//
static navigationOptions = {
title: 'Welcome',
header: null
};
//====================================//
//==========================function to validate user information=========================================//
mvalidate(){
const { navigate } = this.props.navigation;
if (this.state.txt_input_email==""){
Alert.alert("Please enter email");
return;
}
if(this.state.txt_input_password==""){
Alert.alert("Please enter Password");
return;
}
if(!this.validateEmail(this.state.txt_input_email ||
!this.vlidatePassword(this.state.txt_input_password))){
Alert.alert("Email/Password is invalid/Wrong");
}else{
if(this.state.txt_input_email=="abc#gmail.com" && this.state.txt_input_password=="abc123"){
navigate('SplashPage')
}else{
Alert.alert('Wrong username/password');
}
}
}
validateEmail(email) {
if(/^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/){
return true;
}else{
return false;
}
}
vlidatePassword(password){
if(/^[a-zA-Z0-9]{4,100}$/){
return true;
}else{
false;
}
}
//=========================================================================================================//
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
<Image source={require('../images/logo.jpg')} style={styles.image}></Image>
<Text style={styles.text}> Sign In</Text>
<View style={styles.set}>
<View style={styles.imageset}>
<Image source={require('../images/facebook-logo.png')} style={styles.facebook}></Image>
<Image source={require('../images/google-plus.png')} style={styles.google}></Image>
</View>
<View style={[styles.inputWrap, styles.set]}>
<TextInput
placeholder="Email/Employee Id"
style={styles.input}
underlineColorAndroid="transparent"
onChangeText={value => this.setState({txt_input_email: value.trim()})}
/>
</View>
<View style={styles.inputWrap}>
<TextInput
placeholder="Password"
secureTextEntry
style={styles.input}
underlineColorAndroid="transparent"
onChangeText={value => this.setState({txt_input_password: value.trim()})}
/>
</View>
<View style={styles.imageset}>
<TouchableOpacity activeOpacity={.5} onPress={() => navigate('ForgetPage')}>
<View>
<Text style={styles.forget}>Forget Password ?</Text>
</View>
</TouchableOpacity>
<TouchableOpacity activeOpacity={.5} onPress={()=>this.mvalidate()} >
<View style={styles.button}>
<Text style={styles.buttonText}> SIGN IN</Text>
</View>
</TouchableOpacity>
</View>
<View style={styles.imageset}>
<Text style={styles.user}>New User ? </Text>
<TouchableOpacity activeOpacity={.5} onPress={() => navigate('SigninPage')} >
<View>
<Text style={styles.signup}>Sign Up</Text>
</View>
</TouchableOpacity>
</View>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#000000'
},
inputWrap: {
flexDirection: "row",
marginVertical: 10,
height: 40,
width: 300,
marginHorizontal: 20,
backgroundColor: "#FF0000"
},
text: {
color: "#FFF",
fontSize: 25
},
input: {
flex: 1,
paddingHorizontal: 15,
backgroundColor: '#fff'
},
button: {
backgroundColor: "#FF8C00",
paddingVertical: 15,
marginVertical: 15,
marginLeft: 45,
width: 100,
height: 35,
alignItems: "center",
justifyContent: "center"
},
buttonText: {
color: '#FFF',
fontSize: 15
},
forget: {
color: "#11D923",
backgroundColor: "transparent",
fontSize: 18,
marginHorizontal: 15,
marginTop: 20,
},
signup: {
color: "#11D923",
backgroundColor: "transparent",
fontSize: 18,
marginLeft: 25,
marginTop: 15
},
image: {
width: 250,
height: 110
},
set: {
marginTop: 20
},
imageset: {
flexDirection: "row"
},
facebook: {
marginLeft: 85,
width: 65,
height: 65
},
google: {
marginLeft: 20,
width: 65,
height: 65
},
user: {
fontSize: 18,
color: "#FFF",
marginLeft: 25,
marginTop: 17
}
});
const FirstProject = StackNavigator({
MainPage: { screen: Main },
SplashPage: { screen: Splash },
SigninPage: { screen: Signin },
ForgetPage: { screen: Forget },
});
export default FirstProject;
//Code or the Splash Screen
import React, { Component } from 'react';
import { AppRegistry, View, Text, Image, StyleSheet, TouchableHighlight } from 'react-native';
import { StackNavigator } from 'react-navigation';
import Home from './Home';
class Splash extends Component {
//=======navigation optionpane========//
static navigationOptions = {
title: 'Welcome',
header: null
};
//====================================//
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.contain}>
<Image source={require('../images/splash.jpg')} style={{
height: 435, width: 300,
marginHorizontal: 30, marginTop: 52
}}>
<TouchableHighlight onPress={() => navigate('HomePage')} >
<Image source={require('../images/cancel.png')} style={styles.container}>
</Image></TouchableHighlight>
<Image source={require('../images/facebook-logo.png')} style={styles.facebook}></Image>
</Image>
<View style={styles.dir}>
<TouchableHighlight >
<Image source={require('../images/heart.png')} style={styles.welcome}></Image>
</TouchableHighlight>
<Image source={require('../images/whatsapp.png')} style={styles.whatsap}></Image>
<Image source={require('../images/sharing-big-symbol.png')} style={styles.instructions}></Image>
</View>
<Image source={require('../images/google-plus.png')} style={styles.google}></Image>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
height: 30,
width: 30,
marginHorizontal: 270
},
contain: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#000000'
},
welcome: {
height: 35,
width: 35,
marginHorizontal: 40,
marginVertical: 5
},
instructions: {
height: 45,
width: 45,
marginHorizontal: 14,
marginVertical: 5
},
whatsap: {
height: 35,
width: 35,
marginLeft: 135,
marginVertical: 9
},
facebook: {
height: 35,
width: 35,
marginLeft: 247,
marginVertical: 368
},
google: {
height: 35,
width: 35,
marginLeft: 235
},
dir: {
flexDirection: 'row'
}
});
const SplashPage = StackNavigator({
SplashPage: { screen: Splash },
HomePage: { screen: Home}
});
export default SplashPage;
// Code for the Home Page
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View, Image,
TouchableHighlight,
DrawerLayoutAndroid,
TouchableOpacity
} from 'react-native';
import { StackNavigator } from 'react-navigation';
import Main from './Main';
import About from './meditationpages/about';
class Home extends Component {
openDrawer() {
this.refs['DRAWER'].openDrawer()
}
//=======navigation optionpane========//
static navigationOptions = {
title: 'Welcome',
header: null
};
//====================================//
render() {
navigationView = (
<View style={{ flex: 1, backgroundColor: '#B0E0E6', }}>
<Text style={{ margin: 10, fontSize: 15, textAlign: 'left' }}>Home</Text>
<Text style={{ margin: 10, fontSize: 15, textAlign: 'left' }}>Meditation</Text>
<Text style={{ margin: 10, fontSize: 15, textAlign: 'left' }}>Art & Wellness</Text>
<Text style={{ margin: 10, fontSize: 15, textAlign: 'left' }}>One - on - One counselling</Text>
<Text style={{ margin: 10, fontSize: 15, textAlign: 'left' }}>Health Moments</Text>
<Text style={{ margin: 10, fontSize: 15, textAlign: 'left' }}>Blogs</Text>
<Text style={{ margin: 10, fontSize: 15, textAlign: 'left' }}>Live Sessions</Text>
<Text style={{ margin: 10, fontSize: 15, textAlign: 'left' }}>Forums</Text>
<Text style={{ margin: 10, fontSize: 15, textAlign: 'left' }}>Masters</Text>
<Text style={{ margin: 10, fontSize: 15, textAlign: 'left' }}>Global Events & Retreats</Text>
<Text style={{ margin: 10, fontSize: 15, textAlign: 'left' }}>Interview/Audio/Video</Text>
<Text style={{ margin: 10, fontSize: 15, textAlign: 'left' }}>Online Learning</Text>
<Text style={{ margin: 10, fontSize: 15, textAlign: 'left' }}>e-store</Text>
</View>
);
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
<DrawerLayoutAndroid
drawerWidth={250}
ref={'DRAWER'}
drawerPosition={DrawerLayoutAndroid.positions.Left}
renderNavigationView={() => navigationView}>
<View style={styles.welcome}>
<TouchableHighlight onPress={() => this.openDrawer()}>
<Image source={require('../images/menu.png')} style={styles.imagess}></Image>
</TouchableHighlight>
<Image source={require('../images/home.png')} style={[styles.imagess, styles.menu_diff]}></Image>
<TouchableHighlight onPress={() => navigate('AboutPage')} >
<Image source={require('../images/meditation.png')} style={[styles.imagess, styles.icon_diff]}></Image></TouchableHighlight>
<Image source={require('../images/art.png')} style={[styles.imagess, styles.icon_diff]}></Image>
</View>
<TouchableHighlight onPress={() => navigate('MainPage')} style={styles.set}>
<View style={styles.button}>
<Text style={styles.buttonText} > Logout</Text>
</View>
</TouchableHighlight>
</DrawerLayoutAndroid>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#4682B4',
},
welcome: {
flexDirection: 'row',
marginTop: 10,
backgroundColor: '#4682B4'
},
imagess: {
marginLeft: 10,
height: 35,
width: 35
},
menu_diff: {
marginLeft: 177
},
icon_diff: {
marginLeft: 15
},
buttonText: {
color: '#FFF',
fontSize: 20
},
button: {
backgroundColor: "#FF8C00",
paddingVertical: 15,
marginVertical: 15,
marginHorizontal: 120,
width: 100,
height: 40,
alignItems: "center",
justifyContent: "center"
},
set: {
marginTop: 250,
justifyContent: 'center',
alignItems: 'center',
},
});
const HomePages = StackNavigator({
HomePage: { screen: Home },
AboutPage: { screen: About },
MainPage:{ screen: Main},
});
export default HomePages
I have solved this issue. I commented one line
const HomePages = StackNavigator({
HomePage: { screen: Home },
AboutPage: { screen: About },
// MainPage:{ screen: Main}, //Commenting this line solved the issue
});
Maybe main page reference was already created that's why it was creating the problem.
I am trying to customize TouchableOpacity with below style
<TouchableOpacity
onPress={() => {
navigate("EnableNotification");
}}
>
<View
style={{
backgroundColor: "#FE434C",
alignItems: "center",
justifyContent: "center",
borderRadius: 10,
width: 240,
marginTop: 30,
height: 40
}}
>
<Text style={{ color: "white" }}>CONTINUE</Text>
</View>
</TouchableOpacity>
I have this TouchableOpacity in each component. I want something like customize this view in one js file & reuse this. Wherever I want to use this simply implement onPress and Text. How can I achieve this ?
Here's a snippet of one of the buttons I have created. The textStyle & buttonStyle are both in this component excluded, but if you wanted them to be variable you would pass it through RoundButton = ({ textStyle, buttonStyle })
const RoundButton = ({ onPress, children }) => {
return (
<TouchableOpacity onPress={onPress} style={buttonStyle}>
<Text style={textStyle}>{children}</Text>
</TouchableOpacity>
);
};
And here's a use case:
<RoundButton onPress={this.onSubmit.bind(this)>Confirm</RoundButton>
So, you could go:
const Button = ({ onPress, buttonText }) => {
const { buttonStyle, textStyle } = styles;
return (
<TouchableOpacity onPress={onPress} style={styles.button}>
<Text style={{ color: '#fff' }}>{buttonText}</Text>
</TouchableOpacity>
);
};
const styles = {
backgroundColor: '#FE434C',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 10,
width: 240,
marginTop: 30,
height: 40,
}
then import { Button } from '../somepath/Button.js;
Where it will be a useable custom JSX element.
return (
...
<Button onPress={() => navigate('EnableNotification'}>CONTINUE</Button>
...
)
EDIT: Update for passing styling:
const Button = ({ onPress, buttonText, buttonStyle, textStyle }) => {
return (
<TouchableOpacity onPress={onPress} style={buttonStyle}>
<Text style={textStyle}>{buttonText}</Text>
</TouchableOpacity>
);
};
Your use case would be:
import { Button } from '../somepath/Button.js';
class MyPage extends Component {
render() {
return (
...
<Button buttonStyle={styles.yourStyle} textStyle={styles.yourStyle2} onPress={() => navigate('EnableNotification')>CONTINUE</Button>
...
)
}
}
const styles = {
yourStyle: {
...
}
yourStyle2: {
...
}
}