How to smudge part of a view in React Native? - android

I would like to blur part of an Image wherever user drags his finger, I don't want to blur the whole image. Here is my hacky way of doing blur
I am using #react-native-community/blur for blurring the view
const MyView = () => {
const [locations, setLocation] = useState([]);
const [top, setTop] = useState();
const [left, setLeft] = useState();
return (
<>
<View
style={styles.container}
onTouchEnd={(event) => {
console.log(event.nativeEvent.locationX);
console.log(event.nativeEvent.locationY);
setLocation([
...locations,
{
right: event.nativeEvent.locationX,
bottom: event.nativeEvent.locationY,
top,
left,
},
]);
}}
onTouchStart={(event) => {
console.log('S' + event.nativeEvent.locationX);
console.log('S' + event.nativeEvent.locationY);
setLeft(event.nativeEvent.locationX);
setTop(event.nativeEvent.locationY);
}}>
<ImageBackground
style={{width, height}}
source={{
uri:
'https://images.unsplash.com/photo-1593642634315-48f5414c3ad9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1050&q=80',
}}>
<Text>Hi there </Text>
</ImageBackground>
</View>
{locations.map((l, index) => {
return (
<BlurView
key={index.toString()}
style={{
width: l.right - l.left,
height: l.bottom - l.top,
backgroundColor: 'rgba(0,0,0,0.1)',
position: 'absolute',
top: parseFloat(l.top),
left: parseFloat(l.left),
right: parseFloat(l.right),
bottom: parseFloat(l.bottom),
// blurR,
// opacity: 0.4,
}}
blurType="light"
blurAmount={4}
reducedTransparencyFallbackColor="white"
/>
);
})}
</>);
};
This is a really hacky way of smudging part of an image where user drags his finger. On Android , the application just stops responding as soon as I move my finger on more than two places. Does anyone know a better way to smudge part of view instead of blurring the whole image view where user drags his finger

You can use PanResponder. I developed an example application for you. There is no blurview on expo snack but i guess you can easily convert that sample to what you want. Here is example code:
import React, { useState, useRef } from 'react'
import { StyleSheet, View, ImageBackground, PanResponder, Animated } from 'react-native'
const CIRCLE_RADIUS = 60
const IAmTheBlurComponent = () => {
return (
<View style={[StyleSheet.absoluteFill, { backgroundColor: 'pink', opacity: 0.5 }]}></View>
)
}
const Component = () => {
const [pointers, setPointers] = useState([])
const refs: any = useRef({}).current;
const panResponder = useRef(
PanResponder.create({
onStartShouldSetPanResponder: () => true,
onMoveShouldSetPanResponderCapture: () => true,
onPanResponderStart: (evt) => {
setPointers(evt.nativeEvent.touches.map(touch => touch.identifier))
evt.nativeEvent.touches.forEach((event) => {
refs[event.identifier] = { x: new Animated.Value(event.pageX), y: new Animated.Value(event.pageY) }
})
},
onPanResponderMove: (evt) => {
evt.nativeEvent.touches.forEach((event) => {
refs[event.identifier].x.setValue(event.pageX)
refs[event.identifier].y.setValue(event.pageY)
})
},
onPanResponderEnd: (evt) => {
setPointers(evt.nativeEvent.touches.map(touch => touch.identifier))
},
})
).current
return (
<ImageBackground
style={{
flex: 1,
position: 'relative'
}}
source={{
uri:
'https://images.unsplash.com/photo-1593642634315-48f5414c3ad9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1050&q=80',
}}
{...panResponder.panHandlers}
>
{pointers.map((pnt) => {
return (
<Animated.View
key={pnt}
style={{
overflow: 'hidden',
height: CIRCLE_RADIUS * 2,
width: CIRCLE_RADIUS * 2,
borderRadius: CIRCLE_RADIUS,
position: 'absolute',
transform: [
{
translateX: Animated.subtract(refs[pnt].x, CIRCLE_RADIUS)
},
{
translateY: Animated.subtract(refs[pnt].y, CIRCLE_RADIUS)
}
]
}}
>
<IAmTheBlurComponent />
</Animated.View>
)
})}
</ImageBackground>
)
}
export default function App() {
return (
<View style={styles.container}>
<Component />
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
})
For smooth animations, you can chose Reanimated library. I didnt use ValueXY or similar things, so you can easily convert that sample to reanimated.
This is the sample expo snack: https://snack.expo.io/#kubilaysali/suspicious-ice-cream

Related

ReactNative animation is not working after the api call

here is my code.
const actionButtonsAnimated = new Animated.Value(0);
const animated = new Animated.Value(255);
const animateTrendingCardSheet = () => {
Animated.timing(animated, {
toValue: 0,
duration: 1500,
useNativeDriver: true,
}).start();
Animated.timing(actionButtonsAnimated, {
toValue: -180,
duration: 1000,
useNativeDriver: true,
}).start();
};
<Animated.View
style={[
{
transform: [{ translateY: actionButtonsAnimated }],
},
]}
>
<MainActionButtons />
</Animated.View>
<Animated.View
style={[
{
transform: [{ translateY: animated }],
width: "100%",
position: "absolute",
bottom: 0,
},
]}
>
<View style={styles.trendingCards}>
<Text h5 center color={colors.trendingText}>
Trending in your area...
</Text>
<View style={styles.flatlistWrapper}>
<FlatList
horizontal={true}
data={trendingCards}
renderItem={({ item }) => <TrendingCardComponent card={item} />}
/>
</View>
</View>
</Animated.View>
so if i call the animateTrendingCardSheet function inside useEffect like this.
useEffect(() => {
animateTrendingCardSheet()
}, [])
it works as expected but once i put it in a condition that it should be called after the API call has been finished it does not work at all if i again save the file it hot reload animation works
useEffect(() => {
if (loadTrendingCard) {
animateTrendingCardSheet();
}
}, [loadTrendingCard]);
Your issue is that after the first call to animateTrendingCardSheet the toValue that you are animating to is the current value of your Animated variables; so it looks like nothing is happening. You can counteract this by resetting your animation variables before calling your animation function:
import * as React from 'react';
import {
Text,
View,
StyleSheet,
Animated,
TouchableOpacity,
FlatList,
Button
} from 'react-native';
import Constants from 'expo-constants';
const MainActionButtons = () => {
return (
<View
style={{
flexDirection: 'row',
width: '100%',
justifyContent: 'space-between',
}}>
<TouchableOpacity>Btn 1</TouchableOpacity>
<TouchableOpacity>Btn 2</TouchableOpacity>
<TouchableOpacity>Btn 3</TouchableOpacity>
<TouchableOpacity>Btn 4</TouchableOpacity>
</View>
);
};
const TrendingCardComponent = ({ card }) => {
return (
<View style={{ width: '100%' }}>
<Text>{card.title}</Text>
<Text>{card.message}</Text>
</View>
);
};
const trendingCards = [
{ title: 'A Cool Card', message: 'A cool message' },
{ title: 'Card 1', message: 'A cool message' },
{ title: 'A Cool Card', message: 'A cool message' },
{ title: 'A Cool Card', message: 'A cool message' },
];
const initialActionButton = 0;
const initialAnimated = 255;
export default function App() {
const actionButtonsAnimated = new Animated.Value(initialActionButton);
const animated = new Animated.Value(initialAnimated);
const opacity = new Animated.Value(1)
const onApiCall = ()=>{
// set opacity to 0
Animated.timing(opacity,{toValue:0,duration:500}).start(()=>{
// when view is invisible do resets
animated.setValue(initialAnimated)
actionButtonsAnimated.setValue(initialActionButton)
Animated.timing(opacity,{toValue:1,duration:500}).start()
animateTrendingCardSheet()
})
}
const animateTrendingCardSheet = () => {
Animated.timing(animated, {
toValue: 0,
duration: 1500,
useNativeDriver: true,
}).start();
Animated.timing(actionButtonsAnimated, {
toValue: -180 ,
duration: 1000,
useNativeDriver: true,
}).start();
};
// React.useEffect(() => {
// animateTrendingCardSheet();
// }, []);
return (
<View style={styles.container}>
<Button title="Simulate API call" onPress={onApiCall}/>
<Animated.View
style={[
{
transform: [{ translateY: actionButtonsAnimated }],
opacity
},
]}>
<MainActionButtons />
</Animated.View>
<Animated.View
style={[
{
transform: [{ translateY: animated }],
width: '100%',
position: 'absolute',
bottom: 0,
opacity
},
]}>
<View style={styles.trendingCards}>
<Text>Trending in your area...</Text>
<View style={styles.flatlistWrapper}>
<FlatList
style={{ flex: 1 }}
horizontal={true}
data={trendingCards}
renderItem={({ item }) => <TrendingCardComponent card={item} />}
/>
</View>
</View>
</Animated.View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
flatlistWrapper: {
width: '100%',
height: 200,
},
});
Demo
The above answer is good but it does not solve my problem, its all due to a stupid mistake, the issue was i was setting the state before calling the animation call function, as the state changes and it interfere the animation i had to use useRef like this.
const actionButtonsAnimated = useRef(new Animated.Value(initialActionButton)).current;
const animated = useRef(new Animated.Value(initialAnimated)).current;
it reference the state and animation works as expected.

Bottom sheet is not getting closed in react native android

I am using #gorhom/bottom-sheet library to create my bottomsheet which have some weird behaviour in android devices. I am unable to close or swap top bottom the bottomsheet in android only. Also when keyboard appears this bottomsheet keeps transparent background.
Component
const BottomSheetComponent = (props: BottomSheetComponentProps, ref) => {
const theme = useCustomTheme();
const styles = useMemo(() => makeStyles(theme), [theme]);
const {children, visible, onClose, header, snapPoints = ['70%', '70%'], enablePanDownToClose = true, renderBackdrop = true } = props;
// const bottomSheetRef = useRef<BottomSheet>(null);
const detached = true;
/**
* onClick outside to close bottomsheet
*/
const renderBackdropComponent = useCallback(
props => <BottomSheetBackdrop {...props} />,
[],
);
return (
<Modal visible={visible} transparent>
<BottomSheet
ref={ref}
onClose={onClose}
backdropComponent={renderBackdrop ? renderBackdropComponent : null}
snapPoints={snapPoints}
detached={detached}
enablePanDownToClose={enablePanDownToClose}
keyboardBehavior={'interactive'}
keyboardBlurBehavior={'restore'}
style={styles.container}
handleStyle={styles.handleStyle}
handleIndicatorStyle={styles.indicatorStyle}
>
<View style={styles.contentContainer}>
{header}
{children}
</View>
</BottomSheet>
</Modal>
);
};
export default forwardRef(BottomSheetComponent);
Styles
const makeStyles = (theme: ColorTheme) => StyleSheet.create({
container: {
flex: 1,
backgroundColor: theme.primaryDark,
shadowColor: theme.white,
shadowOffset: {
width: 0,
height: 12
},
shadowOpacity: 0.5,
shadowRadius: 16,
elevation: 24
},
handleStyle: {
backgroundColor: theme.primaryDark,
// borderTopColor: theme.backgroundGrey,
},
indicatorStyle: {
backgroundColor: theme.secondaryGrey,
width: scaleWidth(56),
},
contentContainer: {
flex: 1,
backgroundColor: theme.primaryDark,
},
});
What I tried
I tried to work with gesture handler and reinstalled it in the application but it doesn't seems to work
Your BottomSheet need to be wrapped with gestureHandlerRootHOC
return (
<Modal visible={visible} transparent>
<YourButtomSheet />
</Modal>
)
const YourButtomSheet = gestureHandlerRootHOC((props: Props) => {
...
return (
<BottomSheet
ref={ref}
onClose={onClose}
backdropComponent={renderBackdrop ? renderBackdropComponent : null}
snapPoints={snapPoints}
detached={detached}`enter code here`
enablePanDownToClose={enablePanDownToClose}
keyboardBehavior={'interactive'}
keyboardBlurBehavior={'restore'}
style={styles.container}
handleStyle={styles.handleStyle}
handleIndicatorStyle={styles.indicatorStyle}
>
<View style={styles.contentContainer}>
{header}
{children}
</View>
</BottomSheet>
)
})
export default YourButtomSheet
https://docs.swmansion.com/react-native-gesture-handler/docs/1.10.3/

Creating an AnimatedTextInput causes the keyboard to close immediately

I'm having trouble getting an AnimatedTextInput to work properly where a normal TextInput works properly. When I press the TextInput to start typing, there are no problems, and I can start typing immediately. However, on an AnimatedTextInput, the software keyboard closes immediately.
So, this works just fine:
return (
<View>
<TextInput style={[style, styles.input, { paddingTop: 20, paddingBottom: 20 }]} {...restOfProps} onFocus={() => handleFocus()} onBlur={handleBlur} ref={refInput} />
<Animated.View style={[styles.labelContainer, { opacity: opacity}]}>
<Text style={styles.label}>{label}</Text>
</Animated.View>
</View>
)
However this:
const AnimatedTextInput = Animated.createAnimatedComponent(TextInput)
return (
<View>
<AnimatedTextInput style={[style, styles.input, { paddingTop: paddingTop, paddingBottom: paddingBottom }]} {...restOfProps} onFocus={() => handleFocus()} onBlur={handleBlur} ref={refInput} />
<Animated.View style={[styles.labelContainer, { opacity: opacity}]}>
<Text style={styles.label}>{label}</Text>
</Animated.View>
</View>
)
Immediately causes the software keyboard to quickly open then close when touching the input to gain focus/to start typing. On searching, answers I've seen say this is related to being part of a scrollview, but this happens whether in a scrollview or not.
For reference, here's the entire file:
import React, { useRef } from 'react';
import { Animated, StyleSheet, Text, TextInput, View } from 'react-native';
const styles = StyleSheet.create({
input: {
padding: 24,
borderColor: 'transparent',
borderWidth: 1,
borderRadius: 4,
fontFamily: 'Avenir-Medium',
fontSize: 16,
backgroundColor: '#F8F8F8',
},
labelContainer: {
position: 'absolute',
left: 16,
top: 9,
paddingHorizontal: 8,
},
label: {
color: '#ABB4BD',
fontFamily: 'Avenir-Heavy',
fontSize: 12,
},
})
// extend from native TextInput props
const TextField = (props) => {
const { label, style, ...restOfProps } = props;
const [isFocused, setIsFocused] = React.useState(false);
const opacity = useRef(new Animated.Value(0)).current;
const paddingTop = useRef(new Animated.Value(20)).current;
const paddingBottom = useRef(new Animated.Value(20)).current;
const refInput = useRef();
React.useEffect(() => {
Animated.timing(
paddingBottom,
{
useNativeDriver: false,
toValue: isFocused ? 10 : 20,
duration: 200,
}
).start();
Animated.timing(
paddingTop,
{
useNativeDriver: false,
toValue: isFocused ? 30 : 20,
duration: 200,
}
).start();
Animated.timing(
opacity,
{
useNativeDriver: false,
toValue: isFocused ? 1 : 0,
duration: 200,
}
).start();
}, [isFocused])
const handleFocus = (input) => {
console.log('here')
setIsFocused(true);
}
const handleBlur = () => {
console.log('there')
setIsFocused(false);
}
const AnimatedTextInput = Animated.createAnimatedComponent(TextInput)
return (
<View>
<AnimatedTextInput style={[style, styles.input, { paddingTop: paddingTop, paddingBottom: paddingBottom }]} {...restOfProps} onFocus={() => handleFocus()} onBlur={handleBlur} ref={refInput} />
<Animated.View style={[styles.labelContainer, { opacity: opacity}]}>
<Text style={styles.label}>{label}</Text>
</Animated.View>
</View>
)
};
export default TextField;

How to change react native TouchableOpacity color when pressed

Hello guys so now I'm trying to create to do list application using react native and I'm able to make the user add task. Now I want the user to be able to update the Task status by pressing some button (touchableOpacity). I want the touchableOpacity to change color from red to green (if the task is finished) and turn the color from green to red if the task haven't finished. Can someone help me please ? I want to use state for this. I already prepare some state for it.
Here's my code:
const Task = (props) => {
const[pressed, setPressed] = useState(false);
const onPressHandler = () =>{
setPressed(!pressed);
};
return (
<View style={styles.wrapper}>
<Text style={styles.taskList}>{props.text}</Text>
<TouchableOpacity style={styles.taskStatus} onPress={() => onPressHandler()}>
<Text style={styles.statusText}>On Going</Text>
</TouchableOpacity>
</View>
)
}
Hey instead of using TouchableOpacity You can also use Pressable
<Pressable
style={({ pressed }) => [
{
backgroundColor: pressed
? 'rgb(210, 230, 255)'
: 'white'
},
]}>
<Text style={getTextStyle()}>{text}
</Text>
</Pressable>
ref: https://reactnative.dev/docs/pressable
you can only change activeOpacity property which defaults to 0.2. If you want you Touchable component to tint with some other color, then you will have to create custom TouchableComponent using TouchableHighlight
You can add some inline style your TouchableOpacity by comparing the state
<TouchableOpacity style=[{
backgroundColor: pressed ? 'green' : 'red
}, styles.taskList]
onPress={() => onPressHandler()}
>
<Text style={styles.statusText}>On Going</Text>
</TouchableOpacity >
const Task = (props) => {
const [text, setText] = useState('Update')
const [taskCompleted, setTaskCompleted] = useState(null)
const onPressHandler = () => {
setText('On Going...')
setTimeout(() => {
//Based on your task set status
setText('Success')
setTaskCompleted(true)
//Error sample code
// setText('Error')
// setTaskCompleted(false)
}, 2000)
}
const getTouchableOpacityStyle = () => {
if (taskCompleted === null) {
return styles.touchableOpacityDefaultstyle
}
return taskCompleted ? styles.touchableOpacityStyleOnComplete : styles.touchableOpacityStyleOnError
}
const getTextStyle = () => {
if (taskCompleted === null) {
return styles.textDefaultStyle
}
return styles.textStyleOnTaskExecuted
}
return (
<View style={styles.container}>
<Text>{props.text}</Text>
<TouchableOpacity onPress={onPressHandler} style={getTouchableOpacityStyle()}>
<Text style={getTextStyle()}>{text}</Text>
</TouchableOpacity>
</View>
)
}
const styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center'
},
touchableOpacityDefaultstyle: {
backgroundColor: 'grey',
padding: 10
},
touchableOpacityStyleOnComplete: {
backgroundColor: 'green',
padding: 10
},
touchableOpacityStyleOnError: {
backgroundColor: 'red',
padding: 10
},
textDefaultStyle: {
color: 'black'
},
textStyleOnTaskExecuted: {
color: 'white'
}
})
export default Task

react native - collapse table

I plan to make a collapse table. You can find it in this link
I tried:
Using a Custom Component for column name and FlatList for the first column
Using Section list for the rest column
=============================================================
| _____Custom Component_____ | __________Section list header__________ |
|============================================================|
| _________Flat List___________| __________ Section list body____________|
|============================================================|
I am able to make the list scroll together. However, if the list has 450+ rows, the performance will be reduced dramatically.
Please let me know if you have any solution.
Thank you in advanced!
I found a way to do it. The idea is.
Use Animated.ScrollView to control the horizontal scroll
Use FlatList to control the vertical scroll
When we do horizontal scroll, keep the first element of the FlatList and move the rest of them.
Below is the code:
import React, {Component} from 'react';
import {Animated, FlatList, StyleSheet, Text, View,} from 'react-native';
import * as UIConfig from "../../../../configs/UIConfig";
import * as ColorConfig from "../../../../configs/ColorConfig";
export interface CollapseTableColumnType {
name: string,
accessName: string,
width: number,
visible: boolean,
}
interface CollapseTableType {
normalColumns: Array<CollapseTableColumnType>,
collapseColumns: Array<CollapseTableColumnType>,
data: Array<any>
}
interface State {
scrollX: Animated.Value,
}
class CollapseTable extends Component<CollapseTableType, State> {
// Data
private _scrollView: any = null;
private _flatList: FlatList<any> | null = null;
static defaultProps: CollapseTableType = {
normalColumns: [],
collapseColumns: [],
data: [],
};
state: State = {
scrollX: new Animated.Value(0),
};
private _HEADER_SCROLL_DISTANCE = this.props.collapseColumns.concat(this.props.normalColumns)
.reduce((totalWidth, currentWidth) => currentWidth.width + totalWidth, 0);
private _headerTranslate = this.state.scrollX.interpolate({
inputRange: [0, this._HEADER_SCROLL_DISTANCE],
outputRange: [0, this._HEADER_SCROLL_DISTANCE],
extrapolate: 'clamp',
});
scrollToTop = () => {
if (this._flatList) {
this._flatList.scrollToOffset({ animated: false, offset: 0 });
}
};
scrollToLeft = () => {
if (this._scrollView) {
this._scrollView.getNode().scrollTo({x: 0, y: 0, animated: false});
}
};
render() {
return (
<Animated.ScrollView
ref={(ref: any) => this._scrollView = ref}
style={styles.fill}
horizontal={true}
removeClippedSubviews={true}
showsHorizontalScrollIndicator={false}
scrollEventThrottle={1}
onScroll={Animated.event(
[{nativeEvent: {contentOffset: {x: this.state.scrollX}}}],
{useNativeDriver: true},
)}
>
<FlatList
ref={(ref: any) => this._flatList = ref}
removeClippedSubviews={true}
showsVerticalScrollIndicator={false}
data={this.props.data}
renderItem={this.renderRow}
keyExtractor={(item, index) => 'item_' + index}
stickyHeaderIndices={[0]}
ListHeaderComponent={this.renderHeader}
/>
</Animated.ScrollView>
);
}
renderHeader = () => {
return (
<View style={[styles.cellContainer, {backgroundColor: ColorConfig.PRIMARY_90}]}>
<View style={styles.normalCellContainer}>
{
this.props.normalColumns.map((config, indexConfig) => {
return this.renderCell(
indexConfig,
this.props.normalColumns[indexConfig].width,
this.props.normalColumns[indexConfig].name,
this.props.normalColumns[indexConfig].visible,
);
})
}
</View>
<Animated.View style={[
styles.collapseCellContainer,
{
position: 'absolute',
transform: [{translateX: this._headerTranslate}],
backgroundColor: ColorConfig.PRIMARY_90,
},
]}>
{
this.props.collapseColumns.map((config, indexConfig) => {
return this.renderCell(
indexConfig,
this.props.collapseColumns[indexConfig].width,
this.props.collapseColumns[indexConfig].name,
this.props.collapseColumns[indexConfig].visible,
);
})
}
</Animated.View>
</View>
);
};
renderRow = ({item, index}: { item: any, index: number }) => {
return (
<View key={index} style={styles.cellContainer}>
<View style={styles.normalCellContainer}>
{
this.props.normalColumns.map((config, indexConfig) => {
return this.renderCell(
indexConfig,
this.props.normalColumns[indexConfig].width,
item[this.props.normalColumns[indexConfig].accessName],
this.props.normalColumns[indexConfig].visible,
);
})
}
</View>
<Animated.View style={[
styles.collapseCellContainer,
{
position: 'absolute',
transform: [{translateX: this._headerTranslate}],
backgroundColor: ColorConfig.PRIMARY_97
},
]}>
{
this.props.collapseColumns.map((config, indexConfig) => {
return this.renderCell(
indexConfig,
this.props.collapseColumns[indexConfig].width,
item[this.props.collapseColumns[indexConfig].accessName],
this.props.collapseColumns[indexConfig].visible,
);
})
}
</Animated.View>
</View>
);
};
renderCell = (index: number, width: number, text: string, visible: boolean) => {
return (
<View key={index} style={[styles.cell, {width: width, opacity: visible ? 1 : 0}]}>
<Text style={styles.cellText}>{text}</Text>
</View>
);
};
}
const styles = StyleSheet.create({
fill: {
flex: 1,
},
// Header
cellContainer: {
overflow: 'hidden',
},
normalCellContainer: {
flexDirection: 'row',
},
collapseCellContainer: {
flexDirection: 'row',
},
cell: {
paddingTop: 8 * UIConfig.RATIO,
paddingBottom: 8 * UIConfig.RATIO,
paddingLeft: 8 * UIConfig.RATIO,
paddingRight: 8 * UIConfig.RATIO,
borderRightColor: ColorConfig.PRIMARY_ALPHA_10,
borderRightWidth: UIConfig.RATIO,
borderBottomColor: ColorConfig.PRIMARY_ALPHA_10,
borderBottomWidth: UIConfig.RATIO,
justifyContent: 'center',
alignItems: 'center',
},
cellText: {
textAlign: 'center',
color: ColorConfig.PRIMARY,
fontSize: 14 * UIConfig.RATIO,
}
});
export default CollapseTable;
Hope this answer can help you like it did to me!

Categories

Resources