React Native Tab View : How to change text color on change of tab - react-native

I am using react-native-community/react-native-tab-view
is there any method to change the tab text color on change of tab.Right now its just lighten the text color but wanted to change it to a different color ?

To change the text color on your TabBar, it should look like this:
<TabBar
{...props}
indicatorStyle={{ backgroundColor: '#eeaf3b' }}
style={{ backgroundColor: '#282828', height: 55 }}
indicatorStyle={{ backgroundColor: '#eeaf3b', height: 5 }}
renderLabel={this.renderLabel} />
Then renderLabel function should look like this:
renderLabel = ({ route, focused, color }) => {
return (
<View>
<Text
style={[focused ? styles.activeTabTextColor : styles.tabTextColor]}
>
{route.title}
</Text>
</View>
)
}
Then your style should look like this:
const styles = StyleSheet.create({
activeTabTextColor: {
color: '#eeaf3b'
},
tabTextColor: {
color: '#ccc'
}
})

In that case, try passing a callback to the renderLabel property in your TabView like so:
_renderLabel = (scene) => {
const myStyle = { /* Defined your style here.. */ }
// grab the label from the scene. I'm not really sure
// about the structure of scene, but you can see it using console.log
const label = scene.label
return (
<Text style={myStyle}>{label}</Text>
);
}
_renderHeader = () => {
return <TabBar renderLabel={this._renderLabel} />
}

Related

React Native TextInput onPressOut fires instantly

I am making a class for a custom TextInput, where the style will change when the field is selected, and will change back as soon as it is pressed out of. It looks as follows...
export function SoftSearchBar({
height=40,
width='100%',
fontSize=20,
fireOnChange={function(){console.log("No Change Function in place")}},
value=false,
placeholder="Placeholder",
type=null
}){
const [isActive, setActive] = useState(false)
const [style, setStyle] = useState({})
useEffect(() => {
console.log(isActive)
if (isActive){
setStyle(style => ({style: styles.softSearchActive, width: width}))
}
else{
setStyle(style => ({style: styles.softSearchInactive, width: width}))
}
}, [isActive])
return(
<View style={{height: height, flexDirection: 'row'}}>
<TextInput
value={value}
onPressIn={() => setActive(true)}
onPressOut={() => setActive(false)}
style={{...style.style, width: width, zIndex: 0, fontSize: fontSize}}
textContentType={type}
text
placeholder={placeholder}
placeholderTextColor={'black'}
autoCorrect={false}
onChangeText={text => {
fireOnChange(text)
}}
/>
</View>
)
}
Almost all of this works as expected, when the field is pressed, an outline appears indicating its selection, and the text changes color. However, onPressOut fires immediately after onPressIn, as the log will look like this as soon as I press the field
true
false
indicating that onPressOut fired, since it is the only way to setIsActive(false)
I saw some solutions recommending using onResponderRelease as opposed to onPressOut but then it just never unselects. Is there some syntax Im missing with onPressOut? This seems like a pretty simple and straightforward syntax so I am unsure
Main Issue with your code is onPressIn and onPressOut you need to change them to onFocus and onBlur
Here is a working example you can paste into this website
https://reactnative.dev/docs/textinput
You can set your default Input style and then when active you can enable the style you want.
outlineStyle: none to get rid of the default blue outline of the textinput when focused
Can also just remove handleFocus & handleBlur and move the function into the actual function calls to reduce the code further
import React from "react";
import { SafeAreaView, StyleSheet, TextInput } from "react-native";
const UselessTextInput = () => {
const [style, setStyle] = React.useState({borderWidth:2 , borderColor: 'red', outlineStyle: 'none'});
const [active, setActive] = React.useState(false)
const handleFocus = () => setActive(true)
const handleBlur = () => setActive(false)
return (
<SafeAreaView>
<TextInput
style={[styles.input, active && style]}
onFocus={handleFocus}
onBlur={handleBlur}
onChangeText={() => {}}
value={null}
placeholder="useless placeholder"
keyboardType="numeric"
/>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
input: {
height: 40,
margin: 12,
borderWidth: 1,
padding: 10,
},
});
export default UselessTextInput;

Navigation using images nested inside Touchable Opacity

Background:
I've designed a custom footer for my app in React Native, I've set some images to act as icons. I'm trying to have them redirect to other pages of the app upon touch.
What I have tried
I've been trying to use the same images nested within TouchableOpacity components to have them redirect to other pages using react navigation.
This is my code:
export class Footer extends React.Component {
render (){
return (
<View style = { styles.footStyle } >
<TouchableOpacity onPress={ () => navigation.push('Home')} >
<Image
style = { styles.iconStyle }
source = {require('./img/home.png')}/>
</TouchableOpacity>
<TouchableOpacity onPress={ () => navigation.push('Favoritos')} >
<Image
style = { styles.iconStyle }
source = {require('./img/heart.png')}/>
</TouchableOpacity>
<TouchableOpacity onPress={ () => navigation.push('Search')} >
<Image
style = { styles.iconStyle }
source = {require('./img/search.png')}/>
</TouchableOpacity>
<TouchableOpacity onPress={ () => navigation.push('Notifications')} >
<Image
style = { styles.iconStyle }
source = {require('./img/bell.png')}/>
</TouchableOpacity>
<TouchableOpacity onPress={ () => navigation.push('Help')} >
<Image
style = { styles.iconStyle }
source = {require('./img/circle.png')}/>
</TouchableOpacity>
</View>
)
}
}
const styles = StyleSheet.create({
footStyle: {
paddingBottom: 0,
paddingRight: 10,
backgroundColor: '#ffffff',
flex: 0.4,
flexDirection: 'row',
borderTopWidth: 1,
borderTopColor: '#000000'
},
iconStyle: {
flex: 0.2,
height: undefined,
width: undefined
}
})
Problem
When I try and run the app in expo, the images are not rendering at all. I get my blank footer without any content. I've tried touching the footer to see if the images weren't rendering but the "button" actually worked, that didn't work.
Question
How exactly can I nest an image within a TouchableOpacity component? Is it even possible to use this method with React Navigation?
Thanks a lot!
For an Image component to work you should provide a height and width in style.
Here you are setting it as undefined
Try something like
iconStyle: {
flex: 0.2,
height: 100,
width: 100
}
Also on the navigation, you will have to pass the navigation prop to the Footer. As its a class you should access it as this.props.navigation.navigate()
As your code for integrating the Footer is not here, its hard to comment on how to pass the prop to the footer.

How to add space between components that comes from a mapping function?

I am trying to add some buttons with a title that is inside every position of an array (for exaMple the first button have its title in the content of the array in the position 0), that is the reason i am using a map function and it works but... i can not add space between each button
it looks like this:
THIS IS WHERE THE MAPPING FUNCTION IS CALLED:
<ScrollView horizontal={true} showsHorizontalScrollIndicator={false}>
<View style={{
flexDirection: 'row',
justifyContent: 'space-between'}}>
{mapping()}
</View>
</ScrollView>
THIS IS THE FUNCTION:
function mapping() {
const horas = ["6:30-7:30", "7:30-8:30", "7:30-8:30"...]
const mappeo = horas.map((i) => {
return (
<Button
title={i}
type="outline"
style={{ padding:10}}/>
)
}
)
return (mappeo)
}
So how can i separate the buttons?
How about using margin. Padding are used for content inside a container and margins are used for applying margins or spaces outside the container.
Try this
function mapping() {
const horas = ["6:30-7:30", "7:30-8:30", "7:30-8:30"...]
const mappeo = horas.map((i) => {
return (
<Button
title={i}
type="outline"
style={{ padding:10, marginHorizontal:10}}/>
)
}
)
return (mappeo)
}
add 'marginHorizontal' to your button like below:
function mapping() {
const horas = ["6:30-7:30", "7:30-8:30", "7:30-8:30"...]
const mappeo = horas.map((i) => {
return (
<Button
title={i}
type="outline"
style={{ padding:10, marginHorizontal: 5 }}/>
)
}
)
return (mappeo)
}

How can I display 30 pages of text in a (scrolling) screen

I want to display 30 pages of text on a screen. I've tried ScrollView and FlatList but I get a white screen. Only when I try with ScrollView to display only 2 pages, works fine.
I do not want to use a WebView, because I would like to have all data in the app (no internet connection needed).
Here is what I've already tried:
With FlatList:
I have a text.js as a model, which I use to create a Text Object in an array, which I then use as data for the FlatList. For the renderItem function (of FlatList) I use a TextItem to display the text.
text.js
function Text(info) {
this.id = info.id;
this.text = info.text;
}
export default Text;
LongTextModule.js
import Text from '../../models/text';
export const LONGTEXT = [
new Text({
id:'text_1',
text:`.....longtext....`
})
]
TextItem.js
const TextItem = (props) => {
return (
<View style={styles.screen} >
<Text style={styles.textStyle}>{props.longText}</Text>
</View >
);
};
const styles = StyleSheet.create({
screen: {
flex: 1,
},
textStyle: {
justifyContent: 'flex-start',
alignItems: 'flex-start',
fontFamily: 'GFSNeohellenic-Regular',
fontSize: 20,
padding: 10,
}
});
TextDetailScreen.js
const TextDetailScreen = (props) => {
const renderText = data => {
return <TextItem longText={data.item.text} />
}
return <FlatList
data={LONGTEXT}
keyExtractor={(item, index) => item.id}
renderItem={renderText}
/>
};
I think it's needless to show the code with ScrollView, since ScrollView is only for a small list.
I even tried to render the longText like this in the screen.
Without the ScrollView I get the first portion, but with ScrollView a white screen.
const TextDetailScreen = (props) => {
return (
<ScrollView>
<Text> ...longText...</Text>
</ScrollView>
);
};
I'm sure there is a way to display a lot of pages of text on a screen?
But how?
Thank you :)
It seems not to be an unknown Issue, I've also read from time to time about this issue.
But not to use Webview, because you wan't to have all Data in your app - don't have to be an Argument against Webview. With WebView, you also can display Data from your App-Storage.
Example:
<WebView style={styles.myStyle} source={{html: `<p style="font-size:48px">${longtext}</p>`}} />

React Native TabNavigator change TabStyle to follow according to the text

I am using expo v27.0, react native 0.55 and I as you can see in the picture that the tab have somewhat a fixed width like a default width from the tab navigation, and the text wrap into three lines, I want the text to be in 1 line and nowrap, and i have tried styling (flexWrap:
'nowrap', flex: 1) in TabStyle, LabelStyle in TabBarOptions, but still can't get the tab to have the width according to the text inside the tab.
I populate the text for the tabs dynamically from json using fetch, therefore all tabs will have different width according to the text. How to I make the tab to follow the width of the text ?
All answers are greatly welcomed.
Thank you in advance.
Solved, turns out just need to set the width to auto as follows:
tabBarOptions: {
tabStyle: {
width: 'auto'
}
}
You can use render label in render header and in that you can return your Text component and Text is having numberOfLines props that will be 1 and it will add ... at end of the text after one line.
Check example snippet:
_renderLabel = props => {
let preparedProps = {
style: {
fontFamily: fonts.Regular,
marginVertical: 8
},
fontType: props.focused ? "Medium" : "Light"
};
return (
<Text
{...preparedProps}
numberOfLines={1}
ref={ref => {
ref && this.props.addAppTourTarget(ref, props.route.key);
}}
>
{props.route.type === "free" && this.state.is_premium_member
? this.labels.premium
: props.route.title}
</Text>
);
};
_renderHeader = props => (
<TabBar
{...props}
bounces={true}
style={{
backgroundColor: colors.cardBlue
}}
indicatorStyle={{
backgroundColor: colors.radicalRed,
height: 1,
borderRightWidth: initialLayout.width * 0.1,
borderLeftWidth: initialLayout.width * 0.1,
borderColor: colors.cardBlue
}}
tabStyle={{
padding: 0,
borderTopColor: "transparent",
borderWidth: 0
}}
renderLabel={this._renderLabel}
/>
);
_handleIndexChange = index => this.setState({ index });
_renderScene = ({ route, focused }) => {
switch (route.key) {
case "a":
return <One {...this.props} route={route} focused={focused} />;
case "b":
return (
<Two {...this.props} isSeries={true} focused={focused} />
);
case "c":
return <Three {...this.props} route={route} focused={focused} />;
default:
return null;
}
};