I am very new to react.js and JavaScript, so apologies in advance.
I am trying to make a very concise diagramming tool in my webpage, where the user can create their own use case diagram.
I am looking at these examples:
https://reactflow.dev/examples/drag-and-drop/
https://reactflow.dev/examples/update-node/
I got the drag and drop to work, but am having a hard time applying the update node feature. My final goal is to let the user select a node, and update its name via input at the sidebar.
I started with adding const onElementClick = (event, element) => event.dataTransfer.getData("label"); to the main file to get the label from the sidebar, and am trying to send back the changed label by adding the block code below.
<label> label: </label>
<input value={nodeName} onChange={(evt) => setNodeName(evt.target.value)} />
Because their example on https://reactflow.dev/examples/update-node/ has everything in a single file, and am not able to update the node's name with selection, I am just a bit unsure how to proceed from here.
Any help would be sincerely appreciated, as a beginner in react.
Again, apologies and thanks in advance!
main.js
import Sidebar from "./Sidebar";
const initialElements = [
{
id: "1",
type: "input",
data: { label: "User" },
position: { x: 300, y: 150 },
},
{
id: "2",
type: "default",
data: { label: "Use Case" },
position: { x: 700, y: 250 },
},
{
id: "3",
type: "output",
data: { label: "Database" },
position: { x: 1100, y: 350 },
},
];
let id = 0;
const getId = () => `dndnode_${id++}`;
export const Tester = () => {
const reactFlowWrapper = useRef(null);
const [reactFlowInstance, setReactFlowInstance] = useState(null);
const [elements, setElements] = useState(initialElements);
const [nodeName, setNodeName] = useState("Node 1");
const [nodeBg, setNodeBg] = useState("#eee");
const [nodeHidden, setNodeHidden] = useState(false);
const onElementClick = (event, element) => event.dataTransfer.getData("click", element);
const onConnect = (params) => setElements((els) => addEdge(params, els));
const onElementsRemove = (elementsToRemove) =>
setElements((els) => removeElements(elementsToRemove, els));
const onLoad = (_reactFlowInstance) => setReactFlowInstance(_reactFlowInstance);
const onDragOver = (event) => {
event.preventDefault();
event.dataTransfer.dropEffect = "move";
};
const onDrop = (event) => {
event.preventDefault();
const reactFlowBounds = reactFlowWrapper.current.getBoundingClientRect();
const type = event.dataTransfer.getData("application/reactflow");
const label = event.dataTransfer.getData("label");
const position = reactFlowInstance.project({
x: event.clientX - reactFlowBounds.left,
y: event.clientY - reactFlowBounds.top,
});
const newNode = {
id: getId(),
type,
position,
data: { label: label },
};
setElements((es) => es.concat(newNode));
};
return (
<div className="dndflow">
<ReactFlowProvider>
<Box
className="reactflow-wrapper"
ref={reactFlowWrapper}
style={{ height: 600 }}
sx={{ display: "flex", justifyContent: "space-between", justifyContent: "center" }}
>
<ReactFlow
elements={elements}
onConnect={onConnect}
onElementsRemove={onElementsRemove}
onLoad={onLoad}
onDrop={onDrop}
onDragOver={onDragOver}
onElementClick={onElementClick}
>
<Controls />
<MiniMap />
<Background variant="lines" size={1.5} gap={20} color="#eee" />
</ReactFlow>
<Box sx={{ ml: 10 }}>
<Sidebar />
</Box>
</Box>
</ReactFlowProvider>
</div>
);
};
Sidebar.js
export default () => {
const onDragStart = (event, nodeType, label) => {
event.dataTransfer.setData("application/reactflow", nodeType);
event.dataTransfer.setData("label", label);
event.dataTransfer.effectAllowed = "move";
};
const changeNodeName = (event, nodetype, label) => {
//event.dataTransfer.getData()
const [nodeName, setNodeName] = useState("Node 1");
};
return (
<aside>
<Box
sx={{
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
}}
>
<div className="description">Drag nodes to the pane.</div>
<Box
className="dndnode input"
onDragStart={(event) => onDragStart(event, "input", "User")}
draggable
sx={{
mt: 2,
border: 1,
borderColor: "blue",
borderRadius: 0.5,
width: 200,
height: 50,
textAlign: "center",
py: 1.4,
"&:hover": {
opacity: 0.5,
},
}}
>
User
</Box>
<Box
className="dndnode"
onDragStart={(event) => onDragStart(event, "default", "Use Case")}
draggable
sx={{
mt: 2,
border: 0.5,
borderColor: "black",
borderRadius: 0.5,
width: 200,
height: 50,
textAlign: "center",
py: 1.4,
"&:hover": {
opacity: 0.5,
},
}}
>
Use Case
</Box>
<Box
className="dndnode output"
onDragStart={(event) => onDragStart(event, "output", "Database")}
draggable
sx={{
mt: 2,
border: 0.5,
borderColor: "red",
borderRadius: 0.5,
width: 200,
height: 50,
textAlign: "center",
py: 1.4,
"&:hover": {
opacity: 0.5,
},
}}
>
Database
</Box>
</Box>
</aside>
);
};
I get the same problem as you, but after a while, I solve this problem after reading it many times in the docs https://reactflow.dev/docs/api/react-flow-props/,
you can use onNodeClick(event: React.MouseEvent, node: Node) and set a state like show-sidebar that will change every time u click on the nodes set-Show-Sidebar( !show-sidebar), so when it gets true u send the node-id to Sidebar change it and receiver it, change it with onChange function then update nodes with
nodes.map((node)=>{node.id === id ? {...node, label:newName } : node})
Related
I have Flatlist that doesn't scroll.
I can't find the problem why its not scrolling.
When I'm trying to scroll, It does nothing. It doesn't give me to scroll past the Produce item.
It looks like this (I have more items after Produce):
This is my code:
const Dropdown: FC<Props> = ({ label, data, onSelect, current, style }) => {
const [dropdownTop, setDropdownTop] = useState(0);
const [visible, setVisible] = useState(false);
const [selected, setSelected] = useState(current);
const DropdownButton = useRef();
const toggleDropdown = (): void => {
visible ? setVisible(false) : openDropdown();
};
const openDropdown = (): void => {
DropdownButton.current.measure((_fx, _fy, _w, h, _px, _py) => {
setDropdownTop(_py + h - 10);
});
setVisible(true);
};
const renderDropdown = (): ReactElement<any, any> => {
return (
<Modal visible={visible} transparent animationType='none'>
<TouchableOpacity
style={styles.overlay}
onPress={() => setVisible(false)}>
<View style={[styles.dropdown, { top: dropdownTop }]}>
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={(item, index) => index.toString()}
contentContainerStyle={{
flexGrow: 1,
flex: 1,
}}
/>
</View>
</TouchableOpacity>
</Modal>
)
};
const renderItem = ({ item }): ReactElement<any, any> => (
<TouchableOpacity style={styles.item} onPress={() => onItemPress(item)}>
<Text style={{ color: "#616161" }}>{item.label}</Text>
</TouchableOpacity>
)
const onItemPress = (item): void => {
setSelected(item);
onSelect(item);
setVisible(false);
};
return (
<TouchableOpacity
ref={DropdownButton}
style={[styles.button, style]}
activeOpacity={0.6}
onPress={toggleDropdown}>
{renderDropdown()}
<Text style={styles.buttonSecondText}>{label}</Text>
<Text style={styles.buttonText}>{(selected && selected.label) || null}</Text>
</TouchableOpacity>
)
}
export default Dropdown
const styles = StyleSheet.create({
item: {
paddingHorizontal: 10,
paddingVertical: 10,
// borderBottomWidth: 1,
borderWidth: 1,
},
button: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#FFF',
elevation: 10,
width: '100%',
paddingHorizontal: 13,
paddingVertical: 13,
borderRadius: 10,
zIndex: 1,
},
buttonSecondText: {
flex: 2,
color: '#000',
textAlign: 'left',
},
buttonText: {
flex: 2,
textAlign: 'right',
color: '#000',
},
dropdown: {
position: 'absolute',
backgroundColor: '#FFF',
paddingHorizontal: 20,
width: '100%',
shadowColor: '#000000',
shadowRadius: 4,
shadowOffset: { height: 4, width: 0 },
shadowOpacity: 0.5,
},
});
I can't understand where is my problem and why its not scrolling.
Maybe its because its inside a Modal? I'm first time trying to use Modal in React Native
Hi I was working on a project, and I am on a part where I am adding up the total cost of orders in the order summary page. I have used
`
let totalPrice = Object.keys(cartItem).map((menuKey) => (
totalPrice =+ cartItem[menuKey].cost))
`
to sum up the cost and display totalPrice
I understand that it might be in String right now, although I am not sure why, because I have passed the param as a number (4.29)
Right now I have 3 items in my cart, all 4.29 for now.
As expected from a string's behavior, it is being displayed as 4.294.294.29.
Problem number 1) parseDouble not working.
Problem number 2) I have no idea how to use the toFixed(2) method on my code.
Any Idea on how I can implement the total cost method?
Whole File :
`
import {
View,
StyleSheet,
ScrollView,
Alert,
ActivityIndicator,
TouchableOpacity,
Button,
Text
} from "react-native";
import AsyncStorage from "#react-native-async-storage/async-storage";
import { useFocusEffect } from "#react-navigation/native";
import ItemCard from "../components/ItemCard";
import { useState, useCallback } from "react";
import { Swipeable } from "react-native-gesture-handler";
import { Ionicons } from "#expo/vector-icons";
export default function CartScreen({ navigation }) {
const [loading, setLoading] = useState(true);
const [cartItem, setcartItem] = useState({});
const [prevOpenedRow, setPrevOpenedRow] = useState();
const [selectedMenu, setselectedMenu] = useState({});
const CART_KEY = "#carts_Key";
const saveCart = async (menuObj) => {
try {
const jsonValue = JSON.stringify(menuObj);
await AsyncStorage.setItem(CART_KEY, jsonValue);
} catch (e) {
alert(`${title}: ${e}`);
}
};
const deleteCart = async (menuKey) => {
const newItem = { ...cartItem };
delete newItem[menuKey];
setcartItem(newItem);
await saveCart(newItem);
};
const alertBeforeDelete = (menuKeyToDelete) => {
Alert.alert(
"Remove from Cart",
`Removing "${cartItem[menuKeyToDelete].title}"`,
[
{
text: "Cancel",
},
{
text: "Remove",
onPress: () => deleteCart(menuKeyToDelete),
style: "destructive",
},
]
);
};
const clearCart = async () => {
const emptyCart = {};
setcartItem(emptyCart);
await saveCart(emptyCart);
};
const alertBeforeClear = () => {
Alert.alert(
"Clearing All Items at Cart",
"Clearing Cart Now. Are you sure?",
[
{
text: "Cancel",
},
{
text: "Yes, Clear",
onPress: () => clearCart(),
style: "destructive",
},
]
);
};
console.log(cartItem)
let totalPrice = Object.keys(cartItem).map((menuKey) => (
totalPrice =+ cartItem[menuKey].cost))
// Swipeable code modified;
const renderRightActions = (progress, dragX, alertBeforeDelete) => {
return (
<View
style={{
margin: 0,
alignContent: "center",
justifyContent: "center",
width: 70,
}}
>
<TouchableOpacity
style={styles.deleteButton}
onPress={alertBeforeDelete}
>
<Ionicons name="trash" size={40} color="#fff" />
</TouchableOpacity>
</View>
);
};
const closeRow = (menuKey) => {
if (prevOpenedRow && prevOpenedRow !== selectedMenu[menuKey]) {
prevOpenedRow.close();
}
setPrevOpenedRow(selectedMenu[menuKey]);
};
useFocusEffect(
useCallback(() => {
const getCart = async () => {
try {
const jsonValue = await AsyncStorage.getItem(CART_KEY);
setcartItem(jsonValue != null ? JSON.parse(jsonValue) : {});
} catch (e) {
alert(`${e}`);
}
};
getCart();
setLoading(false);
return () => {
};
}, [])
);
return loading ? (
<View style={styles.loadingPage}>
<ActivityIndicator size="large" color="#ffffff" />
</View>
) : (
<>
<Text style={styles.titleText}>Your Current Orders:</Text>
<View style={styles.container}>
<ScrollView>
{Object.keys(cartItem).map((menuKey) => (
<TouchableOpacity
key={menuKey}
onPress={() => {
navigation.navigate({
name: "customize",
params: {
text: cartItem[menuKey].text,
image: cartItem[menuKey].image,
cost: cartItem[menuKey].cost,
},
});
}}
>
<Swipeable
renderRightActions={(progress, dragX) => renderRightActions(progress, dragX, () => alertBeforeDelete(menuKey)
)}
ref={(ref) => (selectedMenu[menuKey] = ref)}
onSwipeableOpen={() => closeRow(menuKey)}
rightOpenValue={-100}
>
<ItemCard
text={cartItem[menuKey].text}
image={cartItem[menuKey].image}
cost ={cartItem[menuKey].cost}
/>
</Swipeable>
</TouchableOpacity>
))}
<View style={styles.priceBlock}><Text style = {styles.totalText}>Total Price: ${totalPrice}</Text></View>
<View style={styles.itemTextBlock}>
<TouchableOpacity
style={styles.clearButton}
title="clear"
color="red"
onPress={alertBeforeClear}>
<Text style={styles.buttonText}>Clear All</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.checkoutButton}
onPress={() => {
navigation.navigate('Past Orders');
clearCart();
}}
>
<Text style={styles.buttonText}>Checkout</Text>
</TouchableOpacity>
</View>
</ScrollView>
</View></>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "white",
},
loadingPage: {
flex: 1,
backgroundColor: "white",
justifyContent: "center",
},
deleteButton: {
color: "red",
backgroundColor: "#f5392f",
height: "95%",
borderRadius: 15,
justifyContent: "center",
alignItems: "center",
},
titleText: {
fontSize: 30,
fontWeight: "bold",
color: "black",
resizeMode: "contain",
textAlign: "center"
},
clearButton: {
width: "40%",
borderRadius: 25,
height: 50,
alignItems: "center",
justifyContent: "center",
backgroundColor: "grey",
},
checkoutButton: {
width: "40%",
borderRadius: 25,
height: 50,
alignItems: "center",
justifyContent: "center",
backgroundColor: "#800000",
},
buttonText: {
color: 'white',
fontWeight: 'bold'
},
itemTextBlock: {
alignItems: "center",
flex: 1,
flexDirection: "row",
justifyContent: "space-evenly",
marginBottom: 100,
},
priceBlock: {
alignItems: "center",
marginBottom: 10,
},
totalText: {
textAlign: "center",
fontSize:24,
fontWeight: "bold",
},
});
`
I have tried
parseDouble and toFixed(2)
To be honest I thought
let totalPrice = Object.keys(cartItem).map((menuKey) => (
totalPrice =+ cartItem[menuKey].cost))
would throw an error.
What I think is the best way to go about this is to use reduce to get your sum:
const initialValue = 0;
const totalPrice = Object.keys(cartItem).reduce((prevValue,currentVal)=>{
let num = parseFloat(cartItem[currentVal].cost);
// if number cant be parsed do nothing
if(isNaN(num))
return prevValue
return prevValue + num;
},initialValue);
If you want to use map:
let totalPrice = 0;
Object.keys(cartItem).map((menuKey) => {
let num = parseFloat(cartItem[menuKey].cost)
if(isNaN(num))
return
totalPrice += num
})
I'm trying to make animation in flatlist, something like this, it will have spring animation when moving item
Something like apple music you can see: https://streamable.com/yg1j2j
With the help of #David Scholz, I was able to make exactly the same, here is expo for that:
https://snack.expo.dev/#quockhanh210199/animated-list-selection
But problem is, when i enable scroll it will have weird animation, so my question is, how to make the animation behavior correct if i enable scroll, you can see the weird animation if you enable scroll and and more item, or use below code:
import React, {useState, useCallback} from 'react';
import { StyleSheet, Text,View, SafeAreaView, ScrollView, StatusBar, Animated,FlatList,TouchableOpacity } from 'react-native';
const App = () => {
const data = [
{
id: "1",
text: "Results",
},
{
id: "2",
text: "Products",
},
{
id: "3",
text: "Stores",
},
{
id: "4",
text: "Stores",
},
{
id: "5",
text: "Stores",
},
{
id: "6",
text: "Stores",
},
]
const [translateValue] = useState(new Animated.Value(0))
const [selected, setSelected] = useState(0)
const onPress = React.useCallback(
(index) => {
setSelected(index)
Animated.spring(translateValue, {
toValue: index * 100,
velocity: 5,
useNativeDriver: true,
}).start()
},
[translateValue, setSelected]
)
return (
<View style={{ flexDirection: "row", marginTop: 100 }}>
<Animated.View
style={[
{
position: "absolute",
backgroundColor: "black",
top: -5,
right: 0,
bottom: 0,
left: 15,
width: 70,
height: 30,
borderRadius: 12,
transform: [{ translateX: translateValue }],
},
]}
/>
<FlatList
data={data}
horizontal={true}
scrollEnabled={true}
renderItem={({ item, index }) => {
return (
<TouchableOpacity onPress={() => onPress(index)}>
<View style={{ width: 100, borderRadius: 10 }}>
<Text style={[{ textAlign: "center" }, index === selected ? { color: "white" } : { color: "black" }]}>
{item.text}
</Text>
</View>
</TouchableOpacity>
)
}}
keyExtractor={(item) => item.id}
/>
</View>
)
}
export default App
Please help, thank you so much
when I run my application it's okay and work If I create an array and put it in the data in FlatList like this array
const photos = [
{ id: 1, title: "Photo 1" },
{ id: 2, title: "Photo 2" },
{ id: 3, title: "Photo 3" },
{ id: 4, title: "Photo 4" },
{ id: 5, title: "Photo 5" },
{ id: 6, title: "Photo 6" },
];
But when I replace the photos array with an API, The app doesn't work. I tried more than API, I think the error is in my code not in the API,
This error appears to me " scrollToIndex out of range: request index1 but maximum is -1 "
What's wrong with my code?
import React, { useState, useRef, useEffect } from "react";
import {
StyleSheet,
View,
FlatList,
Dimensions,
Text,
TouchableOpacity,
} from "react-native";
import { AntDesign } from "#expo/vector-icons";
import axios from "axios";
const phoneWidth = Dimensions.get("screen").width;
const phoneHeight = Dimensions.get("screen").height;
function ScrollScreen() {
const [index, setIndex] = useState(0);
const [border, setBorder] = useState(0);
const refContainer = useRef();
const refBox = useRef();
const [data, setData] = useState([]);
useEffect(() => {
photos();
}, []);
function photos() {
axios
.get("https://jsonplaceholder.typicode.com/photos")
.then(async function (response) {
setData(response.data);
})
.catch((err) => console.error(err));
}
useEffect(() => {
refContainer.current.scrollToIndex({ animated: true, index });
}, [index]);
useEffect(() => {
refBox.current.scrollToIndex({ animated: true, index });
}, [index]);
const theNext = () => {
if (index < photos.length - 1) {
setIndex(index + 1);
setBorder(index + 1);
}
};
const thePrevious = () => {
if (index > 0) {
setIndex(index - 1);
setBorder(index - 1);
}
};
return (
<View style={styles.con}>
<AntDesign
style={[styles.iconConPosition, { left: phoneWidth * 0.05 }]}
onPress={thePrevious}
size={55}
color="#0dddcb"
name="caretleft"
/>
<AntDesign
style={[styles.iconConPosition, { right: phoneWidth * 0.05 }]}
onPress={theNext}
size={55}
color="#0dddcb"
name="caretright"
/>
<FlatList
scrollEnabled={false}
ref={refContainer}
data={data}
// data={photos}
keyExtractor={(item, index) => item.id.toString()}
style={styles.flatList}
renderItem={({ item, index }) => (
<View
style={{
height: 150,
width: phoneWidth * 0.7,
margin: 50,
backgroundColor: "red",
alignSelf: "center",
justifyContent: "center",
alignItems: "center",
}}
>
<Text>{item.id}</Text>
<Text>{item.title}</Text>
</View>
)}
horizontal
pagingEnabled //تفعيل خاصية التمرير
showsHorizontalScrollIndicator={false}
/>
<FlatList
ref={refBox}
data={data}
// data={photos}
keyExtractor={(item, index) => item.id.toString()}
style={styles.flatList}
renderItem={({ item, index }) => (
<TouchableOpacity
onPress={() => {
setIndex(index);
setBorder(index);
}}
style={
border === index
? {
height: 100,
width: phoneWidth * 0.4,
margin: 7,
backgroundColor: "gray",
alignSelf: "center",
justifyContent: "center",
alignItems: "center",
borderWidth: 2,
borderColor: "blue",
}
: {
height: 100,
width: phoneWidth * 0.4,
margin: 7,
backgroundColor: "gray",
alignSelf: "center",
justifyContent: "center",
alignItems: "center",
}
}
>
<Text>{item.id}</Text>
<Text>{item.title}</Text>
</TouchableOpacity>
)}
horizontal
/>
<Text>{index}</Text>
</View>
);
}
export default ScrollScreen;
Initially data is an empty array, but index is set to 0. On the first invocation of the useEffect that tries to scroll, there is an error because scrollToIndex(0) is an error when data is empty, since there is no item for index 0.
Try initializing the border and index state to -1 instead of 0 like:
const [index, setIndex] = useState(-1);
const [border, setBorder] = useState(-1);
On a separate but related note the theNext function has an error, it should be checking data.length instead of photos.length.
Ran into the same issue just now. Using ScrollToOffSet({offset: number, animated: boolean}) instead of scrollToIndex solved the issue for me
I am using react-native-tab-view, and trying to change the indicator width. I would like indicator width to be the same with the tab text. But What I did is just the default. I have tried in many ways, but always it gave me the wrong result. The tab bar should be scrollable horizontally as well. Could you check which part I should change?
This is the expected result :
ShowAllIndex Code :
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: colors.dark,
},
});
const ShowAllIndex = () => {
const { seller } = useSelector((s) => s.auth, shallowEqual);
const [routes] = useState([
{ key: 'best', title: 'BEST' },
{ key: 'jacket', title: '아우터' },
{ key: 'pants', title: '바지' },
{ key: 'skirts', title: '스커트' },
{ key: 'topClothe', title: '원피스' },
{ key: 'one', title: '바지' },
{ key: 'two', title: '스커트' },
{ key: 'three', title: '상의' },
]);
const renderScene = SceneMap({
best: ShowAllMainRoutes,
jacket: JacketRoutes,
pants: PantsRoutes,
skirts: SkirtsRoutes,
topClothe: TopClotheRoutes,
one: ShowAllMainRoutes,
two: JacketRoutes,
three: PantsRoutes,
});
return (
<ScrollView style={[styles.container, { marginTop: Global() }]}>
<CustomTabView
routes={routes}
renderScene={renderScene}
scrollEnabled={true}
tabStyle={{ width: 'auto' }}
showAll={true}
/>
</ScrollView>
);
};
export default ShowAllIndex;
CustomTabView code :
const initialLayout = { width: Dimensions.get('window').width };
const CustomTabView = ({
routes,
renderScene,
numberOfTabs,
indicatorWidth,
scrollEnabled = false,
tabStyle,
showAll,
indicatorStyle,
}) => {
const [index, setIndex] = useState(0);
const renderTabBar = (props) => (
<TabBar
{...props}
scrollEnabled={scrollEnabled}
indicatorStyle={[
indicatorStyle,
{
backgroundColor: colors.barbie_pink,
height: 2.5,
bottom: -1,
},
]}
style={[styles.tabBar]}
renderLabel={({ route, focused }) => {
return (
<Text
style={[styles.label, focused ? styles.activeLabel : styles.label]}
>
{route.title}
</Text>
);
}}
tabStyle={tabStyle}
/>
);
return (
<TabView
navigationState={{ index, routes }}
renderScene={renderScene}
renderTabBar={renderTabBar}
onIndexChange={setIndex}
initialLayout={initialLayout}
style={[styles.container]}
/>
);
};
const styles = StyleSheet.create({
container: {
backgroundColor: colors.dark,
},
scene: {
flex: 1,
marginTop: 5,
},
tabBar: {
backgroundColor: 'transparent',
shadowOpacity: 0,
elevation: 0,
borderBottomWidth: 0.5,
borderColor: colors.very_light_pink_two,
marginBottom: 5,
},
label: {
color: colors.very_light_pink_four,
fontSize: 14,
lineHeight: 20.8,
fontFamily: 'NotoSansCJKkr-Regular',
letterSpacing: -0.35,
},
activeLabel: {
color: colors.barbie_pink,
},
});
Thank you for answers!
Check this solution:
const TAB_MARGIN = 24;
<TabBar
...
scrollEnabled
renderIndicator={indicatorProps => {
const width = indicatorProps.getTabWidth(this.state.index) - TAB_MARGIN
return <TabBarIndicator {...indicatorProps} width={width} />
}}
indicatorStyle={{
backgroundColor: '#333',
height: 4,
left: TAB_MARGIN / 2,
}}
...
/>
I think the prop indicatorStyle in TabBar that can resolves you problem.
You can do the following:
<TabBar
scrollEnabled //add this line to make it scrollable
tabStyle={{width: 100}} //and this one to change the tab width
/>