Related
I have a PrimaryButton element that has 3 variants - primary, secondary and tertiary. As you can see in the style of the Pressable component, I set the default style based on the variant like this styles[variant] . Now I also want to make the backgroundColor of that Pressable component to turn red while it is being pressed if the button variant is tertiary. I already have access to isPressed boolean that tells me if the Pressable is pressed, however, I couldn't figure out how to change the backgroundColor to red only if the variant is tertiary.
const PrimaryButton = ({ title, variant = 'primary', wide = false, style, ...rest }) => {
const width = wide ? '100%' : undefined;
const textColor = variant === 'primary' ? colors.white : colors.primary600;
return (
<Pressable
style={({ pressed: isPressed }) => [
styles.button,
styles[variant],
{
width,
elevation: isPressed ? 5 : 0,
},
style,
]}
{...rest}
>
</Pressable>
);
};
const styles = StyleSheet.create({
button: {
paddingVertical: 12,
paddingHorizontal: 24,
borderRadius: 100,
borderWidth: 1.5,
justifyContent: 'center',
alignItems: 'center',
alignSelf: 'center',
},
primary: {
backgroundColor: colors.primary600,
borderColor: colors.primary600,
},
secondary: {
backgroundColor: colors.white,
borderColor: colors.primary600,
},
tertiary: {
backgroundColor: 'transparent',
borderColor: 'transparent',
},
text: {
textAlign: 'center',
},
});
See if the following helps you. If not please do tell me what went wrong.
style = {({ pressed: isPressed }) => [
styles.button,
styles[variant],
{
width,
elevation: isPressed ? 5 : 0,
...(variant === 'tertiary') ? { backgroundColor: 'red' } : {}
},
style,
]}
check this package, very useful for this stuff.
Styles directly on field level isn't recommended anymore.
https://www.npmjs.com/package/isomorphic-style-loader
Good luck
In order to overwrite a style of a component, in this case, to change the backgroundColor to red only if the variant is tertiary, you can use the ternary operator.
It may be useful to access the defined styles to retrieve the background colors of the other buttons. To do that, you can use StyleSheet.flatten
so that you do not override the previous color style applied.
style = {
({
pressed: isPressed
}) => [
styles.button,
styles[variant],
{
width,
elevation: isPressed ? 5 : 0,
},
{
backgroundColor: isPressed && variant === 'tertiary' ?
'red' :
StyleSheet.flatten(styles[variant]).backgroundColor
},
style,
]
}
As seen in this example.
I'm trying to pass width parameter into StyleSheet like this :
<View style={styles.children(width)}>{children}</View>
And use it like this :
const styles = StyleSheet.create({
modalContent: {
flex: 1,
justifyContent: 'center',
margin: '5%',
},
modalOverlay: {
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
backgroundColor: 'rgba(0,0,0,0.5)',
},
children: (width: any) => ({
width: width,
backgroundColor: 'white',
position: 'absolute',
bottom: 0,
borderTopRightRadius: 40,
borderTopLeftRadius: 40,
paddingVertical: 30,
paddingHorizontal: 20,
}),
});
,
But typescript throws an error This expression is not callable. No constituent of type 'ViewStyle | TextStyle | ImageStyle' is callable.
How can I solve this typescript problem ?
If you want to pass props to stylesheet you have to do something like this
OR
you can use by creating a function which returns ViewStyle
import * as React from "react"
import {View,ViewStyle,StyleSheet} from "react-native"
const App = () => {
return (<View style={Container(width)}></View>)
})
const Container = (width: number | string): ViewStyle => ({
width: width,
height: '50%',
backgroundColor: 'white',
position: 'absolute',
bottom: 0,
borderTopRightRadius: 40,
borderTopLeftRadius: 40,
paddingTop: 10,
paddingHorizontal: 20,
})
I solved the issue implementing it in another way with typescript :
import React, { FC } from "react";
import {
ActivityIndicator,
StyleSheet,
TextStyle,
TouchableOpacity,
ViewStyle,
Platform,
} from "react-native";
import { colors } from "../../styles";
import { fonts } from "../../styles";
import Text from "./Text";
interface ButtonProps {
style?: ViewStyle;
disabled?: boolean | undefined;
onPress?: any;
text?: string;
bordered?: boolean;
textStyle?: TextStyle;
loading?: boolean;
}
const Button: FC<ButtonProps> = ({
style,
disabled,
onPress,
text,
bordered,
textStyle,
loading,
}) => {
const { OS } = Platform;
return (
<TouchableOpacity
activeOpacity={0.6}
disabled={disabled || false}
onPress={onPress}
style={{ ...styles({ disabled, bordered, OS }).button, ...style }}
>
<Text
style={{ ...styles({ disabled, bordered }).buttonText, ...textStyle }}
>
{loading ? <ActivityIndicator color="white" size={30} /> : text}
</Text>
</TouchableOpacity>
);
};
export default Button;
interface StylesProps {
bordered?: boolean;
disabled?: boolean;
OS?: string;
}
interface StyleSheetType {
button: ViewStyle;
buttonText: TextStyle;
}
type StylesFunctionProps = (props: StylesProps) => StyleSheetType;
const styles: StylesFunctionProps = ({ bordered, disabled, OS }) =>
StyleSheet.create<StyleSheetType>({
button: {
borderRadius: OS === "ios" ? 17 : 20,
backgroundColor: disabled ? colors.gray : bordered ? "white" : colors.red,
paddingVertical: 15,
alignItems: "center",
borderWidth: bordered && !disabled ? 1 : 0,
borderColor: colors.red,
},
buttonText: {
fontSize: 20,
// fontFamily: fonts.regular, // light
color: bordered && !disabled ? colors.red : "white",
},
});
I've been trying to build an Image carousel with a bunch of randomly selected images. I wanted to maintain their aspect ratios so I set the resizeMode to 'contain'. Somehow that step leads to the loss of any set borderRadius! What could be the reason? And if that step doesn't work at all, any other ideas on how to maintain the correct aspect ratio + get the corners rounded?
Thanks a lot for your help!
here's the code:
import React, { useCallback, memo, useRef, useState } from "react";
import {
FlatList,
View,
Dimensions,
Text,
StyleSheet,
Image,
} from "react-native";
const images = [
Image1,
Image2,
Image3,
Image4,
Image5,
Image6,
Image7,
Image8,
Image9,
Image10,
Image11,
Image12,
Image13,
Image14,
Image15,
Image16,
Image17,
Image18,
Image19,
Image20,
Image21,
Image22,
Image23,
Image24,
Image25,
Image26,
Image27,
Image28,
Image29,
Image30,
Image31,
Image32,
Image33,
Image34,
Image35,
Image36,
Image37,
Image38,
Image39,
Image40,
Image41,
]
const { width: windowWidth, height: windowHeight } = Dimensions.get("window");
const randomImage = () =>
images[Math.floor(Math.random() * images.length)];
const styles = StyleSheet.create({
slide: {
height: windowHeight,
width: windowWidth,
//justifyContent: "center",
alignItems: "center",
},
slideImage: {
height: '70%',
width: '90%',
borderRadius: 20,
marginTop: 20,
},
slideTitle: {
fontSize: 24,
marginTop: 0,
},
slideSubtitle: {
fontSize: 18,
marginTop: 10,
},
pagination: {
position: "absolute",
bottom: 8,
justifyContent: "center",
flexDirection: "row",
marginBottom: 12
},
paginationDot: {
width: 8,
height: 8,
borderRadius: 4,
marginHorizontal: 2,
},
paginationDotActive: { backgroundColor: "lightblue" },
paginationDotInactive: { backgroundColor: "gray" },
carousel: {},
});
const slideList = Array.from({ length: 999 }).map((_, i) => {
return {
id: i,
image: randomImage,
title: `This is the title ${i + 1}!`,
subtitle: `This is the subtitle ${i + 1}!`,
};
});
const Slide = memo(function Slide({ data }) {
return (
<View style={styles.slide}>
<Image resizeMode = 'contain' source = {randomImage()} style={styles.slideImage}></Image>
<Text style={styles.slideTitle}>{data.title}</Text>
<Text style={styles.slideSubtitle}>{data.subtitle}</Text>
</View>
);
});
function Pagination({ index }) {
return (
<View style={styles.pagination} pointerEvents="none">
{slideList.map((_, i) => {
return (
<View
key={i}
style={[
styles.paginationDot,
index === i
? styles.paginationDotActive
: styles.paginationDotInactive,
]}
/>
);
})}
</View>
);
}
export default function Carousel() {
const [index, setIndex] = useState(0);
const indexRef = useRef(index);
indexRef.current = index;
const onScroll = useCallback((event) => {
const slideSize = event.nativeEvent.layoutMeasurement.width;
const index = event.nativeEvent.contentOffset.x / slideSize;
const roundIndex = Math.round(index);
const distance = Math.abs(roundIndex - index);
// Prevent one pixel triggering setIndex in the middle
// of the transition. With this we have to scroll a bit
// more to trigger the index change.
const isNoMansLand = 0.4 < distance;
if (roundIndex !== indexRef.current && !isNoMansLand) {
setIndex(roundIndex);
}
}, []);
const flatListOptimizationProps = {
initialNumToRender: 0,
maxToRenderPerBatch: 1,
removeClippedSubviews: true,
scrollEventThrottle: 16,
windowSize: 2,
keyExtractor: useCallback(s => String(s.id), []),
getItemLayout: useCallback(
(_, index) => ({
index,
length: windowWidth,
offset: index * windowWidth,
}),
[]
),
};
const renderItem = useCallback(function renderItem({ item }) {
return <Slide data={item} />;
}, []);
return (
<>
<FlatList
data={slideList}
style={styles.carousel}
renderItem={renderItem}
pagingEnabled
horizontal
showsHorizontalScrollIndicator={false}
bounces={false}
onScroll={onScroll}
{...flatListOptimizationProps}
/>
<Pagination index={index}></Pagination>
</>
);
}
``
Actually borderRadius works but you can't see it because of an incorrect ratio.
If your image has a 16:9 ratio, for example, 1600x900 dimensions, then you need to set width and height with the same ratio.
<Image
source={ 1600x900 }
resizeMode="contain"
style={{
width: 300,
height: 300,
borderRadius: 15,
backgroundColor: 'red'
}} />
The result will be:
Because the image has width and height 300, ie 1:1 ratio. If you modify width and height like 320 and 180, ie 16:9, then the image fills all the space and borders will be visible.
Another workaround is to wrap your image with view that hides the overflow
<View
style={{
width: 300,
height: 300,
borderRadius: 150,
overflow: 'hidden',
}}
>
<Image
source={item.image}
style={{
width: 300,
height: 300,
}}
resizeMode='contain'
/>
</View>
I am trying to create an app using react native. Im using expo.
I ve a component named DistList, which should be repeatedly called based on the number of entries from an object. But, the component is not called when used inside a forEach
HomeData.js
import React from 'react';
import { StyleSheet, Text, View, SafeAreaView, Platform, StatusBar, ScrollView, Dimensions } from 'react-native';
import dataCovid from '../store/dataCovid.json'
import DataList from './DataList.js'
import colors from './config/colors.js'
export default class HomeData extends React.Component{
constructor(props) {
super(props);
this.state = {
dataSource : '',
currentTotal : 0,
currentRecovered : 0,
currentDecreased : 0,
currentActive : 0,
}
}
fetchUsers(){
fetch("https://api.covidindiatracker.com/state_data.json")
.then(response => response.json())
.then((responseJson)=> {
this.setState({
loading: false,
dataSource: responseJson
})
})
.catch(error=>console.log(error)) //to catch the errors if any
// console.log(responseJson)
// this.calculateCount();
}
componentDidMount(){
this.fetchUsers();
}
/* componentDidUpdate(){
this.calculateCount();
} */
calculateCount(){
console.log("cc")
// console.log("cclen", this.state.dataSource)
// console.log("cclen", this.state.dataSource.length)
if(this.state.dataSource.length > 0){
let data = /* JSON.stringify( */this.state.dataSource;
// console.log(data)
// if(recoveredResult == 0||decreasedResult == 0||activeResult == 0){
console.log("inside")
// var dataValue = Array.from(data)
// var activeResult = data.map(activeVal => activeVal.active).reduce((nextValue, activeVal) => activeVal + nextValue);
var recoveredResult = data.map(activeVal => activeVal.recovered).reduce((nextValue, activeVal) => activeVal + nextValue);
var decreasedResult = data.map(activeVal => activeVal.deaths).reduce((nextValue, activeVal) => activeVal + nextValue);
var activeResult = data.map(activeVal => activeVal.active).reduce((nextValue, activeVal) => activeVal + nextValue);
var totalResult = recoveredResult+decreasedResult+activeResult;
console.log(recoveredResult)
console.log(decreasedResult)
console.log(activeResult)
this.setState({
currentTotal : totalResult,
currentRecovered : recoveredResult,
currentDecreased : decreasedResult,
currentActive : activeResult,
})
// }
console.log(recoveredResult)
console.log(this.state.currentRecovered)
console.log(this.state.currentDecreased)
console.log(this.state.currentActive)
}
}
handleDataList=()=>{
console.log("asdasd", this.state.dataSource.length)
if(this.state.dataSource.length > 0){
this.state.dataSource.forEach(function(element){
console.log(element);
return (
<View>
<DataList
state={element.state}
recovered={element.recovered}
decreased={element.deaths}
total= {element.confirmed+element.recovered+element.deaths+element.active}
heading={true}
/>
</View>
);
});
}
}
render() {
// console.log("erer", this.state.dataSource)
// console.log("erer", this.state.currentRecovered)
// console.log("erer", JSON.stringify(dataCovid) )
if(this.state.currentActive == 0){
this.calculateCount();
}
return (
<View style={styles.container}>
{/* <ScrollView> */}
<View style={styles.containerTop}>
<View style={styles.totalContainerOne}>
<Text style={[styles.textStyle, styles.textTotal, ]}>Total</Text>
<Text>[{this.state.currentTotal}]</Text>
</View>
<View style={styles.totalContainerTwo}>
<View style={styles.recoveredContainer}>
<Text style={[styles.textStyle, styles.textRecovered, ]}>Recovered</Text>
<Text>[{this.state.currentRecovered}]</Text>
</View>
<View style={styles.decreasedContainer}>
<Text style={[styles.textStyle, styles.textDecreased, ]}>Decreased</Text>
<Text>[{this.state.currentDecreased}]</Text>
</View>
<View style={styles.activeContainer}>
<Text style={[styles.textStyle, styles.textActive, ]}>Active</Text>
<Text>[{this.state.currentActive}]</Text>
</View>
</View>
</View>
<View style={styles.containerBottom}>
<DataList state="State" total="Total" recovered="Recovered" decreased="Decreased" heading={true}/>
<DataList state="State" total="Total" recovered="Recovered" decreased="Decreased" heading={true}/>
{
this.handleDataList()
}
</View>
{/* </ScrollView> */}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
// width : '100%',
// flex: 1,
// height : '100%',
// height: 1500,
// flexDirection : 'row',
// backgroundColor: 'blue',
// alignItems: 'center',
// justifyContent: 'space-evenly',
// marginTop : Platform.OS === 'android' ? StatusBar.currentHeight : 0,
// elevation : 5
},
containerTop: {
// flex: 0.3,
// height : '15%',
height: Dimensions.get('window').height/3,
// flexDirection : 'row',
// backgroundColor: 'blue',
alignItems: 'center',
justifyContent: 'space-evenly',
// marginTop : Platform.OS === 'android' ? StatusBar.currentHeight : 0,
// elevation : 5
},
totalContainerOne: {
height : '45%',
// flex: 0.8,
width : '90%',
backgroundColor: '#eeeeee',
elevation : 20,
alignItems: 'center',
justifyContent: 'center',
borderRadius : 15,
},
textTotal:{
color : colors.totalColor,
},
totalContainerTwo: {
// flex: 0.8,
width : '100%',
height : '45%',
// backgroundColor: 'green',
flexDirection : 'row',
justifyContent : 'space-evenly'
},
recoveredContainer: {
// flex: 1,
width : '30%',
// height : '45%',
backgroundColor: '#eeeeee',
elevation : 50,
alignItems: 'center',
justifyContent: 'center',
borderRadius : 15,
},
textRecovered:{
color : colors.recoveredColor,
},
decreasedContainer: {
// flex: 1,
width : '30%',
// height : '45%',
backgroundColor: '#eeeeee',
elevation : 50,
alignItems: 'center',
justifyContent: 'center',
borderRadius : 15,
},
textDecreased:{
color : colors.decreasedColor,
},
activeContainer: {
// flex: 1,
width : '30%',
// height : '45%',
backgroundColor: '#eeeeee',
elevation : 50,
alignItems: 'center',
justifyContent: 'center',
borderRadius : 15,
},
textActive:{
color : colors.activeColor,
},
textStyle:{
fontSize : 18,
fontWeight : '700',
},
containerBottom: {
paddingTop : 10,
// flex: 0.4,
// height:'85%',
// flexDirection : 'row',
// backgroundColor: 'blue',
alignItems: 'center',
justifyContent: 'space-evenly',
// marginTop : Platform.OS === 'android' ? StatusBar.currentHeight : 0,
// elevation : 5
},
});
DataList.js
import React from 'react';
import { StyleSheet, Text, View, SafeAreaView, Platform, StatusBar, ScrollView, Dimensions } from 'react-native';
import dataCovid from '../store/dataCovid.json'
import colors from './config/colors.js'
export default class DataList extends React.Component{
constructor(props) {
super(props);
this.state = {
}
}
render() {
const {state, total, recovered, decreased, heading} = this.props;
const testStyle = (heading)? styles.testHeadingStyle : styles.dataStyle
return (
<View style={styles.container}>
<View style={styles.stateBox}>
<Text style={testStyle}>{state}</Text>
</View>
<View style={styles.stateBox}>
<Text style={testStyle}>{total}</Text>
</View>
<View style={styles.stateBox}>
<Text style={testStyle}>{recovered}</Text>
</View>
<View style={styles.stateBox}>
<Text style={testStyle}>{decreased}</Text>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
width : '100%',
flex: 1,
// height : '100%',
// height: 1500,
flexDirection : 'row',
// backgroundColor: 'blue',
alignItems: 'center',
justifyContent: 'space-evenly',
// marginTop : Platform.OS === 'android' ? StatusBar.currentHeight : 0,
// elevation : 5
},
stateBox:{
height : 30,
width : 87,
backgroundColor : '#f6f6f7',
borderRadius : 5,
// top : 5,
justifyContent : 'center',
// alignItems : 'center',
elevation : 5,
textAlign : 'left',
paddingLeft : 5,
},
testHeadingStyle:{
fontSize : 15,
fontWeight : '700',
color : '#6c757d',
textShadowColor: 'rgba(0, 0, 0, 0.50)',
textShadowOffset: {width: -1, height: 1},
textShadowRadius: 10,
},
dataStyle:{
fontSize : 15,
fontWeight : '700',
color : '#6c757d',
// textShadowColor: 'rgba(0, 0, 0, 0.50)',
// textShadowOffset: {width: -1, height: 1},
// textShadowRadius: 10,
}
});
I am using this function handleDataList() to call the DistList.js component in forEach. But calling component is not working here. Can someone assist please.
{
this.handleDataList()
}
You can do this, a function inside a render, and it will render whatever the function will return, which can be some html snippet or a component.
However you need to make sure that handleDataList() returns something
handleDataList=()=>{
console.log("asdasd", this.state.dataSource.length)
if(this.state.dataSource.length > 0){
this.state.dataSource.forEach(function(element){
console.log(element);
return (
<View>
<DataList
state={element.state}
recovered={element.recovered}
decreased={element.deaths}
total= {element.confirmed+element.recovered+element.deaths+element.active}
heading={true}
/>
</View>
);
});
}
}
this will return undefined.
You may think it will return
return (
<View>
<DataList
state={element.state}
recovered={element.recovered}
decreased={element.deaths}
total= {element.confirmed+element.recovered+element.deaths+element.active}
heading={true}
/>
</View>
);
but it doesn't, because this return is the return of the forEach function callback, but that's not going to affect handleDataList at all.
handleDataList=()=>{
console.log("asdasd", this.state.dataSource.length)
if(this.state.dataSource.length > 0){
return this.state.dataSource.map(function(element){
console.log(element);
return (
<View>
<DataList
state={element.state}
recovered={element.recovered}
decreased={element.deaths}
total= {element.confirmed+element.recovered+element.deaths+element.active}
heading={true}
/>
</View>
);
});
}
}
should return.
Description
I am working on a react-native project using expo SDK36.
I want to do a swipe left/right list view. I use react-native-swipe-list-view to achieve it.
So far everything worked perfectly, the default example uses a fixed height: 50 per row, while I want to set the height of each row dynamically.
Every attempt where a failure, note that I already use <SwipeListView recalculateHiddenLayout={true} />
This is bad for the UX, since the default line is having a small height: 50, it is nearly impossible to drag the line on iOS and android properly.
Reproduction
Snack: https://snack.expo.io/#kopax/react-native-swipe-list-view-408
import React from 'react';
import { Dimensions, Text, View, StyleSheet } from 'react-native';
import Constants from 'expo-constants';
// You can import from local files
import SwipeListView from './components/SwipeListView';
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.paragraph}>
Change code in the editor and watch it change on your phone! Save to get a shareable url.
</Text>
<Card>
<SwipeListView
dimensions={Dimensions.get('window')}
listViewData={Array(20).fill('').map((d, i) => ({
...d,
title: `Item ${i}`,
description: `This is a very long description for item number #${i},
it should be so long that you cannot see all the content,
the issue is about fixing the dynamic height for each row`
}))
}
minHeight={200}
/>
</Card>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
});
This is my components/SwipeListView.js
import React, { Component } from 'react';
import {
Animated,
Image,
StyleSheet,
TouchableOpacity,
TouchableHighlight,
View,
} from 'react-native';
import {
Avatar,
Button,
Text,
Title,
Subheading,
TouchableRipple,
withTheme,
} from 'react-native-paper';
import { SwipeListView as SwipeListViewDefault } from 'react-native-swipe-list-view';
/* eslint-disable react/prop-types, react/destructuring-assignment, react/no-access-state-in-setstate */
class SwipeListView extends Component {
leftBtnRatio = 0.25;
rightBtnRatio = 0.75;
constructor(props) {
super(props);
this.state = {
listType: 'FlatList',
listViewData: props.listViewData
.map((data, i) => ({ key: `${i}`, ...data })),
};
this.rowTranslateAnimatedValues = {};
props.listViewData
.forEach((data, i) => {
this.rowTranslateAnimatedValues[`${i}`] = new Animated.Value(1);
});
}
getStyles() {
const { minHeight, theme } = this.props;
const { colors } = theme;
return StyleSheet.create({
rowFrontContainer: {
overflow: 'hidden',
},
rowFront: {
alignItems: 'center',
backgroundColor: colors.surface,
borderBottomColor: colors.accent,
borderBottomWidth: 1,
justifyContent: 'center',
minHeight: '100%',
flex: 1,
},
rowBack: {
alignItems: 'center',
backgroundColor: colors.surface,
flexDirection: 'row',
justifyContent: 'space-between',
paddingLeft: 15,
minHeight: '100%',
},
backBtn: {
alignItems: 'center',
bottom: 0,
justifyContent: 'center',
position: 'absolute',
top: 0,
},
backLeftBtn: {
backgroundColor: colors.primary,
left: 0,
width: `${this.leftBtnRatio * 100}%`,
},
backRightBtn: {
backgroundColor: colors.accent,
right: 0,
width: `${this.rightBtnRatio * 100}%`,
},
});
}
onRowDidOpen = (rowKey) => {
console.log('This row opened', rowKey);
};
onSwipeValueChange = swipeData => {
const { dimensions } = this.props;
const { key, value } = swipeData;
if (value < -dimensions.width * this.rightBtnRatio && !this.animationIsRunning) {
this.animationIsRunning = true;
Animated.timing(this.rowTranslateAnimatedValues[key], {
toValue: 0,
duration: 200,
}).start(() => {
const newData = [...this.state.listViewData];
const prevIndex = this.state.listViewData.findIndex(item => item.key === key);
newData.splice(prevIndex, 1);
this.setState({listViewData: newData});
this.animationIsRunning = false;
});
}
};
closeRow(rowMap, rowKey) {
if (rowMap[rowKey]) {
rowMap[rowKey].closeRow();
}
}
deleteRow(rowMap, rowKey) {
this.closeRow(rowMap, rowKey);
const newData = [...this.state.listViewData];
const prevIndex = this.state.listViewData.findIndex(
(item) => item.key === rowKey,
);
newData.splice(prevIndex, 1);
this.setState({ listViewData: newData });
}
render() {
const { minHeight, dimensions, theme } = this.props;
const { colors } = theme;
const styles = this.getStyles();
return (
<SwipeListViewDefault
data={this.state.listViewData}
renderItem={data => (
<Animated.View
style={[styles.rowFrontContainer, {
height: this.rowTranslateAnimatedValues[data.item.key].interpolate({
inputRange: [0, 1],
outputRange: [0, minHeight],
})}]}
>
<TouchableRipple
onPress={() => console.log('You touched me')}
style={styles.rowFront}
underlayColor={colors.background}
>
<View>
<Title>{data.item.title}</Title>
<Text>
{data.item.description}
</Text>
</View>
</TouchableRipple>
</Animated.View>
)}
renderHiddenItem={(data, rowMap) => (
<View style={styles.rowBack}>
<TouchableOpacity
style={[
styles.backLeftBtn,
styles.backBtn,
]}
onPress={() => this.closeRow(rowMap, data.item.key)}
>
<Text>Tap pour annuler</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.backRightBtn,
styles.backBtn,
]}
onPress={() => this.deleteRow(rowMap, data.item.key)}
>
<Animated.View
style={[
styles.trash,
{
transform: [
{
scale: this.rowTranslateAnimatedValues[
data.item.key
].interpolate({
inputRange: [
45,
90,
],
outputRange: [0, 1],
extrapolate:
'clamp',
}),
},
],
},
]}
>
<Text>Swipe left to delete</Text>
</Animated.View>
</TouchableOpacity>
</View>
)}
leftOpenValue={dimensions.width * this.leftBtnRatio}
rightOpenValue={-dimensions.width * this.rightBtnRatio}
previewRowKey={'0'}
previewOpenValue={-40}
previewOpenDelay={3000}
onRowDidOpen={this.onRowDidOpen}
onSwipeValueChange={this.onSwipeValueChange}
recalculateHiddenLayout={true}
/>
);
}
}
export default withTheme(SwipeListView);
Expect
I expect when using recalculateHiddenLayout={true}, to get the hidden row height calculated dynamically
Result Screenshots
On the web, I am able to set the height:
but I when using iOS and Android, the height is forced.
Environment
OS: ios/android/web
RN Version: expo SDK36
How can I set the height of each row dynamically?
Important edit
The problem is the fixed value here in the animation:
height: this.rowTranslateAnimatedValues[data.item.key].interpolate({
inputRange: [0, 1],
outputRange: [0, 200], // <--- here
})}]}
I have replaced it in the example with props.minHeight:
height: this.rowTranslateAnimatedValues[data.item.key].interpolate({
inputRange: [0, 1],
outputRange: [0, this.props.minHeight],
})}]}
It doesn't permit dynamic height, how can I get the row height dynamically?