react native maps callout content is overflowed - react-native

i got a problem with react native maps callout , each marker update its position every 10 seconds, callout starts hidden but, when you press the marker it open the callout and keep it open each new position update, but sometimes the callout content is places out of bounds of the callout container.
image:
callout content not fit in it container
code:
`
import * as React from "react"
import { Text, View,StyleSheet } from 'react-native';
import { Marker,Callout } from 'react-native-maps';
import Svg, { Path, Circle } from "react-native-svg";
import moment from "moment";
import "moment/min/locales.min.js";
import { FontAwesome, FontAwesome5 } from '#expo/vector-icons';
import useStatusImei from "../../hooks/useStatusImei";
import { fecha,timediff } from "../../utils/App";
import {MapaContext} from "../../context/MapaContextProvider";
moment.locale("es");
const Icon = ({ignicion,velocidad,vel_max,grados,color}) =>{
return ignicion == 1 && velocidad > 1 ?
(
<Svg width={60} height={60} xmlns="http://www.w3.org/2000/svg" style={{ transform: [{ rotate: `${grados}deg` }] }}>
<Path
style={[styles.ign,{ stroke: velocidad >= vel_max ? '#ed6b75' : "#fff", fill: color }]}
d="m38.828 45.578 14.599 7.815-7.085-16.295a17.412 17.412 0 0 0 1.338-6.704c0-7.495-4.729-13.869-11.36-16.348L30.213 0l-6.107 14.046c-6.63 2.479-11.36 8.853-11.36 16.348 0 2.376.479 4.639 1.338 6.704L7 53.393l14.599-7.815a17.37 17.37 0 0 0 8.614 2.283c3.136 0 6.071-.837 8.615-2.283z"
/>
</Svg>
)
:
(
<Svg width={40} height={40} xmlns="http://www.w3.org/2000/svg">
<Circle style={[styles.off,{fill: color}]} cx={20} cy={20} r={18} />
</Svg>
)
}
const InfoWindow = ({numero,marca,info,color,time_color,fecha_hora_gps, ignicion,velocidad,vel_max,fecha_hora_ultimo_encendido,odometro, odometro_ultimo_encendido, fecha_hora_inicio_relenti,fecha_hora_ultimo_apagado,fecha_hora_fin_ultimo_viaje,fecha_hora_inicio_ultimo_viaje,odometro_fin_ultimo_viaje,odometro_inicio_ultimo_viaje}) =>{
let informacion, detalle,color_velocidad;
if( ignicion == 1){
if(Math.floor(velocidad)>1){//en movimiento
if( Math.floor(velocidad) < vel_max && Math.floor(velocidad) >=( vel_max - 5 )){
color_velocidad= '#F1C40F';
}else if(Math.floor(velocidad)>=vel_max){
color_velocidad= '#ed6b75';
detalle = (<Text style={{color:color_velocidad,fontWeight:'500'}}>¡Exceso de Velocidad!</Text>);
}else {
color_velocidad = '#26C281';
detalle = (
<View style={styles.info}>
<FontAwesome5 name="code-branch" size={15} color="#5867dd" />
<Text style={styles.text}> {timediff((moment().unix(fecha_hora_gps) - moment(fecha_hora_ultimo_encendido).unix()),0)} </Text>
<Text style={styles.text}> {( ( odometro - odometro_ultimo_encendido) / 1000 ).toFixed(1)}kms</Text>
</View>
);
}
informacion = (
<View>
<View><Text style={[styles.vel,{color:color_velocidad}]}>{ Math.round(velocidad)} kms/h</Text></View>
<View>
{detalle}
</View>
</View>
);
}else{//en relenti
informacion = (<View><Text style={{color,fontWeight:'500'}}>En relentí {timediff((moment().unix() - moment(fecha_hora_inicio_relenti).unix()),0)}</Text></View>);
}
}else{
informacion = (
<View>
<View><Text style={styles.text}>Apagado desde {moment(fecha_hora_ultimo_apagado).calendar()}</Text></View>
<View style={styles.info}>
<FontAwesome5 name="code-branch" size={15} color="#5867dd" />
<Text style={styles.text}> {timediff((moment(fecha_hora_fin_ultimo_viaje).unix() - moment(fecha_hora_inicio_ultimo_viaje).unix()),0)} </Text>
<Text style={styles.text}> {((odometro_fin_ultimo_viaje - odometro_inicio_ultimo_viaje) / 1000 ).toFixed(1)} kms </Text>
</View>
</View>
);
}
//
return (
<Callout>
<View style={styles.calloutContainer} >
<Text><Text style={styles.bold}>{numero}</Text> <Text style={styles.text}>{marca}</Text></Text>
{informacion}
<Text style={[styles.text,{fontSize:12}]} ><FontAwesome name="cloud-upload" size={14} color={time_color} /> {fecha(fecha_hora_gps,5)}</Text>
</View>
</Callout>);
}
const Unidad = ({ unidad,aforos = false }) => {
const {setUnidadFocus,unidad_focus} = React.useContext(MapaContext);
const item = useStatusImei({...unidad},aforos);
const markerRef = React.useRef(undefined);
const handleCallout = ()=>{
markerRef.current.showCallout();
setUnidadFocus({imei:item.imei,fecha_hora_gps:item.fecha_hora_gps,marker:markerRef});
}
React.useEffect(()=>{
if(unidad_focus && unidad_focus.imei == item.imei && !unidad_focus.marker){
handleCallout()
}
},[markerRef.current]);
let fz =12;
if (item && item.latitud && item.longitud) {
if(item.numero.length > 6)
fz = 9
if(item.numero.length > 5)
fz = 10
if(item.numero.length > 4)
fz = 11
return (
<Marker
ref = {(ref)=>{markerRef.current = ref}}
key={item.imei}
coordinate={{ latitude: item.latitud, longitude: item.longitud }}
anchor={{ x: 0.5, y: 0.5 }}
style={styles.marker}
tracksViewChanges={false}
flat={true}
onPress={()=>{handleCallout()}}
>
<Icon {...item} />
<Text style={[styles.markerLabel,{fontSize:fz}]}>{item.numero}</Text>
<InfoWindow {...item} />
</Marker>
);
}
return null;
};
const styles = StyleSheet.create({
marker:{ justifyContent: "center", alignItems: "center" },
calloutContainer: {
width:250,
height:100,
justifyContent:'center',
alignItems: 'center',
padding:5
},
bold:{
fontWeight:'600',
color:"#5867dd",
fontSize:16
},
text:{
color:'#57585a'
},
markerLabel: { color: '#FFFFFF', position: 'absolute', fontSize: 13, fontWeight: '400' },
info:{flexDirection:"row",alignItems:'center',justifyContent:'space-around'},
off:{ strokeWidth: 4, strokeOpacity: 0.5, stroke: "#fff", fillRule: "nonzero" },
ign:{strokeWidth: 6, strokeOpacity: 0.5, fillRule: "nonzero"},
vel: {fontWeight:'500',textAlign:'center'}
})
export default Unidad
`
I read along this forum, changed the components structure, set fixed width and height callout container and keep it with basic text but in each change the problem keep apearing only sometimes, in expo app and in production app.

Related

How to create an onPress event that dismisses a callout?

I'm building a gig guide in React Native, using react native maps.
Users are presented with a Map with markers indicating the location of gig. When these markers are tapped, a callout pops up with gig information:
When the user taps the "Next day's gigs" button, the map is rendered with markers showing the upcoming day's gigs. When the user hits this button, I want to make sure that any open callouts on the current day are dismissed when the button is hit. Any suggestions on how to do this?
Here's the code from the component rendering the map:
GigMap.js
import { useState, useMemo } from "react";
import {
StyleSheet,
Text,
View,
Pressable,
Image,
TouchableOpacity,
} from "react-native";
import MapView from "react-native-maps";
import { Marker, Callout } from "react-native-maps";
import CalloutView from "./CalloutView";
import { mapStyle } from "../util/mapStyle";
import { useGigs } from "../hooks/useGigs";
import { AntDesign } from "#expo/vector-icons";
const GigMap = ({ navigation }) => {
const [selectedDateMs, setSelectedDateMs] = useState(Date.now());
const gigs = useGigs();
//generates current date in format DD/MM/YYYY
const selectedDateString = useMemo(() => {
const date = new Date(selectedDateMs);
const dateToString = date.toString().slice(0,15)
return dateToString // returns in form 'Tue Dec 20 2022'
}, [selectedDateMs]);
//Filtering through gigs to return only current day's gigs
const gigsToday = gigs.filter((gig) => {
const gigDate1 = new Date(gig.dateAndTime.seconds*1000)
const gigDate2 = gigDate1.toString().slice(0,15) //return form 'Tue Dec 20 2022'
return gigDate2 === selectedDateString
})
//increments date by amount
const addDays = (amount) => {
setSelectedDateMs((curr) => curr + 1000 * 60 * 60 * 24 * amount);
};
return (
<View style={styles.container}>
<Text style={styles.headerText}>{`Gigs on ${selectedDateString}`}</Text>
<View style={styles.imageText}>
<Text style = {styles.subHeader}>Tap on</Text>
<Image
style={styles.image}
source={require("../assets/Icon_Gold_48x48.png")}
/>
<Text style = {styles.subHeader}> to see gig info</Text>
</View>
<MapView
initialRegion={{
latitude: -41.29416,
longitude: 174.77782,
latitudeDelta: 0.03,
longitudeDelta: 0.03,
}}
style={styles.map}
customMapStyle={mapStyle}
>
{gigsToday.map((gig, i) => (
<Marker
key={i}
coordinate={{
latitude: gig.location.latitude,
longitude: gig.location.longitude,
}}
image={require("../assets/Icon_Gold_48x48.png")}
description = 'test'
>
<Callout
style={styles.callout}
tooltip={true}
onPress={() =>
navigation.navigate("GigDetails", {
venue: gig.venue,
date: selectedDateString,
gigName: gig.gigName,
image: gig.image
})
}
>
<CalloutView
venue={gig.venue}
gigName={gig.gigName}
genre = {gig.genre}
/>
</Callout>
</Marker>
))}
</MapView>
<View style={styles.buttonOptions}>
<TouchableOpacity onPress={() => addDays(-1)} style = {styles.touchable}>
<AntDesign name="caretleft" size={36} color="#778899" />
<Text style = {{fontFamily:'Helvetica-Neue', color:'#778899'}}>Previous day's gigs</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => addDays(1)} style = {styles.touchable}>
<AntDesign name="caretright" size={36} color="#778899" />
<Text style = {{fontFamily:'Helvetica-Neue',color:'#778899'}}>Next day's gigs</Text>
</TouchableOpacity>
</View>
</View>
);
};
CalloutView.js
import { StyleSheet, Text, View } from 'react-native';
const CalloutView = ({ venue,gigName,genre }) => {
const title = gigName.substring(0,25)
return (
<View style = {styles.container}>
<Text style = {styles.header} >{`${title}`}</Text>
<Text style = {styles.details}>{`${venue} | ${genre}`}</Text>
<Text style = {styles.button}>Tap to see details</Text>
</View>
);
}
Try this
import React from "react";
import { IMAGES } from "theme";
import { View, Text, StyleSheet } from "react-native";
import MapView, { PROVIDER_GOOGLE, Marker, Callout } from "react-native-maps";
const GigMap = () => {
return (
<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,
}}
>
<Marker
coordinate={{
latitude: 37.78825,
longitude: -122.4324,
}}
image={IMAGES.MAP_MARKER}
title="Test Title"
description="This is the test description"
>
<Callout tooltip>
<View>
<View style={styles.bubble}>
<Text numberOfLines={1} style={styles.name}>Gig Title</Text>
<Text>A Gig description</Text>
</View>
<View style={styles.arrowBorder} />
<View style={styles.arrow} />
</View>
</Callout>
</Marker>
</MapView>
);
};
export default GigMap;
const styles = StyleSheet.create({
map: {
height: "100%",
},
// Callout bubble
bubble: {
flexDirection: "column",
alignSelf: "flex-start",
backgroundColor: "#fff",
borderRadius: 6,
borderColor: "#ccc",
borderWidth: 0.5,
padding: 15,
width: 150,
},
// Arrow below the bubble
arrow: {
backgroundColor: "transparent",
borderColor: "transparent",
borderTopColor: "#fff",
borderWidth: 16,
alignSelf: "center",
marginTop: -32,
},
arrowBorder: {
backgroundColor: "transparent",
borderColor: "transparent",
borderTopColor: "#007a87",
borderWidth: 16,
alignSelf: "center",
marginTop: -0.5,
},
// Gig Title
name: {
fontSize: 16,
marginBottom: 5,
},
// Gig button
button: {
width: "40%",
height: 80,
},
});
Here is some of the Suggestions for you
use numberOfLines for title
use Dayjs instead of manually doing date.toString().slice(0,15) also it will be solve your all dates and time related problems

Understanding UI State : Dynamic TextInput loses focus after each key press

Screens and navigating is fine, but getting data from users has been a struggle. Not only are the UI elements different, the means to capture input and store in state effectively across various input types is troubling me. Here is an example of what I think is a simple UX yet I cannot get the text inputs to focus correctly.
In the below example, the desire is to have a list of items within a horizontal scroll view and when i click on the arrow of an item, the screen scrolls and a form to edit the item appears with one or more text boxes. Future enhancements were to have this second panel have more fields based on the type of field from the list, but i cant even get a simple text box to work properly
I've got some code to boot, copy and paste as app.js in an expo init project and it should run
main question: how to retain focus on inputs on the detail panel
import React from "react";
import {
Dimensions,
FlatList,
SafeAreaView,
Text,
TextInput,
TouchableOpacity,
View,
} from "react-native";
const init_items = [
{ name: "start", value: 12500, type: "num" },
{ name: "end", value: 12700, type: "num" },
{ name: "time", value: 123.45, type: "time" },
];
const main_color = "#dddddd";
const _base = 3;
const _width = Dimensions.get("window").width;
export default function App() {
const [index, setIndex] = React.useState(0);
const [items, setItems] = React.useState(init_items);
const [curItem, setCurItem] = React.useState("");
const ref = React.useRef(null);
const textRef = React.useRef(null);
React.useEffect(() => {
console.log("index chsnaged?", index);
//if (!index) return;
ref.current?.scrollToIndex({ index, animated: true });
}, [index]);
React.useEffect(() => {
setIndex(curItem === "" ? 0 : 1);
}, [curItem]);
const useCurItem = () => {
if (curItem == "") return;
return items.find((item) => item.name == curItem);
};
const setCurItemValue = (value) => {
console.log("update " + curItem + " to " + value);
const new_items = items.map((item) => {
if (item.name == curItem) return { ...item, value: value };
return item;
});
console.log("new_items: ", new_items);
setItems(new_items);
};
const Button = ({ type, press }) => {
return (
<TouchableOpacity onPress={() => press(type)}>
<Text style={{ fontSize: 20, fontWeight: "900", margin: _base }}>
{type == "arrow" ? ">" : "X"}
</Text>
</TouchableOpacity>
);
};
const ListPanel = () => {
return (
<View>
{items.map((item) => {
return (
<View
key={item.name}
style={{
margin: _base,
}}
>
<Text style={{ fontWeight: "600", margin: _base }}>
{item.name}
</Text>
<View
style={{
alignItems: "center",
backgroundColor: "white",
borderRadius: _base,
flexDirection: "row",
justifyContent: "space-between",
margin: _base,
padding: _base,
}}
>
<Text>{item.value}</Text>
<Button type="arrow" press={() => setCurItem(item.name)} />
{/* <EmojiButton
name={"fat_arrow"}
onPress={() => setCurItem(item.name)}
size={20}
/> */}
</View>
</View>
);
})}
</View>
);
};
const DetailPanel = () => {
let thisItem = useCurItem();
if (!thisItem) return null;
return (
<View style={{ width: "100%" }}>
{/* <EmojiButton name="arrow_left" onPress={() => setCurItem("")} /> */}
<Button type="cancel" press={() => setCurItem("")} />
<Text>{curItem}</Text>
<Text>{thisItem?.value}</Text>
<Text>{thisItem.type}</Text>
{thisItem.type == "num" && (
<TextInput
ref={textRef}
onChangeText={(text) => setCurItemValue(text)}
// onSubmitEditing={() => textRef.current.focus()}
style={{ backgroundColor: "white", margin: 2 }}
value={thisItem.value.toString()}
/>
)}
</View>
);
};
const screens = [
{ name: "listing", panel: <ListPanel /> },
{ name: "detail", panel: <DetailPanel /> },
];
return (
<View style={{ marginTop: 30 }}>
<Text>Sample sliding inputs</Text>
<FlatList
bounces={false}
horizontal
keyExtractor={(item) => item.name}
ref={ref}
showsHorizontalScrollIndicator={false}
data={screens}
renderItem={({ item, index: fIndex }) => {
console.log("rendering " + item);
return (
<View
style={{
backgroundColor: main_color,
height: 300,
width: _width,
padding: _base,
}}
>
<Text> {item.name}</Text>
{item.panel}
</View>
);
}}
/>
<Text>index: {index}</Text>
<Text>curItem: {curItem}</Text>
<TouchableOpacity onPress={() => setCurItem("")}>
<View>
<Text>reset</Text>
</View>
</TouchableOpacity>
</View>
);
}

How to make a horizontal timeline in a React Native project?

I have an array of objects. Each object has time and status. Also, I have a range of time with a specific value and I needed to display that on the timeline:
I want the result something like that
I suppose need to use "react-native-svg" and "react-native-svg-charts", but I can't understand how to make the timeline.
If you can, suggest a solution, please.
I've resolved this:
import React from "react";
import PropTypes from "prop-types";
import {StyleSheet, View} from "react-native";
import Icons from "react-native-vector-icons/MaterialIcons";
import {LineChart, Path} from "react-native-svg-charts";
import {ClipPath, Defs, ForeignObject, G, Rect} from "react-native-svg";
import {connect} from "react-redux";
import * as shape from "d3-shape";
import colors from "../../../styles/colors";
const TimeLine = (props) => {
// props.info.distractions - the array of red lines on the timeline (green line)
const startTime = props.info.startTs; // the start value of the timeline (GREEN line)
const endTime = props.info.endTs; // the end time value of the timeline (GREEN line)
const data = [0, 0];
const line = shape.curveBasis;
// Get coefficients to scale the array of red lines into the timeline (green line)
const getCoefficients = (distraction) => {
const wholeTime = endTime - startTime;
const dZone = distraction;
const a1 = dZone.start - startTime;
const a2 = dZone.end - endTime;
const startCoefficient = a1 / wholeTime;
const endCoefficient = a2 / wholeTime;
return {startCoefficient, endCoefficient};
};
// To render a red line on the timeline (green line)
const RenderLine = ({width, distraction, index}) => {
const {startCoefficient, endCoefficient} = getCoefficients(distraction);
return (
<ClipPath id={`clip-path-${index + 1}`}>
<Rect
x={startCoefficient * width}
y={"0"}
width={endCoefficient * width}
height={"100%"}
/>
</ClipPath>
);
};
// To render a red line on the timeline (green line)
const DistractionLine = ({line, index}) => {
return (
<G key={index}>
<Path
key={`line-${index + 1}`}
d={line}
stroke={colors.red}
strokeWidth={6}
fill={"none"}
clipPath={`url(#clip-path-${index + 1})`}
/>
</G>
);
};
// To render an icon
const ChartPoint = ({width, distraction, index}) => {
const {startCoefficient, endCoefficient} = getCoefficients(distraction);
return (
<ForeignObject
x={(startCoefficient * width + endCoefficient * width) / 2}
y={40}
width={100}
height={40}>
<Icons name={"touch-app"} color={colors.red} size={24} />
</ForeignObject>
);
};
// To render the timeline (green line)
const Clips = ({x, y, width}) => {
return (
<Defs key={"clips"}>
<ClipPath id="clip-path-0">
<Rect x={"0"} y={"0"} width={width} height={"100%"} />
</ClipPath>
{props.info.distractions.map((distraction, index) => (
<RenderLine
key={index}
index={index}
distraction={distraction}
width={width}
/>
))}
</Defs>
);
};
return (
<View style={styles.chartContainer}>
<Icons
name={"radio-button-checked"}
size={24}
color={colors.red}
style={{marginRight: -2, marginBottom: 10}}
/>
<LineChart
style={{height: 70, width: "90%"}}
data={data}
contentInset={{top: 0, bottom: 40}}
curve={line}
svg={{
stroke: colors.green,
strokeWidth: 6,
clipPath: "url(#clip-path-0)",
}}>
<Clips />
{props.info.distractions.map((distraction, index) => (
<ChartPoint
key={index}
index={index}
distraction={distraction}
/>
))}
{props.info.distractions.map((distraction, index) => (
<DistractionLine
key={index}
index={index}
distraction={distraction}
/>
))}
</LineChart>
<Icons
name={"place"}
size={24}
color={colors.red}
style={{marginLeft: -6, marginBottom: 10}}
/>
</View>
);
};
TimeLine.defaultProps = {
info: {},
};
TimeLine.propTypes = {
info: PropTypes.object,
};
const styles = StyleSheet.create({
chartContainer: {
marginTop: 20,
flexDirection: "row",
padding: 20,
paddingVertical: 20,
backgroundColor: "#fff",
justifyContent: "center",
alignItems: "center",
},
});
const mapStateToProps = (state) => {
const { infoReducer } = state;
return {
info: infoReducer.info,
};
};
export default connect(mapStateToProps)(TimeLine);

What am I doing wrong with my code here I'm so lost

I'm trying to input my firestore into the form and put all my user data so I can pass information as
profile.name
profile.email
profile.location
profile.avatar
so what am I doing wrong here to keep on receiving this error?
Error
This is my mock screen
import Fire from '../utilities/Fire';
super(props);
this.state = {
user: {}
}
const user = this.props.uid || Fire.shared.uid
this.unsubscribe = Fire.shared.firestore
.collection("users")
.doc(user)
.onSnapshot(doc => {
this.setState({ user: doc.data() });
});
this.unsubscribe();
unsubscribe = null;
const profile = {
username: this.state.user.name,
location: this.state.user.location,
email: this.state.user.email,
avatar: this.state.user.avatar ? { uri: this.state.user.avatar } : require("../assets/avatar.png"),
notifications: true,
};
export { profile };
This is my Settings Page
import React, { Component } from "react";
import { Image, StyleSheet, ScrollView, TextInput } from "react-native";
import { Divider, Button, Block, Text, Switch } from "../components";
import { theme, mock } from "../constants";
class Settings extends Component {
state = {
notifications: true,
editing: null,
profile: {}
};
componentDidMount() {
this.setState({ profile: this.props.profile });
}
handleEdit(name, text) {
const { profile } = this.state;
profile[name] = text;
this.setState({ profile });
}
toggleEdit(name) {
const { editing } = this.state;
this.setState({ editing: !editing ? name : null });
}
renderEdit(name) {
const { profile, editing } = this.state;
if (editing === name) {
return (
<TextInput
defaultValue={profile[name]}
onChangeText={text => this.handleEdit([name], text)}
/>
);
}
return <Text bold>{profile[name]}</Text>;
}
render() {
const { profile, editing } = this.state;
return (
<Block>
<Block flex={false} row center space="between" style={styles.header}>
<Text h1 bold>
Settings
</Text>
<Button>
<Image source={profile.avatar} style={styles.avatar} />
</Button>
</Block>
<ScrollView showsVerticalScrollIndicator={false}>
<Block style={styles.inputs}>
<Block row space="between" margin={[10, 0]} style={styles.inputRow}>
<Block>
<Text gray2 style={{ marginBottom: 10 }}>
Username
</Text>
{this.renderEdit("username")}
</Block>
<Text
medium
secondary
onPress={() => this.toggleEdit("username")}
>
{editing === "username" ? "Save" : "Edit"}
</Text>
</Block>
<Block row space="between" margin={[10, 0]} style={styles.inputRow}>
<Block>
<Text gray2 style={{ marginBottom: 10 }}>
Location
</Text>
{this.renderEdit("location")}
</Block>
<Text
medium
secondary
onPress={() => this.toggleEdit("location")}
>
{editing === "location" ? "Save" : "Edit"}
</Text>
</Block>
<Block row space="between" margin={[10, 0]} style={styles.inputRow}>
<Block>
<Text gray2 style={{ marginBottom: 10 }}>
E-mail
</Text>
<Text bold>{profile.email}</Text>
</Block>
</Block>
</Block>
<Divider margin={[theme.sizes.base, theme.sizes.base * 2]} />
<Divider />
<Block style={styles.toggles}>
<Block
row
center
space="between"
style={{ marginBottom: theme.sizes.base * 2 }}
>
<Text gray2>Notifications</Text>
<Switch
value={this.state.notifications}
onValueChange={value => this.setState({ notifications: value })}
/>
</Block>
</Block>
</ScrollView>
</Block>
);
}
}
Settings.defaultProps = {
profile: mock.profile
};
export default Settings;
const styles = StyleSheet.create({
header: {
paddingHorizontal: theme.sizes.base * 2
},
avatar: {
height: theme.sizes.base * 2.2,
width: theme.sizes.base * 2.2
},
inputs: {
marginTop: theme.sizes.base * 0.7,
paddingHorizontal: theme.sizes.base * 2
},
inputRow: {
alignItems: "flex-end"
},
sliders: {
marginTop: theme.sizes.base * 0.7,
paddingHorizontal: theme.sizes.base * 2
},
thumb: {
width: theme.sizes.base,
height: theme.sizes.base,
borderRadius: theme.sizes.base,
borderColor: "white",
borderWidth: 3,
backgroundColor: theme.colors.secondary
},
toggles: {
paddingHorizontal: theme.sizes.base * 2
}
});
Tried to add a class function to fix it but now it's not recognized my profile on my const, tried to change the class name to mock and export both mock and profile but not working any tips?
fixed the first error but now I am getting a second error with my setState
The error is pretty informative.
You can not have super() sitting outside of a class constructor.
Here would be a working example of that:
class YourComponentName extends Component {
constructor( props ) {
super( props )
this.state = {
user: {}
}
}
...
}
export default YourComponentName
More info on super: https://overreacted.io/why-do-we-write-super-props/
While this should resolve the error you're getting, it probably will not resolve your underlying issue. I recommend researching React state machines.
super(props); should be used inside constructor on the class. So just wrap your super and state in the constructor or remove super completely.

React-native navigation progress bar

I am new to React-native can anyone please tell me how I would create a header menu with a progress bar, something like the attached image. Any advice much appreciated...
I have made progress, how can I remove the space inbetween each step?
<View style={styles.stepIndicatorBox}>
{stepsIds.map((step, idx) => {
const words = steps[step].split(' ');
const activeStepStyle = step === activeStep && styles.activeStep;
return (
<View key={`${step}${idx}`}>
<Svg height="25" width="100">
<Line
x1="10"
y1="10"
x2="100"
y2="10"
stroke={theme.colors.blue}
strokeWidth="2"
/>
<Circle
cx="50"
cy="10"
r="3"
stroke={theme.colors.blue}
strokeWidth="2.5"
fill={theme.colors.lightBlue}
/>
</Svg>
{words.map(w =>
<Text style={[styles.stepName, activeStepStyle]}>
{w}
</Text>
)}
</View>
);
})}
</View>
My styles are:
const styles = StyleSheet.create({
sceneContainer: {
bottom: 0,
left: 0,
position: 'absolute',
right: 0,
top: 0,
},
stepIndicatorBox: {
height: theme.utils.em(4),
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
backgroundColor: theme.colors.lightBlue,
paddingHorizontal: theme.metrics.mainPadding,
},
activeStep: {
...theme.fontStyles.smallBold,
color: theme.colors.activeStepName,
fontWeight: 'bold',
},
stepName: {
...theme.fontStyles.small,
color: theme.colors.blue,
textAlign: 'center',
},
});
I used the following code and react-native-svg:
_renderStepIndicator = () => {
const { navigation } = this.props; // {dispatch}
const { steps, getStep } = stepsOptions;
const route = navigation.state.routes[navigation.state.routes.length - 1];
const activeStep = getStep(route.routeName);
const stepsIds = Object.keys(steps);
const { height, width } = Dimensions.get('window');
const stepWidth = width / 5;
const RouteComponent = StepIndicatorRouter.getComponentForRouteName(
route.routeName
);
if (RouteComponent.navigatorType === STEP_INDICATOR) {
return null;
}
return (
<View style={styles.stepIndicatorBox}>
{stepsIds.map((step, idx) => {
const words = steps[step].split(' ');
const activeStepStyle = step === activeStep && styles.activeStep;
return (
<View key={`${step}${idx}`} style={styles.stepIndicatorStep}>
<Svg height="25" width={stepWidth}>
<Line
x1="0"
y1="15"
x2={stepWidth}
y2="15"
stroke={theme.colors.blue}
strokeWidth="2"
/>
<Circle
cx="40"
cy="15"
r="3"
stroke={theme.colors.blue}
strokeWidth="2"
fill={
step === activeStep
? theme.colors.blue
: theme.colors.lightBlue
}
/>
</Svg>
{words.map(w =>
<Text style={[styles.stepName, activeStepStyle]}>
{w}
</Text>
)}
</View>
);
})}
</View>
);
};