Currently, I'm developing React Native app for TV platform and I'm able to play video on TV.
I added react-native-drawer in Video Player component and able to open/close drawer but not able to change focus inside the drawer.
Here is the drawer code:
render() {
return (
<Container hasTVPreferredFocus={true}>
<Content
bounces={false}
style={{ flex: 1, backgroundColor: '#fff', top: -1 }}
>
<View style={styles.container}>
<TouchableHighlight onPress={() => {this.setState({ selected: 'play' });}}>
<View style={{ backgroundColor: this.state.selected === 'play'? '#fbd2c1' : '#FFFFFF' , padding: 10, borderRadius: 5 }}>
<Image style={styles.image} source={require('./images/play.png')} />
</View>
</TouchableHighlight>
<TouchableOpacity onPress={() => {this.setState({ selected: 'time' });}}>
<View style={{ backgroundColor: this.state.selected === 'time'? '#fbd2c1' : '#FFFFFF' , padding: 10, borderRadius: 5 }}>
<Image style={styles.image} source={require('./images/clock.png')} />
</View>
</TouchableOpacity>
<TouchableOpacity onPress={() => {this.setState({ selected: 'user' });}}>
<View style={{ backgroundColor: this.state.selected === 'user'? '#fbd2c1' : '#FFFFFF' , padding: 10, borderRadius: 5 }}>
<Image style={styles.image} source={require('./images/user.png')} />
</View>
</TouchableOpacity>
<TouchableOpacity onPress={() => {this.setState({ selected: 'resolution' });}}>
<View style={{ backgroundColor: this.state.selected === 'resolution' ? '#fbd2c1' : '#FFFFFF' , padding: 10, borderRadius: 5 }}>
<Image style={styles.image} source={require('./images/computer.png')} />
</View>
</TouchableOpacity>
</View>
{ this.renderUI() }
</Content>
</Container>
);
}
Thanks.
To solve that i would suggest you to force the focus and see if it works like that. If it works the problem is in how you use your TouchableHighlight.
I would think of forcing the focus change like so:
hasTVPreferredFocus={true}
onPress={() => {}}
(You have to insert this in the element tag TouchableHighlight )
Related
I want to press on a flat item and then open a new screen which has details from the item but how is the best way to do that?
should I make a modal and give it the details?
or should I make a new screen for every item?
const renderRecipe = ({ item }) => {
return (
<View style={styles.item}>
<Image style={styles.image} source={{ uri: item.image }}>
</Image>
<Text style={{
color: '#00aecc', fontSize: 18,
marginTop: 15
}}>{item.label}</Text>
<View style={{ alignItems: "center" }}>
<Text style={{ color: '#fff', marginTop: 100, fontSize: 20 }}>Zutaten:</Text>
<Text style={{ color: '#00aecc', fontSize: 18, marginTop: 15 }}>{item.id}</Text>
</View>
</View >
)
}
return (
<View style={styles.container}>
{isLoading && <View style={{ height: "100%", width: "100%" }}><ActivityIndicator style={styles.loading} color='#00aecc' size="large" /></View>}
<FlatList
data={userRecipes}
renderItem={renderRecipe}
keyExtractor={(item) => item.id}>
</FlatList>
</View >
);
This is my item now how can I do what I want.
I will try to explain. You have two screens Home and Details.
Assume in your Home screen your Flatlist. So when you click to item on Flatlist you will navigate to Details screen with items details.That's it!
You can also do this with modal. But here it depends on requirement. There is not any perfect solution. Based on case scenario you do it.
In your case I will do followings.
First I will import TouchableOpactiy and useNavigation.
import {TouchableOpactiy} from 'react-native'
import { useNavigation } from '#react-navigation/native';
Then I will use it to my flatlist items.
Home Screen
const Home = () => {
const navigation = useNavigation();
const renderRecipe = ({ item }) => {
return (
<TouchableOpactiy onPress={()=> navigation.navigate('Details', {item} )}>
<View style={styles.item}>
<Image style={styles.image} source={{ uri: item.image }}>
</Image>
<Text style={{
color: '#00aecc', fontSize: 18,
marginTop: 15}}>{item.label}</Text>
<View style={{ alignItems: "center" }}>
<Text style={{ color: '#fff', marginTop: 100, fontSize: 20 }}>Zutaten:
</Text>
<Text style={{ color: '#00aecc', fontSize: 18, marginTop: 15 }}>{item.id}
</Text>
</View>
</View >
</TouchableOpactiy>
)
}
return (
/*your flalist*/
)
}
Details Screen
const Details = ({ route, navigation ) => {
const { item } = route.params;
return (
<Text>{item.label}</Text>
)
}
so basically, am trying to achieve something like so, such that when +100 is pressed, the color of say, Upload ID Card changes to really show that that field is completed.
<View
style={{ justifyContent: "flex-start", marginTop: 25 }}
>
<Text
style={ styles.scoreTitle }
>
{item.key}
</Text>
</View>
<View style={styles.perScoreRightContentView}>
<Text
style={styles.scorePlus100}
onPress={() => // change style of the the text child above}
>
+ 100
</Text>
<MaterialIcons name="keyboard-arrow-right" size={24} />
</View>
</View>
So, this is what I have tried out but with no success;
...
const [isSelected, setIsSelected] = React.useState(false);
...
<Text
style={[
isSelected
? { ...styles.scoreTitle, color: "#C6C6C6" }
: styles.scoreTitle
]}
>
{item.key}
</Text>
</View>
<TouchableOpacity
style={styles.perScoreRightContentView}
onPress={() => setIsSelected(!isSelected)}
>
<Text style={styles.scorePlus100}>+ 100</Text>
<MaterialIcons name="keyboard-arrow-right" size={24} />
</TouchableOpacity>
...
const styles = StyleSheet.create({
scoreTitle: {
color: style.color.blackText,
fontSize: 13,
fontFamily: style.fontFamily.medium
}
});
Now I understand, you can put a ref on the text element and access to syle of that text element from the press function.
some thing like that :
<View style={{ justifyContent: "flex-start", marginTop: 25 }}>
<Text style={ styles.scoreTitle } ref='colorText'>
{item.key}
</Text>
</View>
<View style={styles.perScoreRightContentView}>
<Text style={styles.scorePlus100} onPress={() => changeStyle()}>
+ 100
</Text>
<MaterialIcons name="keyboard-arrow-right" size={24} />
</View>
const changeStyle = () => {
const myReference = this.colorText.current // The DOM element
myReference.style.color = "yellow";
}
don't forget to useRef to declar the ref.
I actually found a solution, thanks rovas
So basically what had to be done was to split components such that they manage different state, that is to say,
const Score = ({ title }: { title: string }) => {
const [scoreSelected, setScoreSelected] = React.useState(false);
return (
<View style={styles.perSectionScore}>
<View style={{ justifyContent: "flex-start", marginTop: 25 }}>
<Text
style={[
scoreSelected
? { ...styles.scoreTitle, color: "#C6C6C6" }
: styles.scoreTitle
]}
>
{title}
</Text>
</View>
<View
style={styles.perScoreRightContentView}
>
<Text
style={styles.scorePlus100}
onPress={() => {
setScoreSelected(!scoreSelected);
}}
>
+ 100
</Text>
<MaterialIcons name="keyboard-arrow-right" size={24} />
</View>
</View>
);
};
and then use in a to-be rendered component, i.e
<View style={styles.scoresContainer}>
<FlatList
data={scoreTitles}
renderItem={({ item }) => {
const index = scoreTitles.indexOf(item);
return (
<>
{
<View
key={index}
style={{
padding: 10
}}
>
<Score title={item.key}/>
<View style={{ flex: 0.5 }}>
<Input
disabled={true}
inputContainerStyle={{ borderBottomColor: "#EAEAEA" }}
/>
</View>
</View>
}
</>
);
}}
/>
</View>
</View>
);
...
I am new to react naive and am trying to place two views one under the other but when I try doing this there is a big gap between the views as shown below.
This anyway to be able to fix this or do I need to use flatlist?
Here is my code.
render() {
return (
<>
<View style={{ flex: 1, flexDirection: "row", height: 130 }}>
<View style={styles.IconImage}>
<TouchableOpacity
onPress={() =>
Linking.openURL("http://facebook.com/")
}
>
<FontAwesome
name="location-arrow"
size={40}
color={"#E8AA65"}
/>
</TouchableOpacity>
</View>
<View style={{ paddingTop: 50, paddingLeft: 40 }}>
<Text style={{ fontSize: 20 }}>Find Us</Text>
</View>
</View>
<View style={{ flexDirection: "row", height: 130 }}>
<View style={styles.IconImage}>
<TouchableOpacity
onPress={() =>
Linking.openURL("http://facebook.com/")
}
>
<Icon
name={Platform.OS === "ios" ? "ios-settings" : "md-settings"}
size={40}
color={"#E8AA65"}
/>
</TouchableOpacity>
</View>
<View style={{ paddingTop: 50, paddingLeft: 40 }}>
<Text style={{ fontSize: 20 }}>Settings</Text>
</View>
</View>
</>
);
}
const styles = StyleSheet.create({
IconImage: {
paddingTop: 40,
paddingLeft: 40,
},
});
The issue is caused by providing flex:1 in your main view.
Output without flex:1:
The remaining offset is caused by your height together with your padding values.
Demo:
I've created a snack where you can play around with it:
https://snack.expo.io/rkUKpLUUU
I have created a button Add Margin inside flatlist that is posting data to backend, however when I try to post it throws me Unhandled Promise Rejection error.
My add margin function is as follows:
margin = () => {
let data = {
method: 'POST',
body: JSON.stringify({
margin: this.state.margin,
}),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
}
console.log(data)
this.setState({
isLoading: true,
})
return fetch('some url',item._id )
.then((response) => response.text())
.then((responseJson) => {
this.setState({
isLoading: false,
data: responseJson.data,
});
console.log(JSON.stringify(responseJson));
})
}
I have called the above function as follows:
<TextInput value={this.state.margin} onChangeText={(text) => this.setState({ margin: text })}placeholder="enter margin" />
<TouchableHighlight onPress={this.margin}>
<Text>Add Margin </Text>
</TouchableHighlight>
After clicking on Add Margin, my logs are:
{"body": "{\"margin\":\"76\"}", "headers": {"Accept": "application/json", "Content-Type": "application/json"}, "method": "POST"}
WARN Possible Unhandled Promise Rejection (id: 3):
TypeError: undefined is not an object (evaluating 'this.state.data.product')
render
finishClassComponent#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:17804:43
updateClassComponent#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:17767:50
invokeGuardedCallbackImpl#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:9044:21
invokeGuardedCallback#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:9140:42
beginWork$$1#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:23261:34
performUnitOfWork#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:22399:30
workLoopSync#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:22381:45
renderRoot#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:22145:29
renderRoot#[native code]
runRootCallback#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:21906:34
runRootCallback#[native code]
http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:12636:38
unstable_runWithPriority#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:42642:30
flushSyncCallbackQueueImpl#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:12631:28
flushSyncCallbackQueue#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:12620:35
scheduleUpdateOnFiber#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:21788:37
enqueueSetState#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:14189:23
setState#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:4647:37
tryCallOne#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:27029:16
http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:27130:27
_callTimer#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:30584:17
_callImmediatesPass#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:30620:19
callImmediates#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:30839:33
callImmediates#[native code]
__callImmediates#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:2627:35
http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:2404:34
__guard#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:2610:15
flushedQueue#http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false:2403:21
flushedQueue#[native code]
invokeCallbackAndReturnFlushedQueue#[native code]
Please help, and point me what am doing wrong, let me know if you require anything else.
My render method is as follows:
render() {
const ViewportAwareVideo = Viewport.Aware(Video);
if (this.state.isLoading) {
return (
<View style={{ flex: 1, padding: 20 }}>
<ActivityIndicator />
</View>
);
}
return (
<View >
<StatusBar hidden />
<TouchableOpacity
onPress={() => this.props.navigation.navigate('Cart')}
style={{
position: 'absolute',
top:10,
right:80,
zIndex:100
}}>
<Icon
name="shopping-cart"
size={24}
style={{ paddingLeft: 60}}
color="white"
/>
</TouchableOpacity>
<TouchableOpacity
style={{
position: 'absolute',
top:10,
right:20,
zIndex:100
}}
onPress={() => this.props.navigation.navigate('User')}
>
<Icon
name="user-circle"
size={24}
style={{ paddingLeft: 20 }}
color="white"
/>
</TouchableOpacity>
<SwiperFlatList
initialNumToRender={1}
vertical={this.state.vertical}
index={0}
data={this.state.data.product}
scrollEventThrottle={1}
onEndThreshold={0}
renderItem={({ item }) => (
<View style = {{alignContent: 'stretch'}} >
<View>
<ScrollView >
<GestureRecognizer
onSwipeLeft={this.onSwipeLeft}/>
<ViewportAwareVideo
repeat paused={this.state.videoPaused}
source={{ uri: item.urlVid }}
resizeMode = "cover"
preTriggerRatio={PRE_TRIGGER_RATIO}
retainOnceInViewport={false}
style={{width: width, height:height}}
innerRef={ref => this._videoRef = ref}
onViewportEnter={() => this._videoRef.play()}
onViewportLeave={() => this._videoRef.stop()}
/>
</ScrollView>
</View>
<View
style={{
position: 'absolute',
flexDirection: 'column',
alignItems: 'flex-end',
top: '50%',
right: 10,
}}>
<TouchableOpacity
onPress= {() => this.onButtonPress(item)}
style={{
alignItems: 'center',
borderRadius: 60,
padding: 10,
}}>
<Icon
name="heart"
size={30}
color={this.state.likedItemIds.includes(item._id) ? "red" : "white"}
/>
<Modal
style={{flex:1,
justifyContent: 'center',
alignItems: 'center',
marginTop: (Platform.OS == 'android') ? 20 : 0}}
animationType="slide"
transparent={false}
visible={this.state.modalVisible}
onRequestClose = {() => { this.props.navigation.navigate('Home'), console.log('closed') } }>
<View>
<Text>{item.title} - {item.price}</Text>
<TextInput value={this.state.margin} onChangeText={(text) => this.setState({ margin: text })}placeholder="enter margin" />
<TouchableHighlight onPress={this.margin}>
<Text>Add Margin </Text>
</TouchableHighlight>
{/* <TouchableHighlight
onPress={() => {
this.setModalVisible(!this.state.modalVisible);
}}> */}
{/* <TouchableHighlight onPress={()=>{this.props.navigation.navigate('Home')}}>
<Text>Go Back</Text></TouchableHighlight> */}
{/* </TouchableHighlight> */}
</View>
</Modal>
</TouchableOpacity>
<TouchableOpacity
onPress={()=>this.shareProduct(item)}
style={{
alignItems: 'center',
borderRadius: 60,
padding: 10,
}}>
<Icon name="share" size={30} color="white" />
</TouchableOpacity>
<Text style={{ right: 5, color: 'white' }} />
<TouchableOpacity
style={{
alignItems: 'center',
borderRadius: 60,
padding: 10,
}}>
<Icon name="whatsapp" size={30} color="white" />
</TouchableOpacity>
<Text style={{ right: 5, color: 'white' }} />
<TouchableOpacity
onPress= {() => this.download(item)}
style={{
alignItems: 'center',
borderRadius: 60,
padding: 10,
}}>
<Icon name="download" size={30} color="white" />
</TouchableOpacity>
<Text style={{ right: 5, color: 'white' }} />
</View>
<View
style={{
position: 'absolute',
flexDirection: 'column',
top: '90%',
left: 10,
}}>
<TouchableOpacity onPress={() => this.props.navigation.navigate('Product', {_id: item._id})}>
<View
style={{
flexDirection: 'row',
}}>
<Text
style={{ fontWeight: 'bold', fontSize: 20, color: 'white' }}>
{item.title} - {item.price}
</Text>
</View>
</TouchableOpacity>
</View>
</View>
)}
keyExtractor={ item => item._id}
/>
</View>
);
}
}
// AppRegistry.registerComponent('homePage',()=> homePage);
export default withNavigationFocus(Videos)
I am trying to put a background color for an app I am making but it doesn't fit to all the screen and the bottom of it doesn't take the style.
This is my code:
<ScrollView>
<View style={styles.main}>
<View style={{ marginTop: 10 }}>
<Image style={{ flex: 1, height: 80, width: 80, alignSelf: 'center', marginTop: 23 }}
source={require('./../src/img/profile.png')} />
</View>
<View style={styles.fourblock}>
<TouchableOpacity
style={styles.redbox}
onPress={() => Actions.personal()}>
<Text style={styles.redboxText}>
Personal Detail
</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.redbox}
onPress={() => Actions.savedschools()}>
<Text style={styles.redboxText}>
Saved Schools
</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.redbox}
onPress={() => Actions.languages()}>
<Text style={styles.redboxText}>
Your Reviews
</Text>
</TouchableOpacity>
</View>
</View>
</ScrollView>
And this is the style I want to put:
main: {
//marginTop: 52,
backgroundColor: '#F8F8FF',
flex: 1,
},
<ScrollView> must be inside <View style={styles.main}>
so
<View style={styles.main}>
<ScrollView>
<View>
// .........
</View>
</ScrollView>
</View>
<Image style={{ flex: 1, height: 80, width: 80, alignSelf: 'center', marginTop: 23 }}
resizeMode: 'stretch', // or 'cover' . <<------------------
source={require('./../src/img/profile.png')} />
One more way you can fit view on all screen is using positioning absolute and make all left, top, right and bottom 0.
Here is an example.
<View style={{ position : 'absolute', top : 0, left : 0, right : 0,bottom : 0,}}</View>