How to truncate 'back' button for headerTitle in react-navigation? - ios

I'm using react-navigation with StackNavigator. Is there a way to avoid the overlapping of the back button label and the headerTitle by truncating the back button label?
const MainNavigationOptions = {
headerStyle: {
backgroundColor: colors.CiPrimary
},
headerTitleStyle: {
color: 'white',
height: 50,
width: 140
},
headerTintColor: 'white',
headerTitle:
<Text>LONG TEXT FOR TESTING</Text>
}
Illustration of issue:

(This Answer takes into account that the viewer is using react-navigation 5.x)
In Your Screen component
export const screenOptions = (navData) => {
let title = navData.route.params.movieTitle;
if (title.length > 18) {
title = title.substr(0, 18) + "...";
}
return {
headerTitle: title,
};
};
Here, since we are using substr() , you can use it accordingly and truncate it to custom match your case, keeping in mind the edge cases.
Then you can import it in your AppNavigator.js or wherever you initialize your navigator (in my case below ;)
import {screenOptions as MoviesDetailScreenOptions} from
"../screens/MovieDetailScreen";
Here screenOptions is the named-export you are using MoviesDetailScreenOptions is the alias if i am not mistaken.

Create a style for your button label because it now left for you to style it your self and you can style it any way you want.
const styles = {
leftTouch: {
flexDirection: 'row',
...
},
customStyle: {
paddingLeft: 10,
...
}
textStyle: {
width: 60,
fontSize: 14,
......
}
}
const { leftTouch, customStyle, textStyle} = styles;
Instead of Icon you can use <Image /> but am assuming you are using an icon i.e react-native-vector-icon or likes.
N.B Now you have control of everything the button should do especially when pressed.
const MainNavigationOptions = {
headerStyle: {
backgroundColor: colors.CiPrimary
},
headerTitleStyle: {
color: 'white',
height: 50,
width: 140
},
.....
headerLeft: ( <TouchableOpacity style={leftTouch} onPress={() => goBack()} >
<Icon name="ios-arrow-dropleft-circle-outline" size={25} style={customStyle} color="#ffffff" />
<Text numberOfLines={1} style={textStyle}>A Longer Text for testing</Text>
</TouchableOpacity>
)
}

If you mean to shorten the back button label, why not use either:
headerBackTitle (change the Back label for the previous screen, put it in navigationOptions of the previous screen);
headerBackTitleStyle (change the Back label displayed on current screen, put it in navigationOptions of the current screen)

Related

While using a custom header with react navigation for a react native app, I can't identify where this background is coming from?

I am using the default stack from react navigation, and in my navigator screen options I have my own custom header header: (props) => <Header props={props} />. In my screen, I have a background colour, and in my SafeAreaView I have a background colour. For illustration I have set them both to the same.
In my custom header I am applying margin of 15 horizontally as well as to the top. So it is the colour underneath the custom header.
My question is this: Where is this header background colour being set? (the light grey one)
Here you can see what I mean
I have tried headerStyle {backgroundColor}, but no difference (i believe because using header overrides a lot of these options? Unsure though as it is not stated in the documentation.)
For reference, I am basing it off of this documentation: https://reactnavigation.org/docs/native-stack-navigator/#options
However it appears that this background colour is being set somewhere else entirely? And so I'm not sure where.
I realize setting headerTransparent and applying margin for each screen is a viable solution but I figure there is a better way to simply set the background colour of this space correctly.
edit with header component:
export default function Header({ props }) {
const { navigation, route, options, back } = props;
const title = getHeaderTitle(options, route.name);
return (
<View style={styles.header}>
<View style={styles.container}>
{back && (
<IconButton
type="ion"
name="chevron-back"
size={26}
iconStyle={styles.backButton}
onPress={navigation.goBack}
/>
)}
<Text style={styles.title}>{title}</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
width: screenWidth - 30,
height: 60,
borderRadius: 10,
padding: 15,
marginTop: 15,
backgroundColor: colors.white,
alignSelf: "center",
flexDirection: "row",
alignItems: "center",
},
backButton: {
zIndex: 1,
},
title: {
flex: 1,
textAlign: "center",
flexDirection: "column",
fontSize: 24,
fontWeight: "bold",
// marginLeft: -26,
},
header: {
backgroundColor: colors.neutral95,
},
});

React Navigation: How to put an iOS style dismissible bar on expo modal

I am trying to achieve a dismissible bar for my modal. Something like in this image:
What i am at right now
code:
<RootStack.Group
screenOptions={{
presentation: "modal",
gestureEnabled: true,
headerBackTitleVisible: false,
headerTitle: "",
hideNavigationBar: false,
gestureEnabled: true,
}}
>
<RootStack.Screen name="MyModal" component={ModalScreen} />
</RootStack.Group>
I am not sure if there is a built-in solution to that, but for sure you can hide the status bar per screen. In this case that's MyModal screen. And once you hide it you can implement a custom header that can be anything you wish it to be, but you will need to hook back actions etc.
Another way is to implement a custom Header, React Navigation has an API for that https://reactnavigation.org/docs/stack-navigator#header
Since there isn't a built in solution, you could achieve what you want by doing something like so:
(1) You will need to replace react-navigation's generated header with a custom one, like the following:
function LogoTitle() {
return (
<Image
style={{ width: 50, height: 50 }}
source={require('#expo/snack-static/react-native-logo.png')}
/>
);
}
function StackScreen() {
return (
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ headerTitle: (props) => <LogoTitle {...props} /> }}
/>
</Stack.Navigator>
);
}
Source: https://reactnavigation.org/docs/headers#replacing-the-title-with-a-custom-component
(2) Your custom component would have to look something like this:
export default function App() {
const cancelButtonOnPress = () => {
navigation.goBack();
}
return (
<View style={styles.container}>
<View style={styles.bar}></View>
<Text onPress={()=>{cancelButtonOnPress()}} style={styles.cancelButton}>Cancel</Text>
</View>
);
}
const styles = StyleSheet.create({
cancelButton: {
color: '#0573ad'
},
bar: {
alignSelf: 'center',
width: 40,
height: 7,
backgroundColor: 'gray',
borderRadius: 40,
},
container: {
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
padding: 8,
borderWidth: 1,
borderColor: 'black',
},
});
The above App looks like the following:
(3) Since you are passing your custom component to react-navigation, the gesture swipe to dismiss the modal should be retained, if for some reason it isn't, you could try setting fullScreenGestureEnabled to true in screenOptions.

Set height of ListView in React Native

I need to set width and height of ListView. While setting width works as expected, setting height has no effect and ListView is always stretching into almost bottom of the screen (there is only margin between bootom of screen and bottom of ListView). I am creating ListView in render method this way:
<ListView ref={component => this._stationsListFrom = component} style={styles.stationsList} dataSource={this.state.dataSource} renderRow={(rowData) => <Text>{rowData}</Text>} />
This is its style:
stationsList: {
backgroundColor: 'white',
height: 0,
}
I have also tried to set its height in a method by this command:
this._stationsListFrom.setNativeProps({height: 200});
When I have tried to set width using this command, it worked. But setting height does nothing.
How can I set height of ListView (for example, in the case of TextInput its not a problem) to desired value? Only way I wound is to use bottom margin, but that is not the way I want to use.
I am testing on iOS only (for the case it works differently on Android).
My code:
import React, { Component } from 'react';
import Dimensions from 'Dimensions';
import {
AppRegistry,
StyleSheet,
Text,
TextInput,
ListView,
Button,
View
} from 'react-native';
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'flex-start',
alignItems: 'flex-start',
backgroundColor: '#D8CD36',
padding: 25
},
label: {
textAlign: 'left',
color: '#333333',
fontSize: 20,
margin: 5,
},
textInput: {
height: 40,
borderColor: 'black',
borderWidth: 2,
padding: 7,
},
stationsList: {
backgroundColor: 'white',
height: 0,
},
separator: {
flex: 1,
height: StyleSheet.hairlineWidth,
backgroundColor: '#8E8E8E',
},
menuButton: {
},
},
);
export default class TestApp extends Component {
constructor(props) {
super(props);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); this.state = { dataSource: ds.cloneWithRows(['Žilina', 'Košice', 'Vrútky']), };
}
render() {
return (
<View style={styles.container}>
<Text style={styles.label}>
Z
</Text>
<TextInput ref={component => this._textInputFrom = component} style={styles.textInput} placeholder="Východzia stanica" onChangeText={this.fromTextChange.bind(this)} onLayout={(event) => { this.correctMenuFromWidth(event.nativeEvent.layout) }} renderSeparator={(sectionId, rowId) => <View key={rowId} style={styles.separator}/>} />
<Text style={styles.label}>
Do
</Text>
<TextInput style={styles.textInput} placeholder="Cieľová stanica"/>
<ListView ref={component => this._stationsListFrom = component} style={styles.stationsList} dataSource={this.state.dataSource} renderRow={(rowData) => <Button onPress={this.menuFromButtonPressed} style={styles.menuButton} title={rowData} />} />
</View>
);
}
correctMenuFromWidth(layout) {
const {x, y, width, height} = layout;
this._stationsListFrom.setNativeProps({marginTop: -74, width: width});
}
menuFromButtonPressed() {
};
fromTextChange() {
this._textInputFrom.setNativeProps({text: 'Kraľovany'});
this._stationsListFrom.setNativeProps({height: 200});
};
}
AppRegistry.registerComponent('TestApp', () => TestApp);
Move ListView inside wrapper and set height to wrapper:
<View style={{height: 200}}>
<ListView .../>
</View>
From ScrollView docs (ListView uses ScrollView):
Keep in mind that ScrollViews must have a bounded height in order to work, since they contain unbounded-height children into a bounded container (via a scroll interaction). In order to bound the height of a ScrollView, either set the height of the view directly (discouraged) or make sure all parent views have bounded height.

How to range ScollView and Button in a row in react native?

I wanna to place a ScrollView and Button in a row, but It doesn't work, neither paddingLeft or width.
Without the Button the NaviScrollView will fill the hole view even I had set the width; with the Button and the Button will fill the hole view. Why?
export class Home extends Component {
render() {
return (
<View style={ styles.container }>
<NaviScrollView data= { fakeData }/>
<Button title="添加" color='gray' style={{right:0, width:20}}/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: 'red',
top: 20,
height: 44
},
})
class NaviScrollView extends Component {
render(){
return (
<ScrollView horizontal={true}>
{
this.props.data.map((item, index) =>
<Button key={ index } title={ item.title } onPress={ () => this._buttonPressed(item.title + item.url)}
color = 'black'/>)
}
</ScrollView>
);
}
}
Using style property : flexDirection : 'row' for View tag to organize childrens in a row or flexDirection : 'column' to organize childrens in a column.
I make a simple example base on your project. I didn't know its similar with your project or not but just take a look.
export default class Home extends Component {
render(){
return(
<View style={ styles.container }>
<ScrollView>
<Text>ABC</Text>
<Text>DEF</Text>
<Text>GHI</Text>
<Text>JKL</Text>
<Text>NMO</Text>
</ScrollView>
<TouchableOpacity style={styles.press}>
<Text>Press Me</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
button : {
width : 50,
height : 50
},
container: {
flexDirection : 'row',
backgroundColor: 'red',
top: 20,
height: 44
},
press: {
width: 150,
padding: 10,
backgroundColor : 'yellow'
}
})

How to set a background Image of Navigator in React-Native

I'm using Navigator component in React-Native.
//...
render() {
return (
<Navigator
ref="navigator"
navigationBar={this.renderHeader()}
sceneStyle={styles.container}
initialRoute={{type: 'Home'}}
renderScene={this.renderScene.bind(this)} />
);
}
Now I need to set a background image fixed for all scenes, but I can't wrap Navigator component inside another View.
// No errors but background is ignored
render() {
return (
<View style={styles.navigatorContainer}>
<Image source={require('image!logo-big')} style={styles.background} />
<Navigator
ref="navigator"
navigationBar={this.renderHeader()}
sceneStyle={styles.container}
initialRoute={{type: 'Home'}}
renderScene={this.renderScene.bind(this)} />
</View>
);
}
var styles = StyleSheet.create({
container: {
flex: 1
},
background: {
position: 'absolute',
left: 0,
top: 0,
width: 1024,
height: 768
},
navigatorContainer: {
flex: 1,
backgroundColor: '#FF0000'
}
});
If I set the backgroundColor to class NavigatorContainer, I can see red background but it doesn't work with image.
Any suggestions?
Found the fix: to show the background image you must set the navigatorContainer's backgroundColor to 'transparent'.

Resources