react-native-sortable-list
react-native-sortable-list copied to clipboard
programmatically sortable list
Im trying to "simulate" tap of user but without tap on item.. for example when I make timeout and change order so it will make the effect of the sort. I tried this way but it's not make any animation, it's only render the list
import React, { Component } from 'react';
import {
Animated,
Easing,
StyleSheet,
Text,
Image,
View,
Dimensions,
Platform,
} from 'react-native';
import SortableList from 'react-native-sortable-list';
const window = Dimensions.get('window');
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
data: {
0: {
image: 'https://placekitten.com/200/240',
text: 'Chloe',
},
1: {
image: 'https://placekitten.com/200/201',
text: 'Jasper',
},
2: {
image: 'https://placekitten.com/200/202',
text: 'Pepper',
},
3: {
image: 'https://placekitten.com/200/203',
text: 'Oscar',
},
4: {
image: 'https://placekitten.com/200/204',
text: 'Dusty',
},
5: {
image: 'https://placekitten.com/200/205',
text: 'Spooky',
},
6: {
image: 'https://placekitten.com/200/210',
text: 'Kiki',
},
7: {
image: 'https://placekitten.com/200/215',
text: 'Smokey',
},
8: {
image: 'https://placekitten.com/200/220',
text: 'Gizmo',
},
9: {
image: 'https://placekitten.com/220/239',
text: 'Kitty',
},
}
}
}
componentDidMount() {
setTimeout(() => {
let data2 = {
2: {
image: 'https://placekitten.com/200/240',
text: 'Chloe',
},
1: {
image: 'https://placekitten.com/200/201',
text: 'Jasper',
},
0: {
image: 'https://placekitten.com/200/202',
text: 'Pepper',
},
3: {
image: 'https://placekitten.com/200/203',
text: 'Oscar',
},
4: {
image: 'https://placekitten.com/200/204',
text: 'Dusty',
},
5: {
image: 'https://placekitten.com/200/205',
text: 'Spooky',
},
6: {
image: 'https://placekitten.com/200/210',
text: 'Kiki',
},
7: {
image: 'https://placekitten.com/200/215',
text: 'Smokey',
},
8: {
image: 'https://placekitten.com/200/220',
text: 'Gizmo',
},
9: {
image: 'https://placekitten.com/220/239',
text: 'Kitty',
},
}
this.setState({data:data2})
}, 3000);
}
render() {
return (
<View style={styles.container}>
<Text style={styles.title}>React Native Sortable List</Text>
<SortableList
style={styles.list}
contentContainerStyle={styles.contentContainer}
data={this.state.data}
renderRow={this._renderRow} />
</View>
);
}
_renderRow = ({ data, active }) => {
return <Row data={data} active={active} />
}
}
class Row extends Component {
constructor(props) {
super(props);
this._active = new Animated.Value(0);
this._style = {
...Platform.select({
ios: {
transform: [{
scale: this._active.interpolate({
inputRange: [0, 1],
outputRange: [1, 1.1],
}),
}],
shadowRadius: this._active.interpolate({
inputRange: [0, 1],
outputRange: [2, 10],
}),
},
android: {
transform: [{
scale: this._active.interpolate({
inputRange: [0, 1],
outputRange: [1, 1.07],
}),
}],
elevation: this._active.interpolate({
inputRange: [0, 1],
outputRange: [2, 6],
}),
},
})
};
}
componentWillReceiveProps(nextProps) {
if (this.props.active !== nextProps.active) {
Animated.timing(this._active, {
duration: 300,
easing: Easing.bounce,
toValue: Number(nextProps.active),
}).start();
}
}
render() {
const { data, active } = this.props;
return (
<Animated.View style={[
styles.row,
this._style,
]}>
<Image source={{ uri: data.image }} style={styles.image} />
<Text style={styles.text}>{data.text}</Text>
</Animated.View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#eee',
...Platform.select({
ios: {
paddingTop: 20,
},
}),
},
title: {
fontSize: 20,
paddingVertical: 20,
color: '#999999',
},
list: {
flex: 1,
width: window.width,
},
contentContainer: {
...Platform.select({
ios: {
paddingVertical: 30,
},
android: {
paddingVertical: 0,
}
})
},
row: {
flexDirection: 'column',
alignItems: 'center',
backgroundColor: '#fff',
padding: 16,
width: 110,
height: 150,
marginHorizontal: 10,
borderRadius: 4,
margin: 10,
...Platform.select({
ios: {
shadowColor: 'rgba(0,0,0,0.2)',
shadowOpacity: 1,
shadowOffset: { height: 2, width: 2 },
shadowRadius: 2,
},
android: {
elevation: 0,
marginHorizontal: 30,
},
})
},
image: {
width: 50,
height: 50,
marginBottom: 15,
borderRadius: 25,
},
text: {
fontSize: 18,
color: '#222222',
},
});
@adirzoari
As the docs states, you can pass order array as follows:
componentDidMount() { setTimeout(() => { const order = [2, 1, 9, 7, 3, 0, 8, 4, 5, 6]; this.setState({order}) }, 3000); } render() { return ( <View style={styles.container}> <SortableList style={styles.list} contentContainerStyle={styles.contentContainer} data={this.state.data} order={this.state.order} renderRow={this._renderRow} /> </View> ); }
@bureyburey thanks, that's exactly what I'm looking for!
@adirzoari 🤘
@bureyburey Im trying to make something like that. I changed sortingEnabled to false, each row is button, when user press on button then it takes the row to change it to first in the list.. my problem is how to pass function props for <SortableList .../> to the child(each row) when the user tab on button than it change the new order.. part of my example
<SortableList
sortingEnabled={false}
style={style.list}
contentContainerStyle={style.contentContainer}
data={this.state.data}
renderRow={this._renderRow}
order={this.state.order}
/* pass any function for example
onPressToChangeOrder = {()=>{ make functionality to make new order}}
*/
/>
each row
`class Row extends Component {
constructor(props) {
super(props)
this.state = {
checked_id: -1,
}
this._active = new Animated.Value(0)
this._style = {
...Platform.select({
ios: {
transform: [
{
scale: this._active.interpolate({
inputRange: [0, 1],
outputRange: [1, 1.1],
}),
},
],
shadowRadius: this._active.interpolate({
inputRange: [0, 1],
outputRange: [2, 10],
}),
},
android: {
transform: [
{
scale: this._active.interpolate({
inputRange: [0, 1],
outputRange: [1, 1.07],
}),
},
],
elevation: this._active.interpolate({
inputRange: [0, 1],
outputRange: [2, 6],
}),
},
}),
}
}
componentWillReceiveProps(nextProps) {
if (this.props.active !== nextProps.active) {
Animated.timing(this._active, {
duration: 300,
easing: Easing.bounce,
toValue: Number(nextProps.active),
}).start()
}
}
render() {
const { data, active } = this.props
console.log('data', data)
if (!data) return null
return (
<Animated.View style={[style.row, this._style]} active={active}>
<Button
style={style.view_item}
onPress={() => {
this.setState({ checked_id: data.id })
/* call to new order
this.props.onPressToChangeOrder()
*/
}}
>
<View>
<CheckBox
checked_id={this.state.checked_id}
id={data.id}
icon={'md-checkmark'}
checked={data.checked}
onPress={id => {
console.log('pressed again')
this.chooseItem(id)
}}
disabled={false}
/>
</View>
<View />
<View>
<Text style={style.text_item}>{data.text}</Text>
</View>
</Button>
</Animated.View>
)
}
}
`
@adirzoari
You tried passing onPressRow function as prop to SortableList?
From the docs:
onPressRow? (function) (key) => void Called when a row was pressed.
yes,it's not working nothing is printing.
{this.state.data && Object.keys(this.state.data).length > 0 && (
<SortableList
style={style.list}
contentContainerStyle={style.contentContainer}
data={this.state.data}
renderRow={this._renderRow}
order={this.state.order}
onPressRow={() => {
console.log('press row')
}}
/* pass any function for example
onPressToChangeOrder = {()=>{ make functionality to make new order}}
*/
/>
)}
Do the props in the row render function has onPress function?
it works only when sortingEnabled = {true}.. but I don't want the user will have option to sort.
Do the props in the row render function has onPress function?
no.. how to pass it?
row component
class Row extends Component {
constructor(props) {
super(props)
this.state = {
checked_id: -1,
}
this._active = new Animated.Value(0)
this._style = {
...Platform.select({
ios: {
transform: [
{
scale: this._active.interpolate({
inputRange: [0, 1],
outputRange: [1, 1.1],
}),
},
],
shadowRadius: this._active.interpolate({
inputRange: [0, 1],
outputRange: [2, 10],
}),
},
android: {
transform: [
{
scale: this._active.interpolate({
inputRange: [0, 1],
outputRange: [1, 1.07],
}),
},
],
elevation: this._active.interpolate({
inputRange: [0, 1],
outputRange: [2, 6],
}),
},
}),
}
}
componentWillReceiveProps(nextProps) {
if (this.props.active !== nextProps.active) {
Animated.timing(this._active, {
duration: 300,
easing: Easing.bounce,
toValue: Number(nextProps.active),
}).start()
}
}
render() {
const { data, active } = this.props
console.log('data', data)
if (!data) return null
return (
<Animated.View style={[this._style, style.view_item]} active={active}>
<Button
style={style.view_item}
onPress={() => {
// this.setState({ checked_id: data.id })
/* call to new order
this.props.onPressToChangeOrder()
*/
}}
>
<View>
<CheckBox
checked_id={this.state.checked_id}
id={data.id}
icon={'md-checkmark'}
checked={data.checked}
onPress={id => {
console.log('pressed again')
this.chooseItem(id)
}}
disabled={false}
/>
</View>
<View />
<View>
<Text style={style.text_item}>{data.text}</Text>
</View>
</Button>
</Animated.View>
)
}
}
Do the props in the row render function has onPress function?
no.. how to pass it?
Nevermind, my bad. The onPressRow should suffice
it works only when sortingEnabled={true} and when I remove button so this way
` <Animated.View style={[this._style, style.view_item]} active={active}>
<View>
<CheckBox
checked_id={this.state.checked_id}
id={data.id}
icon={'md-checkmark'}
checked={data.checked}
onPress={id => {
console.log('pressed again')
this.chooseItem(id)
}}
disabled={false}
/>
</View>
<View />
<View>
<Text style={style.text_item}>{data.text}</Text>
</View>
</Animated.View>
)
}`
but it's not what I'm looking for... I don't want user have option to sort..
@adirzoari try this:
<SortableList style={styles.list} contentContainerStyle={styles.contentContainer} data={this.state.data} renderRow={this._renderRow} order={this.state.order} sortingEnabled={true} manuallyActivateRows={true} onPressRow={(key) => { this.setState({order: [key, ...Object.keys(this.state.data).filter((i) => i != key)]}) }} />
- the ordering could use some more work on it .....
but in my case I want sortingEnabled={false} because I don't want user change order by sort it.
@adirzoari in my attempt to re-create it you cannot re-organize by dragging, only by clicking on a row will it move to the top https://snack.expo.io/rJIMsvQEN
@bureyburey Awesome!!! that's exactly what I want! thank your for your time! I appreciate!
@adirzoari Glad i could help :)
is there any way to make separator between each item? like in flatlist
Add view with border? Or border on the Row component?
umm sounds good.. thanks. you can close this issue
last thing, in row class, can i know what the key press? because i want to make when i press on view(not in checkbox) so it change checkbox style.
The key is passed to the renderRow function, so just pass it along to the Row component
_renderRow = ({ data, active, key }) => { return <Row data={data} active={active} key={key}/> }
I mean to the chosen row key. for example if I press on item num 3 so I want only the checkbox or item num 3 will be active (without press on checkbox button)