rdhox / react-native-smooth-picker Goto Github PK
View Code? Open in Web Editor NEWA smooth picker for react-native
License: MIT License
A smooth picker for react-native
License: MIT License
The issue is easy to replicate:
In the example in this repo, remove all cities after "Amsterdam".
initiateScrollToIndex no longer works now. It is not until you scroll that the list jumps to the correct index.
This is how the SmoothPicker initially renders with the below code:
const dataCity = [
"Paris",
"Berlin",
"Lisbonne",
"Budapest",
"Londres",
"Prague",
"Rome",
"Barcelone",
"Amsterdam",
];
const opacities = {
0: 1,
1: 1,
2: 0.6,
3: 0.3,
4: 0.1,
};
const sizeText = {
0: 20,
1: 15,
2: 10,
};
const Item = React.memo(({ opacity, selected, vertical, fontSize, name }) => {
return (
<View
style={[
styles.OptionWrapper,
{
opacity,
borderColor: selected ? "#ABC9AF" : "transparent",
width: vertical ? 190 : "auto",
},
]}>
<Text style={{ fontSize }}>{name}</Text>
</View>
);
});
const ItemToRender = ({ item, index }, indexSelected, vertical) => {
const selected = index === indexSelected;
const gap = Math.abs(index - indexSelected);
let opacity = opacities[gap];
if (gap > 3) {
opacity = opacities[4];
}
let fontSize = sizeText[gap];
if (gap > 1) {
fontSize = sizeText[2];
}
return (
<Item
opacity={opacity}
selected={selected}
vertical={vertical}
fontSize={fontSize}
name={item}
/>
);
};
const Test = () => {
function handleChange(index) {
setSelected(index);
refPicker.current.scrollToIndex({
animated: false,
index: index,
viewOffset: -30,
});
}
const [selected, setSelected] = useState(5);
const refPicker = useRef(null);
return (
<View style={styles.container}>
<View style={styles.wrapperHorizontal}>
<SmoothPicker
initialScrollToIndex={selected}
refFlatList={refPicker}
keyExtractor={(_, index) => index.toString()}
horizontal={true}
scrollAnimation
showsHorizontalScrollIndicator={false}
data={dataCity}
renderItem={(option) => ItemToRender(option, selected, false)}
/>
</View>
<View style={styles.wrapperVertical}>
<SmoothPicker
initialScrollToIndex={selected}
onScrollToIndexFailed={() => {}}
keyExtractor={(_, index) => index.toString()}
showsVerticalScrollIndicator={false}
data={dataCity}
scrollAnimation
onSelected={({ item, index }) => handleChange(index)}
renderItem={(option) => ItemToRender(option, selected, true)}
magnet
/>
</View>
<View>
<Text>{`Your selection is ${dataCity[selected]}`}</Text>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
paddingTop: 60,
paddingBottom: 30,
flex: 1,
flexDirection: "column",
justifyContent: "space-evenly",
alignItems: "center",
backgroundColor: "#F5FCFF",
},
wrapperHorizontal: {
height: 100,
justifyContent: "center",
alignItems: "center",
margin: "auto",
color: "black",
},
wrapperVertical: {
width: 250,
height: 350,
justifyContent: "center",
alignItems: "center",
margin: "auto",
color: "black",
},
OptionWrapper: {
justifyContent: "center",
alignItems: "center",
marginTop: 10,
marginBottom: 10,
paddingTop: 10,
paddingBottom: 10,
paddingLeft: 30,
paddingRight: 30,
height: 50,
borderWidth: 3,
borderRadius: 10,
},
});
export default Test;
After digging through the code a bit, I've found that in _renderItem
in SmoothPicker.js, when there are 11 or more items, this._alignAfterMount()
does run (in the if statement below), while if there are fewer items, it never runs.
So, for a reason I don't understand, when there are 11 or more items, the if/else statement below is run through data.length+1 times, but it is run through only data.length times when there are fewer than 11 items?
if (this.countItems === data.length) {
this.countItems = 0;
this._alignAfterMount();
} else {
this.countItems = this.countItems + 1;
}
Thank you for the package, it works pretty good!
Although, I have one issue - which is a bit frustrating.
initialScrollToIndex newer opens the last item of the array. It just behaves in a weird way.
Setup:
<SmoothPicker
keyExtractor={(_, index) => index.toString()}
showsVerticalScrollIndicator={false}
initialScrollToIndex={dataCity.length - 1}
data={dataCity}
horizontal={true}
scrollAnimation
showsHorizontalScrollIndicator={false}
renderItem={option => ItemToRender(option, selected, true)}
magnet
/>
Hi,
It seems that there is no rtl support. when I try to use the component on rtl the direction of the scroll is the opposite direction from the chosen index. like if I scroll left the chosen one scroll right.
if this could be fixed, it will be great!
Hey there!
When having the scroll picker in a fixed height wrapper (which is in a display flex column container):
If I have a TextInput e.g. underneath the scrollpicker, the values inside always jumping when focusing the TextInput.
Do you knwo how to fix that?
BR, Sebi
Hi,
The component looks excellent and very unusable.
I have a minor request.
I want to also enable picking an item by pressing the item itself.
Now, due to the ref feature in this component, I can use "scrollToIndex" to achieve the aforementioned goal. However, this choice does not affect the internal state of the smooth picker component and thus, when performing the scrollToIndex, the selection does not change.
My request is could you please add a prop which on change changes the selected item/index or could you please a "scrollToIndex" method that can allow to programmatically scroll to the item and perform the internal state change?
Hi,
Iโm having a problem with a horizontal inverted list - initially, all is rendered fine (active option not centered, though) but after a first scroll, the first item looks pulled to the very end of the view.
I would appreciate any help.
Platforms: iOS, Android
react-native-smooth-picker: 1.1.3
https://snack.expo.io/@jullk/horizontal-inverted-list
https://monosnap.com/file/d6IgwxKwj3YTDwcIo2ZxHggA1FUEFC
Following code works fine
const petTypes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
export default class Example extends Component {
constructor(props) {
super(props);
this.state = {
selected: 5
};
}
onPetChange = index => {
this.setState({
selected: index
});
};
render() {
return (
<SmoothPicker
style={{ marginTop: 300 }}
horizontal
initialScrollToIndex={this.state.selected}
keyExtractor={(_, index) => index.toString()}
ref={ref => (this.refPetList = ref)}
showsHorizontalScrollIndicator={false}
bounces={true}
magnet={true}
scrollAnimation
data={petTypes}
onSelected={({ item, index }) => this.onPetChange(index)}
renderItem={({ item, index }) => {
return this.petPickerItem(index, item);
}}
/>
);
}
petPickerItem = (index, item) => {
return <Text style={this.state.selected === index?{color:"red"}:{color: "#000000"}}>{index}</Text>;
};
}
When the input array is reduced by one value to the following
const petTypes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
I'm facing this issue only in release mode that the smooth picker moves uncontrollably in horizontal mode with fast scrolling.
Not able to reproduce this in Debug mode and hence not able to solve it. Scrolling stops abruptly after some time or when I close the App and restart.
"react-native-smooth-picker": "^1.0.2",
<SmoothPicker
initialScrollToIndex={selected}
refFlatList={refPicker}
keyExtractor={(_, index) => index.toString()}
horizontal={true}
scrollAnimation
showsHorizontalScrollIndicator={false}
data={constants.MyArray}
renderItem={option => ItemToRender(option, selected, false)}
onSelected={({ item, index }) => handleChange(index)}
style={{backgroundColor: 'white', paddingLeft: 5, paddingRight: 5}}
/>
function handleChange(index) {
setSelected(index);
refPicker.current.scrollToIndex({
animated: true,
index: index,
viewOffset: -30,
});
}
const ItemToRender = ({item, index}, indexSelected, vertical) => {
const selected = index === indexSelected;
const gap = Math.abs(index - indexSelected);
let opacity = opacities[gap];
if (gap > 3) {
opacity = opacities[4];
}
let fontSize = sizeText[gap];
if (gap > 1) {
fontSize = sizeText[2];
}
return <Item opacity={opacity} selected={selected} vertical={vertical} fontSize={fontSize} name={item}/>;
};
Hello ,
The package is very Good.
Only i'm facing issue for large array data.
I want to use horizontal scroll option for 200 to 250 data.
this is my code
const data = Array.from(Array(250).keys()).slice(100, 250);
<SmoothPicker
initialScrollToIndex={selected}
onScrollToIndexFailed={() => {}}
keyExtractor={(_, index) => Math.random()}
showsHorizontalScrollIndicator={false}
data={data}
scrollAnimation={true}
onSelected={({ item, index }) => handleChange(index,item)}
renderItem={(option) => ItemToRender(option, selected, true)}
magnet
selectOnPress
horizontal
/>
const Item = React.memo(({ opacity, selected, horizontal, fontSize, name }) => {
color = selected ? "#fff" : "#717171";
return (
<View
style={[
styles.OptionWrapper,
{
opacity,
width: horizontal ? 10 : "auto",
backgroundColor: selected ? "#ff9800" : "transparent",
},
]}
>
{selected ? (
) : (
)}
);
});
const ItemToRender = ({ item, index }, indexSelected, horizontal) => {
const selected = index === indexSelected;
const gap = Math.abs(index - indexSelected);
let opacity = opacities[gap];
if (gap > 3) {
opacity = opacities[4];
}
let fontSize = sizeText[gap];
if (gap > 1) {
fontSize = sizeText[2];
}
return (
<Item
opacity={opacity}
selected={selected}
horizontal={horizontal}
fontSize={fontSize}
name={ <View
style={[
{
backgroundColor: '#4c3e5c30' ,
height: 15,
width:0.3,
marginRight: 1
},
]}
><Text>{item}</Text></View>}
/>
);
};
If you have any solution, Please help me.
Thanks
I need to use FlatList from react-native-gesture-handler
for being able to scroll on nested component.
Maybe could be something like this:
import { FlatList } from 'react-native-gesture-handler';
<SmoothPicker
...
flatListComponent={<FlatList />}
/>
I've tried to use the prop initialScrollToIndex
to make the picker select its first item when it is rendered. So I used the following code:
<SmoothPicker
offsetSelection={0}
horizontal={true}
snapInterval={50}
showsHorizontalScrollIndicator={false}
initialScrollToIndex={0}
data={data.map((item, index) => item.text)}
onSelected={({item, index}) => this.handleChangeSelectedItem(index)}
renderItem={({item, index}) => (
<Text
style={index===this.state.selectedIndex ? stylestext_selected : styles.text}
key={item}
>
{item}
</Text>
)}
magnet={true}
scrollAnimation={true}
snapToAlignment={'start'}
/>
Unfortunately, no item in the list is selected, when its rendered first:
Did I make a mistake when using the prop?
I'm having a problem with initialScrollToIndex method, so when my component renders the list should immediately scroll to a certain given index, i was passing that through redux. the behavior i'm getting is that when the component mounts the initialScrollToIndex sometimes works sometimes it doesn't. first i thought its from redux so i simply gave it a static index of 10, though the unstable behavior remains. sometimes it moves sometimes no.
<SmoothPicker
offsetSelection={0}
initialScrollToIndex={initialIndex}
magnet
// scrollAnimation
horizontal
data={result}
activeOpacityButton={0}
keyExtractor={( index) => index.toString()}
onSelected={({ item, index }) => this.handleChange(item, index)}
renderItem={({item,index}) => this.renderScrollItem(item,index)}
/>
When I try to use this component with regular React, I get an error that it's using experimental features. Would it be possible to either not use the experiment features or make another version that's compatible with normal React?
Hello, thanks for this amazing lib!!
I am building an custom date picker from this smooth picker, and it would be a great help if the interface props from SmoothPicker were exported. I would like to create a PR for it.
Hi,
Tried your example to implement smooth scroll when on scrolling found handleChange method throws error which is
TypeError: refPicker.current.scrollToIndex is not a function. (In 'refPicker.current.scrollToIndex({animated: false,index: index,viewOffset: -30})','refPicker.current.scrollToIndex' is undefined).
Also when scrolling values not properly selecting and set in to useState by index. Please suggest what is the issue here and how to fix it.
The implementation examples given is very poor
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.