Open teryi opened 3 years ago
Can you share sample code?
Below is the code, the scroll keep offset to top when i change the checkbox state. Is there any other solutions?
import React, {Component} from "react";
import {Dimensions, TouchableOpacity} from "react-native";
import {RecyclerListView, DataProvider, LayoutProvider} from "recyclerlistview";
import {View, Body, Grid, Icon, ListItem, Right, Row, Button} from "native-base";
import Colors from "../constants/Colors";
import {TextInput} from "react-native-paper";
import {Text} from '../components/Themed';
import {useNavigation} from "@react-navigation/native";
const ViewTypes = {
FULL: 0,
HALF_LEFT: 1,
HALF_RIGHT: 2
};
export default function RecycleTestComponent(props) {
const navigation = useNavigation();
const {mode, isShowCheckbox, data} = props;
const [selected_leave, set_selected_leave] = React.useState([]);
let dataProviderTemplate = new DataProvider((r1, r2) => {
return r1 !== r2;
});
console.log(data)
const [dataProvider, setDataProvider] = React.useState(dataProviderTemplate.cloneWithRows(data));
React.useEffect(() => {
set_selected_leave([])
}, [isShowCheckbox])
const isChecked = (itemId) => {
const isThere = selected_leave.includes(itemId);
return isThere;
};
const pressItem = ({leave_item}) => {
if (!isShowCheckbox) {
navigation.navigate('LeaveApprovalDetailScreen', {
mode: mode,
leave_item: leave_item,
})
} else {
if (selected_leave.includes(leave_item.leave_appl_group_id)) {
set_selected_leave(selected_leave.filter(item => item !== leave_item.leave_appl_group_id));
} else {
set_selected_leave(prevState => [...prevState, leave_item.leave_appl_group_id])
}
}
}
let {width} = Dimensions.get("window");
const _layoutProvider = new LayoutProvider(
index => {
return ViewTypes.FULL;
},
(type, dim) => {
dim.width = width;
dim.height = 180;
}
);
const _rowRenderer = React.useCallback((type, leave_item) => {
if (leave_item) {
let attachment_arr = []
for (var i = 0; i < leave_item.leave_attachment.length; i++) {
attachment_arr = attachment_arr.concat(leave_item.leave_attachment[i]);
}
return (
<TouchableOpacity onPress={() => pressItem({leave_item})}>
<View noIndent style={{
width: Dimensions.get("window").width,
padding: 10,
height:180,
flexDirection: 'row',
borderBottomColor: Colors.lightgrey,
borderBottomWidth: 1,
backgroundColor: (isChecked(leave_item.leave_appl_group_id)) ? Colors.lightgrey : null
}}
key={leave_item.leave_appl_group_id}
>
{/*Left*/}
<View style={{flex: 1, justifyContent: 'center', alignContent: 'center',}}>
<Row>
<View style={{
borderRadius: 4,
backgroundColor: leave_status_color(leave_item.leave_status),
padding: 4,
height: 24
}}>
<Text style={{
fontSize: 12,
color: Colors.milk_white,
fontWeight: "bold"
}}>{leave_item.leave_status_label}</Text>
</View>
</Row>
<Row>
<Text ellipsizeMode={'tail'} style={{fontSize: 14}}><Text
style={{
fontWeight: 'bold',
color: Colors.darkblue
}}>{leave_item.employee_no} {leave_item.employee_name} </Text> </Text>
</Row>
<Row>
<Text ellipsizeMode={'tail'} numberOfLines={1} style={{
fontSize: 14,
fontWeight: 'bold',
color: Colors.darkgrey
}}>({leave_item.leave_code}) - {leave_item.leave_name}
</Text>
</Row>
<Row style={{marginBottom: 4}}>
<View style={{
borderRadius: 4,
borderWidth: 0.5,
borderColor: Colors.grey,
padding: 5,
height: 26
}}>
<Text style={{
fontSize: 12,
color: Colors.darkgrey,
fontWeight: 'bold'
}}>{leave_item.leave_start}</Text>
</View>
<View style={{justifyContent: 'center'}}><Text
style={{
fontSize: 12,
color: Colors.darkgrey
}}> until </Text></View>
<View style={{
borderRadius: 4,
borderWidth: 0.5,
borderColor: Colors.grey,
padding: 5,
height: 26
}}>
<Text style={{
fontSize: 12,
color: Colors.darkgrey,
fontWeight: 'bold'
}}>{leave_item.leave_end}</Text>
</View>
</Row>
<Row>
<View style={{
borderRadius: 4,
backgroundColor: Colors.blue,
padding: 4,
height: 24
}}>
<Text style={{
fontSize: 12,
color: Colors.milk_white,
fontWeight: "bold",
}}>{leave_item.interval_format}</Text>
</View>
</Row>
<Row style={{marginTop: 4}}>
{
(attachment_arr.length > 0) ?
<View style={{alignSelf: 'center'}}>
<Icon type={'AntDesign'} name={'paperclip'}
style={{
fontSize: 18,
padding: 2,
color: Colors.blue,
}}/>
</View>
: null
}
{
(parseInt(leave_item.leave_emergency) == 1) ?
<View style={{
borderRadius: 4,
backgroundColor: Colors.red,
padding: 4,
height: 24,
marginRight: 4,
marginTop: 4
}}>
<Text style={{
fontSize: 12,
color: Colors.milk_white,
fontWeight: "bold"
}}>Emergency</Text>
</View>
: null
}
{
(parseInt(leave_item.leave_advance) == 1) ?
<View style={{
borderRadius: 4,
backgroundColor: Colors.darkgrey,
padding: 4,
height: 24,
marginRight: 4,
marginTop: 4
}}>
<Text style={{
fontSize: 12,
color: Colors.milk_white,
fontWeight: "bold"
}}>Advance</Text>
</View>
: null
}
</Row>
</View>
{/*Right*/}
<View style={{width: 30}}>
<Row>
<View>
<Text><Icon type="MaterialCommunityIcons"
name={(isChecked(leave_item.leave_appl_group_id)) ? "checkbox-marked" : "checkbox-blank-outline"}
style={{color: Colors.darkgrey}}/></Text>
</View>
</Row>
<Row>
<View style={{
alignItems: 'center',
alignContent: 'center',
justifyContent: 'center',
width: 30,
height: 30,
backgroundColor: Colors.blue,
borderRadius: 4,
}}>
<Icon type={'Ionicons'} name={'md-chatbox-sharp'}
style={{
fontSize: 20,
color: Colors.milk_white,
}}/>
</View>
</Row>
</View>
</View>
</TouchableOpacity>
)
}
}, [selected_leave])
return <RecyclerListView forceNonDeterministicRendering={true} layoutProvider={_layoutProvider}
dataProvider={dataProvider}
rowRenderer={_rowRenderer}/>;
}
const leave_status_color = (leave_status) => {
switch (parseInt(leave_status)) {
case 3:
case 7:
case 8:
return Colors.orange
break;
case 5:
return Colors.red
break;
default:
return Colors.blue
}
}
I have the same issue.. when I modify local state, it messes up the scroll index and also the dynamic heights if I use forceDeterministicRendering and don't set a dim.height on the cells..
I had the same issue, but I managed to resolve it with the answers I find in here: issue-493 From what I see in your code, you should useState even for layout provider, not only for data.
After hours of bumping my head against the wall and trying everything possible, I was finally able to fix the issue. The problem most people are facing is when updating a value in their data via state causing a complete rerender.
After creating your layoutProvider disable the Undocumented shouldRefreshWithAnchoring
property:
_layoutProvider.shouldRefreshWithAnchoring = false;
I had the jumping issue because I have to recreate layoutProvider on rerender because If I don't, when I insert or move items, they take up wrong type and render into wrong component. I rewrote code multiple times, rewrote it as a class component etc but it would always jump to the start of top most item because shouldRefreshWithAnchoring
means that when a rerender occurs, list should scroll to first visible item in the list even if it is 1px
in View.
Here's what happened when I used a fixed layoutProvider that never changed:
Before Render: type section -> section header type note -> note type note -> note type section -> section header
After rerender and changing item(Pin a note to top of list): type section -> note type note -> note type note -> section header type section -> note
This won't be a problem for you if all your items are of the same type and you can keep a fixed layoutProvider created once.
Another note that I am using Functional Components. I read somewhere that you should not recreate the layoutProvider but when I do that, on removing or moving items, they are rendered in a wrong types. For example a note
would render in place of section
. Hope this helps you and saves you some time.
Finally I think this is a great library but lacks when it comes to proper documentation. I even watched a couple of videos on it too which again only showed static list items rendered using a generator function which doesn't help
After hours of bumping my head against the wall and trying everything possible, I was finally able to fix the issue. The problem most people are facing is when updating a value in their data via state causing a complete rerender.
After creating your layoutProvider disable the Undocumented
shouldRefreshWithAnchoring
property:_layoutProvider.shouldRefreshWithAnchoring = false;
I had the jumping issue because I have to recreate layoutProvider on rerender because If I don't, when I insert or move items, they take up wrong type and render into wrong component. I rewrote code multiple times, rewrote it as a class component etc but it would always jump to the start of top most item because
shouldRefreshWithAnchoring
means that when a rerender occurs, list should scroll to first visible item in the list even if it is1px
in View.Here's what happened when I used a fixed layoutProvider that never changed:
Before Render: type section -> section header type note -> note type note -> note type section -> section header
After rerender and changing item(Pin a note to top of list): type section -> note type note -> note type note -> section header type section -> note
This won't be a problem for you if all your items are of the same type and you can keep a fixed layoutProvider created once.
Another note that I am using Functional Components. I read somewhere that you should not recreate the layoutProvider but when I do that, on removing or moving items, they are rendered in a wrong types. For example a
note
would render in place ofsection
. Hope this helps you and saves you some time.Finally I think this is a great library but lacks when it comes to proper documentation. I even watched a couple of videos on it too which again only showed static list items rendered using a generator function which doesn't help
worked for me. you save my day. thanks
Currently i face an issue whereby the scroll not preserve but jump to previous few item offset when re-render the view