How to enable ScrollView in horizontally and vertically both. But i don't want to use ListView. Please suggest how can i do that. I want to scroll whole render method View in both directions.
Here is my code. In this, all the TextView and TextInput appears in one line after ScrollView Settings. I want each view separately.
render() {
const { navigate } = this.props.navigation;
if (this.state.isLoading) {
return (
<View style={{ flex: 1, paddingTop: 20 }}>
<ActivityIndicator />
</View>
);
}
return (
<View style={styles.MainContainerViewCamp}>
<Text style={{ padding: 5, fontSize: 35, backgroundColor: '#00BCD4', marginBottom: 7 }}>Data Slabs</Text>
<ScrollView keyboardShouldPersistTaps='always' style={styles.container}
directionalLockEnabled={false}
horizontal={true}>
<View style={styles.SwitchOuterSectionStyle}>
<Text style={styles.textViewContainer}>A(1,1) </Text>
<TextInput placeholder="CPR*" value={this.state.cpr1} style={styles.TextInputStyleClass}
keyboardType='numeric'
onChangeText={cpr1 => this.setState({ cpr1 })} underlineColorAndroid='transparent' />
<TextInput placeholder="CPM*" value={this.state.cpm1} style={styles.TextInputStyleClass}
keyboardType='numeric'
onChangeText={cpm1 => this.setState({ cpm1 })} underlineColorAndroid='transparent' />
</View>
<View style={styles.SwitchOuterSectionStyle}>
<Text style={styles.textViewContainer}>B(0.75,0.75) </Text>
<TextInput placeholder="CPR*" value={this.state.cpr2} style={styles.TextInputStyleClass}
keyboardType='numeric'
onChangeText={cpr2 => this.setState({ cpr2 })} underlineColorAndroid='transparent' />
<TextInput placeholder="CPM*" value={this.state.cpm2} style={styles.TextInputStyleClass}
keyboardType='numeric'
onChangeText={cpm2 => this.setState({ cpm2 })} underlineColorAndroid='transparent' />
</View>
<View style={styles.SwitchOuterSectionStyle}>
<Text style={styles.textViewContainer}>C-Default(0.5,0.5) </Text>
<TextInput placeholder="CPR*" value={this.state.cpr3} style={styles.TextInputStyleClass}
keyboardType='numeric'
onChangeText={cpr3 => this.setState({ cpr3 })} underlineColorAndroid='transparent' />
<TextInput placeholder="CPM*" value={this.state.cpm3} style={styles.TextInputStyleClass}
editable={this.state.bud} keyboardType='numeric'
onChangeText={cpm3 => this.setState({ cpm3 })} underlineColorAndroid='transparent' />
</View>
<View style={styles.SwitchOuterSectionStyle}>
<Text style={styles.textViewContainer}>D(0.25,0.25)</Text>
<TextInput placeholder="CPR*" value={this.state.cpr4} style={styles.TextInputStyleClass}
keyboardType='numeric'
onChangeText={cpr4 => this.setState({ cpr4 })} underlineColorAndroid='transparent' />
<TextInput placeholder="CPM*" value={this.state.cpm4} style={styles.TextInputStyleClass}
editable={this.state.bud} keyboardType='numeric'
onChangeText={cpm4 => this.setState({ cpm4 })} underlineColorAndroid='transparent' />
</View>
<View style={styles.SwitchOuterSectionStyle}>
<Text style={styles.textViewContainer}>E(0,0)</Text>
<TextInput placeholder="CPR*" value={this.state.cpr5} style={styles.TextInputStyleClass}
keyboardType='numeric'
onChangeText={cpr5 => this.setState({ cpr5 })} underlineColorAndroid='transparent' />
<TextInput placeholder="CPM*" value={this.state.cpm5} style={styles.TextInputStyleClass}
editable={this.state.bud} keyboardType='numeric'
onChangeText={cpm5 => this.setState({ cpm5 })} underlineColorAndroid='transparent' />
</View>
<TouchableOpacity
style={styles.SubmitButtonStyle}
activeOpacity={.5}
onPress={this.onSaveDataSlabs} >
<Text style={styles.TextStyle}> SAVE </Text>
</TouchableOpacity>
</ScrollView>
</View>
);
}
And here is the stylesheet:-
const styles = StyleSheet.create({
MainContainerViewCamp: {
justifyContent: 'center',
paddingTop: (Platform.OS === 'ios') ? 20 : 30,
padding: 5,
},
SwitchOuterSectionStyle: {
flexDirection: 'row',
padding: 4,
justifyContent: 'center',
alignItems: 'center'
},
textViewContainer: {
padding: 7,
fontSize: 17,
width: 150,
},
TextInputStyleClass: {
textAlign: 'left',
paddingLeft: 7,
margin: 10,
width: 150,
height: 40,
borderWidth: 1,
borderColor: '#00BCD4',
},
listViewStyle: {
borderWidth: 1,
height: 360,
borderColor: '#87ceeb',
},
SubmitButtonStyle: {
marginTop: 10,
paddingTop: 15,
paddingBottom: 15,
backgroundColor: '#00BCD4',
borderRadius: 10,
borderWidth: 1,
borderColor: '#fff'
},
TextStyle: {
color: '#fff',
textAlign: 'center',
}
});
Just set both directionalLockEnabled and horizontal to make it work
<ScrollView
style={styles.container}
directionalLockEnabled={false}
horizontal={true}
>
And there is a library that you can use. It's Four-way scrolling Scroller View for react-native.
Related
I am following the below tutorial and trying to implement the react native bottom sheet in my Home Screen.
I used all his codes but still I am not able to open the bottom sheet when I click the filters button
Providing the video tutorial, GitHub link and my code below below
Its throwing an error at this line —> bs = React.createRef();
Can you let me know how to fix it
https://www.youtube.com/watch?v=mjJzaiGkaQA
https://github.com/itzpradip/Food-Finder-React-Native-App/blob/master/screens/EditProfileScreen.js
import 'react-native-gesture-handler';
import React, {useRef, useState} from 'react';
//import MapView, {PROVIDER_GOOGLE} from 'react-native-maps';
import {Marker, PROVIDER_GOOGLE} from 'react-native-maps';
import MapView from 'react-native-map-clustering';
import Autocomplete from 'react-native-autocomplete-input';
import {GooglePlacesAutocomplete} from 'react-native-google-places-autocomplete';
//import {Button} from 'react-native';
import {
Image,
LogBox,
SafeAreaView,
ScrollView,
StyleSheet,
Text,
TextInput,
TouchableOpacity,
View,
} from 'react-native';
import {NavigationContainer} from '#react-navigation/native';
import {createNativeStackNavigator} from '#react-navigation/native-stack';
import {createDrawerNavigator} from '#react-navigation/drawer';
import {Button, Menu, Provider} from 'react-native-paper';
import DropDownPicker from 'react-native-dropdown-picker';
//import { Input } from 'react-native-elements';
//import Geolocation from 'react-native-geolocation-service';
import Animated from 'react-native-reanimated';
import BottomSheet from 'reanimated-bottom-sheet';
LogBox.ignoreAllLogs();
const Drawer = createDrawerNavigator();
const Stack = createNativeStackNavigator();
const data = ['dropdown1', 'drop down 2', 'a drop down'];
const AuthStack = () => {
return (
<Drawer.Navigator>
<Stack.Screen name="HomeScreen" component={HomeScreen} />
<Stack.Screen name="HomeScreen2" component={HomeScreen2} />
{/* <Stack.Screen name="HomeScreen7" component={HomeScreen7}/>
<Stack.Screen name="HomeScreen8" component={HomeScreen8}/> */}
</Drawer.Navigator>
);
};
const App = () => {
return (
<NavigationContainer>
<Stack.Navigator
screenOptions={{
headerShown: false,
}}>
<Stack.Screen
name="Main"
component={Main}
options={{headerShown: false}}
/>
<Stack.Screen name="AuthStack">{() => <AuthStack />}</Stack.Screen>
{/* <AuthStack /> */}
{/* <Stack.Screen name="OnboardingScreen" component={OnboardingScreen} /> */}
</Stack.Navigator>
</NavigationContainer>
);
};
const Main = ({navigation}) => {
return (
<SafeAreaView
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
}}>
<View style={{}}>
<Text style={{fontSize: 30, fontWeight: 'bold', color: '#20315f'}}>
GAMEON
</Text>
</View>
<TouchableOpacity
onPress={() => navigation.navigate('AuthStack')}
style={{
backgroundColor: '#AD40AF',
padding: 20,
flexDirection: 'row',
justifyContent: 'space-between',
color: '#fff',
width: '90%',
marginBottom: 50,
}}>
<Text
style={{
color: '#fff',
fontWeight: 'bold',
}}>
Let's Begin
</Text>
</TouchableOpacity>
</SafeAreaView>
);
};
const Home = () => {
return (
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
}}>
<Text style={{fontSize: 30, fontWeight: 'bold', color: '#20315f'}}>
Home
</Text>
</View>
);
};
const HomeScreen2 = () => {
return (
<View style={styles.container}>
<MapView
// provider={PROVIDER_GOOGLE}
// remove if not using Google Maps
style={styles.map}
region={{
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.015,
longitudeDelta: 0.0121,
}}></MapView>
{/* <View style={styles.searchBox}>
<TextInput
placeholder="Search here"
placeholderTextColor="#000"
autoCapitalize="none"
style={{flex: 1, padding: 0}}
/>
</View> */}
<View style={styles.searchBox}>
<Autocomplete
//onChangeText={}
/>
</View>
</View>
);
};
const HomeScreen = ({navigation}) => {
bs = React.createRef();
fall = new Animated.Value(1);
// renderInner = () => (
// <View style={styles.panel}>
// <View style={{alignItems: 'center'}}>
// <Text style={styles.panelTitle}>Upload Photo</Text>
// <Text style={styles.panelSubtitle}>Choose Your Profile Picture</Text>
// </View>
// <TouchableOpacity style={styles.panelButton} onPress={takePhotoFromCamera}>
// <Text style={styles.panelButtonTitle}>Take Photo</Text>
// </TouchableOpacity>
// <TouchableOpacity style={styles.panelButton} onPress={choosePhotoFromLibrary}>
// <Text style={styles.panelButtonTitle}>Choose From Library</Text>
// </TouchableOpacity>
// <TouchableOpacity
// style={styles.panelButton}
// onPress={() => this.bs.current.snapTo(1)}>
// <Text style={styles.panelButtonTitle}>Cancel</Text>
// </TouchableOpacity>
// </View>
// );
// renderHeader = () => (
// <View style={styles.header}>
// <View style={styles.panelHeader}>
// <View style={styles.panelHandle} />
// </View>
// </View>
// );
return (
<SafeAreaView
style={{
flex: 1,
backgroundColor: '#fff',
}}>
<View
style={{
flex: 0.4,
zIndex: 100,
elevation: 1000,
}}>
<ScrollView
showsHorizontalScrollIndicator={false}
horizontal={true}
contentContainerStyle={{
alignItems: 'center',
flexDirection: 'row',
}}>
<View
style={{
margin: 10,
flex: 1,
zIndex: 100,
}}>
<TouchableOpacity onPress={() => this.bs.current.snapTo(0)}>
<Text>filters</Text>
</TouchableOpacity>
{/* <BottomSheet
ref={this.bs}
snapPoints={[330, 0]}
renderContent={this.renderInner}
renderHeader={this.renderHeader}
initialSnap={1}
callbackNode={this.fall}
enabledGestureInteraction={true}
/> */}
</View>
</ScrollView>
</View>
</SafeAreaView>
);
};
const INITIAL_REGION = {
latitude: 52.5,
longitude: 19.2,
latitudeDelta: 8.5,
longitudeDelta: 8.5,
};
const styles = StyleSheet.create({
container: {
// ...StyleSheet.absoluteFillObject,
// justifyContent: 'flex-end',
// alignItems: 'center',
flex: 1,
},
searchBox: {
position: 'absolute',
left: 150,
marginTop: Platform.OS === 'ios' ? 8 : 4,
// flexDirection: 'row',
backgroundColor: '#fff',
width: '60%',
alignSelf: 'center',
borderRadius: 5,
//padding: 5,
//shadowColor: '#ccc',
height: '4%',
// marginLeft: 249,
shadowOffset: {width: 0, height: 3},
//shadowOpacity: 0.5,
// shadowRadius: 5,
//elevation: 10,
},
sectionContainer: {
marginTop: 32,
paddingHorizontal: 24,
},
sectionTitle: {
fontSize: 24,
fontWeight: '600',
},
sectionDescription: {
marginTop: 8,
fontSize: 18,
fontWeight: '400',
},
highlight: {
fontWeight: '700',
},
map: {
...StyleSheet.absoluteFillObject,
},
});
export default App;
Your mistake is here.
You can't use "this" with functional components. If you use bs.current.snapTo(0), it will open the sheet.
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>
I use react-native-vector-icons.
Click the input
Keyboard goes up
When pressing the icon, icon doesn't trigger, the keyboard will go down first rather than the onpress method icon triggers while having the keyboard is on
Expected Result would like a live chat, while keyboard is up submit icon will always trigger.
I tried to enwrap it in scrollview with keyboardshouldpersisttaps and it doesn't work.
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : null}
style={{ flex: 1 }}
keyboardVerticalOffset={64}
>
<View style={styles.slide} key={i}>
<TouchableHighlight
style={styles.video}
onPress={this.handleDoubleTap}
onLongPress={this.handlePlayAndPause}
>
<ViewportAwareVideo
key={i}
source={{ uri: firstVideoUri }}
shouldPlay={this.state.shouldPlay}
isLooping
preTriggerRatio={-0.4} // default is 0
retainOnceInViewport={false} // default is false
style={styles.video}
onPlaybackStatusUpdate={this._onPlaybackStatusUpdate}
progressUpdateIntervalMillis={1000}
resizeMode='contain'
innerRef={ref => (this._videoRef = ref)}
onViewportEnter={() => {
this.setState({ shouldPlay: true });
}}
onViewportLeave={() => {
this.setState({ shouldPlay: false });
}}
/>
</TouchableHighlight>
{this.state.shouldPlay ? null : (
<TouchableHighlight
onPress={this.handlePlayAndPause}
style={styles.pauseBtn}
>
<IconComponent name='play-circle' size={50} color='black' />
</TouchableHighlight>
)}
<CopilotStep
name='swipeUp'
text='Swipe up to view next video'
order={5}
>
<WalkthroughableView style={styles.topSection}>
<Text style={styles.imageHeadingText}>{product.name}</Text>
{product.short_description === '' ? null : (
<HTML
html={product.short_description}
imagesMaxWidth={Dimensions.get('window').width}
containerStyle={styles.imageDescText}
baseFontStyle={styles.htmlStyle}
/>
)}
<CopilotStep
name='swipeRight'
text='Swipe right to view product details'
order={6}
>
<WalkthroughableView
style={{
flexDirection: 'row',
flexWrap: 'wrap',
paddingHorizontal: 20,
paddingVertical: 5
}}
>
{product.tags.map((value, index) => {
return (
<Text key={index} style={styles.tagText}>
{value.name.charAt(0) === '#'
? value.name
: '#' + value.name}
</Text>
);
})}
</WalkthroughableView>
</CopilotStep>
{product.total_sales > 0 ? (
<View
style={{
flexDirection: 'row',
flexWrap: 'wrap',
paddingHorizontal: 20,
paddingVertical: 5
}}
>
<Text style={styles.totalSales}>
{product.total_sales +
(product.total_sales > 100
? '+ bought'
: ' bought in the last 24 hours')}
</Text>
</View>
) : null}
</WalkthroughableView>
</CopilotStep>
<View style={styles.bottomSection}>
<View style={{ flex: 1, justifyContent: 'flex-end', height: 30 }}>
{this.state.messages.map((message, index) => (
<React.Fragment key={index}>
<View
key={index}
style={{
flexDirection: 'row',
alignItems: 'center',
marginHorizontal: 5,
marginVertical: 5,
paddingLeft: 10,
height: 20
}}
>
<Image
style={{ width: 20, height: 20, borderRadius: 20 / 2 }}
source={{ uri: 'https://picsum.photos/20/20' }}
/>
<Text
style={{
fontFamily: Constants.fontHeader,
marginHorizontal: 5,
color: '#007AFF'
}}
>
{message.user.name}
</Text>
<Text
style={{
fontFamily: Constants.fontHeader,
marginHorizontal: 5,
color: 'white'
}}
>
{message.text}
</Text>
</View>
</React.Fragment>
))}
</View>
<CopilotStep
name='chatOnFeed'
text='Click here to chat on video feed'
order={7}
>
<WalkthroughableTextInput
style={{
// position: 'absolute',
// bottom: 0,
// left: 0,
fontFamily: Constants.fontFamily,
marginBottom: 110,
marginHorizontal: 5,
marginVertical: 5,
paddingRight: 35,
paddingLeft: 20,
height: 35,
width: width - 60,
backgroundColor: 'white',
borderRadius: 25
}}
onChangeText={messageText => this.setState({ messageText })}
value={this.state.messageText}
placeholder='Share your thoughts'
placeholderTextColor='#9B9B9B'
/>
</CopilotStep>
<IconComponent
style={{ position: 'absolute', bottom: 115, right: 10 }}
name='arrow-right'
size={25}
color='black'
onPress={product => this.sendMessage(product)}
/>
</View>
<View style={styles.iconBar}>
<CopilotStep
name='productDetail'
text='Click here to got to product details'
order={8}
>
<WalkthroughableText>
<IconComponent
style={styles.iconBarIcon}
name='shopping-cart'
size={iconSize}
color='white'
onPress={() => {
this.props.onViewProductScreen({ product });
this.setState({ shouldPlay: false });
}}
/>
</WalkthroughableText>
</CopilotStep>
<Text style={styles.iconBarText}>Shop</Text>
<CopilotStep
name='like'
text='Click here to like this product'
order={9}
>
<WalkthroughableText>
<Entypo
style={styles.iconBarIcon}
name='heart'
size={30}
color={this.state.isInWishList ? 'red' : 'white'}
onPress={() => {
this.state.isInWishList
? this.props.removeWishListItem(product)
: this.props.addWishListItem(product);
this.setState(prevState => ({
isInWishList: !prevState.isInWishList
}));
}}
/>
</WalkthroughableText>
</CopilotStep>
<Text style={styles.iconBarText}>Like</Text>
<CopilotStep
name='share'
text='Click here to share this product'
order={10}
>
<WalkthroughableText>
<IconComponent
style={styles.iconBarIcon}
name='share'
size={iconSize}
color='white'
onPress={this.onShare}
/>
</WalkthroughableText>
</CopilotStep>
<Text style={styles.iconBarText}>Share</Text>
<CopilotStep
name='fullChat'
text='Click here to view full chat'
order={11}
>
<WalkthroughableText>
<IconComponent
style={[styles.iconBarIcon, { paddingTop: 4 }]}
name='message-circle'
size={iconSize}
color='white'
onPress={product => this.sendChat(product)}
/>
</WalkthroughableText>
</CopilotStep>
</View>
</View>
</KeyboardAvoidingView>
);
You can see my problem is on IconComponent after the WalkthroughableTextInput
If you are using NativeBase component use it like this
<Content keyboardShouldPersistTaps={'handled'}>
...
</Content>
For ReactNative <ScrollView/>
<ScrollView keyboardShouldPersistTaps={'handled'}>
...
</ScrollView>
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 have recently started using React-Native, and one of the main issues I have been struggling with is the layout design.
I have a "Card" like component that holds some information about movies. Components like Image and Text that are big goes out of the bounds of the card and does not respect the padding and margins provided.
Here is the JSX code:
<View style={[styles.container, styles.card]}>
<View style={{alignSelf: 'stretch', flexDirection: 'row', padding: 10}}>
<Image style={{height: 50, width: 50, borderRadius: 25}}
source={require('../../img/sarah-avatar.png.jpeg')}/>
<View style={{flexDirection: 'column', marginTop: 5, marginLeft: 15}}>
<Text style={styles.title}>{ this.state.movie.name }</Text>
<Text style={{color: 'gray'}}>{ moment(this.state.movie.releaseDate).format('DD/MM/YYYY') }</Text>
</View>
</View>
<View style={{alignItems: 'center'}}>
<!-- THIS IMAGE DOES NOT RESPECT THE CARD BOUNDS -->
<Image style={{height: 220, resizeMode: 'center'}}
source={require('../../img/advance-card-bttf.png')}/>
<View style={{flexWrap: 'wrap', marginTop: 10, marginBottom: 20}}>
<Text style={{color: 'gray', fontSize: 14}}>
{ this.state.movie.summary }
</Text>
</View>
</View>
<View style={{flexDirection: 'row', flex: 1}}>
<Button onPress={this.onLikeClick.bind(this)}>
<View style={{flexDirection: 'row'}}>
<Icon name="thumbs-up" size={18} color="#007aff" />
<Text style={{color: '#007aff', marginLeft: 5}}>{ this.state.movie.likes } Likes</Text>
</View>
</Button>
<View style={{width: 20}} />
<Button onPress={this.onCommentClick.bind(this)}>
<View style={{flexDirection: 'row'}}>
<Icon name="comment" size={18} color="#007aff" />
<Text style={{color: '#007aff', marginLeft: 5}}>{ this.state.movie.comments.length } Comments</Text>
</View>
</Button>
</View>
<Comments comments={this.state.movie.comments }
showComments={ this.state.showComments }
handler={this.handler} />
</View>
const styles = StyleSheet.create({
card: {
backgroundColor: "#fff",
borderRadius: 2,
shadowColor: "#000000",
shadowOpacity: 0.3,
shadowRadius: 1,
shadowOffset: {
height: 1,
width: 0.3,
},
padding: 10,
flexWrap: 'wrap'
},
container: {
flex: 1,
backgroundColor: '#F5FCFF',
margin: 5
},
title: {
fontSize: 20,
backgroundColor: 'transparent'
},
button: {
marginRight: 10
}
});
And the comments component JSX code:
<View style={{flexDirection: 'column'}}>
{
this.props.comments.map((comment, index) => {
return (
<View key={index} style={{flexDirection: 'row', marginTop: 20}}>
<Image style={{height: 50, width: 50, borderRadius: 25}}
source={require('../../img/avatar-ts-woody.png')}/>
<View style={{flexDirection: 'column', marginLeft: 15, marginTop: 3}}>
<Text style={{fontSize: 18}}>{ comment.name }</Text>
<!-- THE COMMENT CONTENT GOES OUTSIDE OF THE CARD -->
<Text style={{color: 'gray'}}>{ comment.content }</Text>
</View>
</View>
)
})
}
<TextInput placeholder="Leave a comment"
value={this.state.commentContent}
onChangeText={(text) => this.setState({commentContent : text})}
onSubmitEditing={this.onCommentEntered.bind(this)}
style={{height: 40, marginTop: 18}} />
</View>
Here you can see that the cover image seems like it's out of the card:
In here each comment might start correctly inside the card, but will go outside of the bounds when text is too long: