Interpolate is not a function react native - javascript

I follow video at the link https://www.youtube.com/watch?v=YE7c6ch2msY and try do it.
But when I add animated interpolate it show error " interpolate is not a function"
Here is my code
import * as React from 'react';
import { StatusBar, Animated, Text, Image, View, StyleSheet, Dimensions, FlatList } from 'react-native';
import { TouchableOpacity } from 'react-native-gesture-handler';
const { width, height } = Dimensions.get('screen');
const Indicator = ({ scrollX }) => {
return (
<View style={{ position: 'absolute', bottom: 100, flexDirection: 'row' }}>
{DATA.map((_, i) => {
const inputRange =[(i-1) * width, i* width, (i+1)* width];
const scale = scrollX.interpolate({
inputRange,
outputRange:[0.8,1.4,0.8],
extrapolate:'clamp',
})
return <View key={`indicatot-${i}`}
style={{
height: 10,
width: 10,
borderRadius: 5,
backgroundColor: '#333',
margin: 10
}} />
})}
</View>
)
}
export default function App() {
const scrollX = React.useRef(new Animated.Value(0)).current;
return (
<View style={styles.container}>
<StatusBar hidden />
<Animated.FlatList
...
renderItem={({ item }) => {
return (
...
)
}}>
</Animated.FlatList>
<Indicator scrollX={{ scrollX }} />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
I can see type of scrollX is any, is not Animted.Value
How I can fix it?

It's just a little typo, you're putting double brackets when passing down the scrollX
<Indicator scrollX={{ scrollX }} />
This means you're passing an object with a property scrollX, just remove one set of brackets scrollX={ scrollX }

Related

How to move label along with slider value in React Native

I am working on a React Native Project, I want to move the label along with the slider value. I tried many ways but its not working accurately.
Here is my code:
import React, { useState } from 'react'
import { Text, StyleSheet, View, Dimensions } from 'react-native'
import Slider from '#react-native-community/slider';
function LabelSlider() {
const windowWidth = Dimensions.get('window').width;
const [value, setValue] = useState(0)
// const left = value * (windowWidth-60)/85;
const [showValue, setShowValue] = useState(false)
//var percent = (percentToGet / 100) * number;
return (
<View>
{showValue ?
<View >
<Text style={{ width:50, textAlign: 'auto', left: value}}>{value}</Text>
</View> :
<></>}
<Slider
style={{ width: 200, height: 40 }}
maximumValue={300}
minimumValue={0}
step={1}
value={value}
onValueChange={(value) => setValue(value)}
onSlidingStart={() => setShowValue(true)}
onSlidingComplete={() => setShowValue(true)}
minimumTrackTintColor="#FFFFFF"
maximumTrackTintColor="#000000"
/>
</View>
)
}
export { LabelSlider }
I have also attached two images of the output I was able to get:
Image 1,
Image 2
You can use a shared value and interpolate the left position for the label.
Right now what happens is, that the left value goes from 0 to 300. This makes the label unresponsive. You can do something as shown below.
Also, here's a Snack for the implementation.
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import Slider from '#react-native-community/slider';
import Animated, {
useSharedValue,
useAnimatedStyle,
interpolate,
Extrapolate,
} from 'react-native-reanimated';
// Constants
const MAX_SLIDER_VALUE = 300;
const MIN_SLIDER_VALUE = 0;
const SLIDER_WIDTH = 200;
export default function App() {
// State to store progress value of slider
const [value, setValue] = React.useState(0);
// Shared value for storing label position
const progress = useSharedValue(0);
// Whenever `value` changes, update the progress shared value
// This will accordingly update the left position of the label
React.useEffect(() => {
progress.value = value;
}, [value]);
// Animate the left position according to the shared value
// Also Extrapolate it so that it doesn't exceed 100%
const animatedStyle = useAnimatedStyle(() => {
const leftPosition = interpolate(
progress.value,
[MIN_SLIDER_VALUE, MAX_SLIDER_VALUE],
[0, 100],
Extrapolate.CLAMP
);
return {
left: `${leftPosition}%`,
};
});
return (
<View style={styles.container}>
<View style={{ width: SLIDER_WIDTH }}>
<Animated.View style={[styles.labelView, animatedStyle]}>
<Text>{value}</Text>
</Animated.View>
<Slider
style={{ width: SLIDER_WIDTH, height: 40 }}
maximumValue={MAX_SLIDER_VALUE}
minimumValue={MIN_SLIDER_VALUE}
step={1}
value={value}
onValueChange={setValue}
minimumTrackTintColor="#FFFFFF"
maximumTrackTintColor="#000000"
/>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#ecf0f1',
padding: 8,
},
labelView: {
marginBottom: 20,
},
});
You can use react native element slider for this, I have given the example code below
import React from 'react';
import { View } from 'react-native';
import {Slider} from 'react-native-elements';
const App = () => {
return (
<View
style={{
flex: 1,
justifyContent: "center",
}}>
<Slider
thumbStyle={{height: 15, width: 15, backgroundColor: 'orange'}}
maximumTrackTintColor="grey"
minimumTrackTintColor="orange"
thumbProps={{
children: (
<View
style={{
color: 'green',
marginTop: -22,
width: 100,
}}>
<Text>Value</Text>
</View>
),
}}
/>
</View>
)
}
export default App;

How to create custom dropdown list in react-native?

I almost consume 17 hours, but the answers on what I have searched did not satisfy the exact answer to my question,
how to create own custom DropdownList in react native? I already did, the 1st child node which is DropDown (cyan) is work properly, the 2nd child node which is the the List (green) with absolute position but it was not work properly, unless the root parent (red) will also covered the 2nd child node with absolute position, to make it active and clickable, as like what I mention from the picture, Figure 1.0
I set absolute position of the List (green) to make it float from the next child node and the error was persist, the List(parent) was disabled and it cannot click each child items (yellow), unless I set height of the root parent (red) that covered the entire child node but it leads to the next node to adjust the position and do the unexpected layout, like the sample picture Figure 1.1
I DID IT!, the problem is the root parent (red) must not have customized styled property, and I still have one questions, I dont know if it is bug or what, once I did not put any custom property in the style of root parent it works properly, and here is my source code
App.js
import React, { useState } from 'react';
import Separator from './Separator';
import Spinner from './Spinner';
import {
View,
Text,
TouchableOpacity
} from 'react-native';
export default function () {
const [spBusiness, setSPBusiness] = useState({
showList: false,
selectedItem: ''
})
const onShowList = () => {
if (spBusiness.showList) {
setSPBusiness(prev => ({
...prev,
showList: false
}))
}
else {
setSPBusiness(prev => ({
...prev,
showList: true
}))
}
}
const onSelectItem = (item, index) => {
setSPBusiness(prev => ({
showList: false,
selectedItem: item
}));
}
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#fff' }}>
<Box text='Rectangle 1' onPress={() => console.log('Rect 1')} />
<Separator vertical={1} />
<Spinner
placeholder='Select Item'
items={['A', 'B', 'C']}
isListShow={spBusiness.showList}
selectedItem={spBusiness.selectedItem}
onShowList={onShowList}
onSelectItem={onSelectItem}
/>
<Separator vertical={1} />
<Box text='Rectangle 2' onPress={() => console.log('Rect 2')} />
<Separator vertical={1} />
</View>
)
}
const Box = props => (
<TouchableOpacity onPress={props.onPress} style={{ zIndex: -1, borderRadius: 7.5, width: 250, height: 45, justifyContent: 'center', alignItems: 'center', backgroundColor: '#242424' }}>
<Text style={{ color: '#fff' }}>{props.text}</Text>
</TouchableOpacity>
)
DropDownList/index.js
import React from 'react';
import styles from './style';
import AIcon from 'react-native-vector-icons/AntDesign';
import {
View,
Text,
Dimensions,
TouchableOpacity,
ScrollView
} from 'react-native';
import Separator from '../Separator';
export default function (props) {
const { items } = props;
const { width, height } = Dimensions.get('window');
const size = size => (size / 100) * width;
const hp = hp => (hp / 100) * height;
const wp = wp => (wp / 100) * width;
return (
<View>
{/* here is the root parent with empty style property*/}
<TouchableOpacity
style={styles.skin}
activeOpacity={0.75}
onPress={props.onShowList}
>
<View style={styles.body}>
<View style={styles.upperBodyPane}>
</View>
<View style={styles.centerBodyPane}>
{props.selectedItem.length === 0 &&
<Text>{props.placeholder}</Text>
}
{props.selectedItem.length !== 0 &&
<Text>{props.selectedItem}</Text>
}
<AIcon name='caretdown' size={size(3.5)} color='#242424' />
</View>
</View>
</TouchableOpacity>
{props.isListShow &&
<ScrollView
style={styles.list}
contentContainerStyle={styles.listContainer}
>
{
items.map((item, index) => (
<View key={index}>
<Item
item={item}
onPress={() => props.onSelectItem(item, index)}
/>
{items.length !== (index + 1) ? <Separator vertical={0.5} /> : null}
</View>
))
}
</ScrollView>
}
</View>
)
}
const Item = props => (
<TouchableOpacity style={styles.item} onPress={props.onPress}>
<Text style={styles.itemText}>{props.item}</Text>
</TouchableOpacity>
)
DropDownList/style.js
import {
Dimensions,
StyleSheet
} from 'react-native';
const { width, height } = Dimensions.get('window');
const size = size => (size / 100) * width;
const hp = hp => (hp / 100) * height;
const wp = wp => (wp / 100) * width;
export default StyleSheet.create({
skin: {
minWidth: wp(70),
height: hp(5.5),
paddingHorizontal: wp(6),
justifyContent: 'center',
backgroundColor: 'cyan',
position: 'relative'
},
body: {
},
centerBodyPane: {
alignItems: 'center',
flexDirection: 'row',
justifyContent: 'space-between',
},
item: {
height: hp(5),
paddingHorizontal: wp(5),
justifyContent: 'center',
backgroundColor: 'orange',
},
itemText: {
color: 'white'
},
list: {
top: hp(6.5),
width: wp(70),
maxHeight: hp(15),
backgroundColor: 'green',
position: 'absolute',
},
listContainer: {
padding: size(1.75),
}
})
but the worse case only, I need to set the next child node of DropDownList to zIndex: -1 , but it finally works.

Use percentage/relative values in Styling of <View /> on iOS in react-native

I want to do something like this in react-native
<View
style = { width: '100%', padding: 10, borderRadius: '25%' }>
{...}
</View>
But I get (on iOS)
JSON value '25%' of type NSString cannot be converted to NSNumber
Is there a way to use relative/percentage values as styling input for borderRadius?
You can do something like that, use ref in order to have a reference to that element, then you can measure its width (not in percentage) and you can calculate the border radius.
import React, { useRef, useEffect, useState } from 'react';
import { Text, View, StyleSheet } from 'react-native';
export default function App() {
const ref = useRef();
const [width, setWidth] = useState(0);
useEffect(() => {
ref.current.measure((x, y, w, h) => {
setWidth(w);
});
}, []);
return (
<View style={styles.container}>
<View
ref={ref}
style={{
width: '80%',
padding: 10,
backgroundColor: 'red',
borderRadius: width / 4, // 25%
}}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
Okay, after a quick researching, i found that borderRadius style expects number as a value, not a String
So if you want to custom the value of borderRadius, you can do sth like this:
<View style={{
width: 300,
height: 300,
backgroundColor: 'red',
padding: 10,
borderRadius: 300/4 // equal 25% of its size
}}>

React Native: Touchable Opacity element is clickable on iOS but not Android

I'm working on a React Native app with a typeahead component. The typeahead displays options that overlay other content on the route (see right image below). When a user clicks one of those options, an onPress listener runs a function:
This all works just fine on iOS. On Android though, the onPress event is never received. Even more strangely, when I try to click on an option lower in the list (like Boston, MA, USA), the onPress event is received by the card below the pressed option (Djerba).
Does anyone know what might cause this behavior? I'd be super grateful for any insights others can offer on this query.
Here's the code for the Explore view and the typeahead components.
Explore.js
import React from 'react'
import { connect } from 'react-redux'
import { Text, View, ScrollView, TouchableOpacity } from 'react-native'
import { gradients, sizing } from '../../style'
import { LinearGradient } from 'expo-linear-gradient'
import { MountainHero } from '../Heros'
import { CardRow } from '../Card'
import Loading from '../Loading'
import { setExploreSearch, onExploreTypeaheadClick } from '../../actions/locations'
import { Typeahead } from '../Typeahead'
const styles = {
container: {
flex: 1,
flexDirection: 'column',
},
scrollView: {
paddingBottom: sizing.margin,
},
loadingContainer: {
position: 'absolute',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
zIndex: 100,
elevation: 100,
top: 53,
width: '100%',
},
typeahead: {
margin: sizing.margin,
marginBottom: 0,
width: sizing.screen.width - (2*sizing.margin),
zIndex: 100,
elevation: 100,
}
}
const Explore = props => {
const { authenticated: a, spotlight, loading } = props;
let r = (a.recommendedLocations || []);
if (!r || !spotlight) return null;
// remove spotlight locations from the recommended locations
const ids = spotlight.map(i => i.guid);
const recommended = r.filter(i => ids.indexOf(i.guid) == -1);
return (
<LinearGradient style={styles.container} colors={gradients.teal}>
<ScrollView contentContainerStyle={styles.scrollView}>
{loading && (
<View style={styles.loadingContainer}>
<Loading />
</View>
)}
<MountainHero text='Explore' />
<Typeahead
style={styles.typeahead}
placeholder='Search Cities'
value={props.exploreSearch}
onChange={props.setExploreSearch}
vals={props.exploreTypeahead}
valKey={'place_id'}
onTypeaheadClick={props.onExploreTypeaheadClick}
/>
<CardRow
text='Explore Places'
cards={recommended}
type='location' />
<CardRow
text='In the Spotlight'
cards={spotlight}
type='location' />
</ScrollView>
</LinearGradient>
)
}
const mapStateToProps = state => ({
authenticated: state.users.authenticated,
spotlight: state.locations.spotlight,
exploreSearch: state.locations.exploreSearch,
exploreTypeahead: state.locations.exploreTypeahead,
loading: state.locations.loading,
})
const mapDispatchToProps = dispatch => ({
setExploreSearch: s => dispatch(setExploreSearch(s)),
onExploreTypeaheadClick: val => dispatch(onExploreTypeaheadClick(val)),
})
export default connect(mapStateToProps, mapDispatchToProps)(Explore)
Typeahead.js
import React from 'react'
import { Text, View, TouchableOpacity } from 'react-native'
import { sizing, GradientInput } from '../style'
const styles = {
container: {
position: 'absolute',
zIndex: 100,
elevation: 100,
height: 400,
width: '100%',
},
input: {
width: '100%',
borderRadius: 0,
},
typeaheadContainer: {
position: 'absolute',
zIndex: 100,
elevation: 100,
top: 55,
width: '100%',
},
typeaheadRow: {
padding: 10,
paddingTop: 12,
paddingBottom: 12,
borderWidth: 1,
borderColor: '#eeeeee',
backgroundColor: '#ffffff',
marginBottom: -1,
},
typeaheadRowText: {
fontSize: 15,
fontFamily: 'open-sans',
lineHeight: 20,
backgroundColor: '#ffffff',
},
}
export const Typeahead = props => {
return (
<View style={[props.container, props.style]}>
<GradientInput style={styles.input}
placeholder={props.placeholder}
value={props.value}
onChange={props.onChange} />
<TypeaheadList vals={props.vals}
valKey={props.valKey}
onTypeaheadClick={props.onTypeaheadClick} />
</View>
)
}
export const TypeaheadList = props => {
if (!props.vals) return null;
return (
<View style={styles.typeaheadContainer}>
{props.vals.map(i => {
let text = i.text;
if (text.length > 31) text = text.substring(0,31) + '...';
return (
<TouchableOpacity activeOpacity={0.5} key={i[props.valKey]}
style={styles.typeaheadRow}
onPress={() => props.onTypeaheadClick(i[props.valKey])}>
<Text numberOfLines={1} style={styles.typeaheadRowText}>{text}</Text>
</TouchableOpacity>
)
})}
</View>
)
}
export default Typeahead
Try to move Typeahead component below all CardRow components and set position:absolute for Typeahead. Probably on android - the latest view shadow all views before (I am not sure, but I think you have to try it for next discovering issue).
You should also remove position: absolute from all but one component. Working code:
Explore.js
import React from 'react'
import { connect } from 'react-redux'
import { Text, View, ScrollView, TouchableOpacity } from 'react-native'
import { gradients, sizing } from '../../style'
import { LinearGradient } from 'expo-linear-gradient'
import { MountainHero } from '../Heros'
import { CardRow } from '../Card'
import Loading from '../Loading'
import { setExploreSearch, onExploreTypeaheadClick } from '../../actions/locations'
import { Typeahead } from '../Typeahead'
const styles = {
container: {
flex: 1,
flexDirection: 'column',
},
scrollView: {
paddingBottom: sizing.margin,
},
loadingContainer: {
position: 'absolute',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
zIndex: 1,
elevation: 1,
top: 53,
width: '100%',
},
topCardRow: {
paddingTop: sizing.margin + sizing.gradientInput.height,
},
typeahead: {
margin: sizing.margin,
marginBottom: 0,
width: sizing.screen.width - (2*sizing.margin),
zIndex: 1,
elevation: 1,
position: 'absolute',
top: sizing.mountainHero.height,
left: 0,
}
}
const Explore = props => {
const { authenticated: a, spotlight, loading } = props;
let r = (a.recommendedLocations || []);
if (!r || !spotlight) return null;
// remove spotlight locations from the recommended locations
const ids = spotlight.map(i => i.guid);
const recommended = r.filter(i => ids.indexOf(i.guid) == -1);
return (
<LinearGradient style={styles.container} colors={gradients.teal}>
<ScrollView contentContainerStyle={styles.scrollView}>
{loading && (
<View style={styles.loadingContainer}>
<Loading />
</View>
)}
<MountainHero text='Explore' />
<CardRow
style={styles.topCardRow}
text='Explore Places'
cards={recommended}
type='location' />
<CardRow
text='In the Spotlight'
cards={spotlight}
type='location' />
<Typeahead
style={styles.typeahead}
placeholder='Search Cities'
value={props.exploreSearch}
onChange={props.setExploreSearch}
vals={props.exploreTypeahead}
valKey={'place_id'}
onTypeaheadClick={props.onExploreTypeaheadClick}
/>
</ScrollView>
</LinearGradient>
)
}
const mapStateToProps = state => ({
authenticated: state.users.authenticated,
spotlight: state.locations.spotlight,
exploreSearch: state.locations.exploreSearch,
exploreTypeahead: state.locations.exploreTypeahead,
loading: state.locations.loading,
})
const mapDispatchToProps = dispatch => ({
setExploreSearch: s => dispatch(setExploreSearch(s)),
onExploreTypeaheadClick: val => dispatch(onExploreTypeaheadClick(val)),
})
export default connect(mapStateToProps, mapDispatchToProps)(Explore)
Typeahead.js
import React from 'react'
import { Text, View, TouchableOpacity } from 'react-native'
import { sizing, GradientInput } from '../style'
const styles = {
container: {
zIndex: 1,
elevation: 1,
height: 400,
width: '100%',
},
input: {
width: '100%',
borderRadius: 0,
},
typeaheadContainer: {
zIndex: 1,
elevation: 1,
top: 0,
width: '100%',
},
typeaheadRow: {
padding: 10,
paddingTop: 12,
paddingBottom: 12,
borderWidth: 1,
borderColor: '#eeeeee',
backgroundColor: '#ffffff',
marginBottom: -1,
zIndex: 1,
elevation: 1,
},
typeaheadRowText: {
fontSize: 15,
fontFamily: 'open-sans',
lineHeight: 20,
backgroundColor: '#ffffff',
},
}
export const Typeahead = props => {
return (
<View style={[props.container, props.style]}>
<GradientInput style={styles.input}
placeholder={props.placeholder}
value={props.value}
onChange={props.onChange} />
<TypeaheadList vals={props.vals}
valKey={props.valKey}
onTypeaheadClick={props.onTypeaheadClick} />
</View>
)
}
export const TypeaheadList = props => {
if (!props.vals) return null;
return (
<View style={styles.typeaheadContainer}>
{props.vals.map(i => {
let text = i.text;
if (text.length > 31) text = text.substring(0,31) + '...';
return (
<TouchableOpacity activeOpacity={0.5} key={i[props.valKey]}
style={styles.typeaheadRow}
onPress={() => props.onTypeaheadClick(i[props.valKey])}>
<Text numberOfLines={1} style={styles.typeaheadRowText}>{text}</Text>
</TouchableOpacity>
)
})}
</View>
)
}
export default Typeahead

Styling reusable components in React-Native

I made a reusable component Button.js and I'm importing it on two different screens. The button looks the same, but on the first screen I need it to be position: 'absolute' and on the second one position: 'relative' (the default).
How do I add the position to be absolute on the first screen? I tried to add the styling on FirstPage.js but it does not work. How do I overwrite the style that is defined in Button.js?
Button.js:
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
const Button = ({ position, onPress, children }) => {
const { buttonStyle, textStyle } = styles;
return (
<TouchableOpacity onPress={onPress} style={buttonStyle, {'position': position}}>
<Text style={textStyle}>{children}</Text>
</TouchableOpacity>
);
};
Button.defaultProps = {
position: 'relative',
}
const styles = {
textStyle: {
alignSelf: 'center',
color: '#F44336',
fontSize: 16,
},
buttonStyle: {
zIndex: 2,
width: 100,
backgroundColor: '#FFF',
}
};
export { Button };
You can pass props, something like this (Button.js) (edited according to posted code):
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
const Button = ({ position, onPress, children }) => {
const { buttonStyle, textStyle } = styles;
const style = {...buttonStyle, position };
return (
<TouchableOpacity onPress={onPress} style={style}>
<Text style={textStyle}>{children}</Text>
</TouchableOpacity>
);
};
Button.defaultProps = {
position: 'relative',
}
const styles = {
textStyle: {
alignSelf: 'center',
color: '#F44336',
fontSize: 16,
},
buttonStyle: {
zIndex: 2,
width: 100,
backgroundColor: '#FFF',
}
};
export { Button };
Your button of course looks different, this is just an outline of what you could do (basically just using props).
This is REUSABLE Button as touchableOpacity.
export const NormalThemeButton = (props) => {
return (
<TouchableOpacity
style={[{ ...props.style, ...styles.normalThemeBtn }]}
style={[{ alignItems: props.align }, styles.anchor]}
onPress={props.onPress} >
<CustomText text={props.text} l bold style={{
textAlign: 'center',
color: theme['blackColor']
}} />
{props.children}
</TouchableOpacity >
);
};
This is where this RESUABLE Button is been used.
style={{ ...styles.openArrivedButton }}
text={Lng.instance.translate('useWaze')}
onPress={() => { Waze() }}/>
Hope You find it helpful.

Categories