Updated to latest code

This commit is contained in:
bartonstee
2020-12-21 09:18:57 +01:00
committed by GitHub
parent f7cc6eecb4
commit 5400e77f9e
15 changed files with 21220 additions and 199 deletions

155
src/CustomListView.tsx Normal file
View File

@@ -0,0 +1,155 @@
import { PureComponent, ReactNode, createElement, createRef } from "react";
import { View, FlatList, ScrollView, TouchableOpacity, Text, ViewStyle } from "react-native";
import { ObjectItem } from "mendix";
import { Big } from "big.js"
import { CustomListViewProps } from "../typings/CustomListViewProps"
import { Style, mergeNativeStyles } from '@mendix/pluggable-widgets-tools';
let clickTimer: number;
export interface CustomStyle extends Style {
footer: ViewStyle
}
const defaultStyle: CustomStyle = {
footer: {
marginBottom: 300,
}
};
interface State {
clickDisabled?: boolean;
scrollIndex: number;
}
export class CustomListView extends PureComponent<CustomListViewProps<CustomStyle>, State> {
private readonly styles = mergeNativeStyles(defaultStyle, this.props.style);
constructor(props: CustomListViewProps<CustomStyle>) {
super(props)
this.state = {
clickDisabled: false,
scrollIndex: Number(this.props.scrollItem?.displayValue),
}
}
renderFlatListHandler = this.renderFlatList.bind(this);
renderScrollViewHandler = this.renderScrollView.bind(this);
onClickHandler = this.onClick.bind(this);
renderEmptyHandler = this.renderEmpty.bind(this);
renderFooterHandler = this.renderFooter.bind(this);
flatListRef = createRef<FlatList<any>>();
render(): ReactNode {
const { scrollView } = this.props;
return (
<View>{scrollView ? <this.renderScrollViewHandler /> : <this.renderFlatListHandler />}</View>
)
}
renderFlatList() {
const { ds, windowSize, initialNumToRender, removeClippedSubviews, maxNumberToRenderPerBatch, cellBatchingSize, useItemLayout, itemSize } = this.props;
const size = Number(itemSize)
return (
<View>
{useItemLayout ?
<FlatList
getItemLayout={(data, index) => ({
length: size,
offset: size * index,
index,
data
})}
ref={this.flatListRef}
data={ds?.items}
renderItem={this.renderItem}
windowSize={windowSize}
initialNumToRender={initialNumToRender}
removeClippedSubviews={removeClippedSubviews}
ListEmptyComponent={this.renderEmptyHandler()}
maxToRenderPerBatch={maxNumberToRenderPerBatch}
ListFooterComponent={this.renderFooterHandler()}
/>
:
<FlatList
data={ds?.items}
renderItem={this.renderItem}
windowSize={windowSize}
initialNumToRender={initialNumToRender}
removeClippedSubviews={removeClippedSubviews}
ListEmptyComponent={this.renderEmptyHandler()}
maxToRenderPerBatch={maxNumberToRenderPerBatch}
ListFooterComponent={this.renderFooterHandler()}
updateCellsBatchingPeriod={cellBatchingSize}
/>
}
</View>
);
}
renderScrollView() {
const { ds, container } = this.props;
return (
<View>
<ScrollView>
{ds.items?.map((item) => <View key={item.id}>{container(item)}</View>)}
</ScrollView>
</View>
);
}
renderItem = ({ item, index }: { item: ObjectItem, index: number }) => {
const { container, useItemLayout, itemSize } = this.props;
return (
<View>
<TouchableOpacity onPress={() => this.onClickHandler(item, index)} disabled={this.state.clickDisabled}>
<View key={item.id} style={useItemLayout ? { height: Number(itemSize) } : null}>{container(item)}</View>
</TouchableOpacity>
</View>
)
}
renderFooter() {
return <View style={this.styles.footer}></View>
}
scrollToOffset = (index: number) => {
const { itemSize } = this.props
this.flatListRef.current?.scrollToOffset({ animated: true, offset: index * Number(itemSize) })
this.props.scrollToItem?.setValue(false);
}
renderEmpty() {
const { emptyMessage } = this.props;
return <View><Text>{emptyMessage}</Text></View>
}
onClick(item: ObjectItem, index: number) {
const { onClick, scrollItem } = this.props;
const actionValue = onClick!(item);
if (!this.state.clickDisabled) {
this.setState({ clickDisabled: true });
actionValue.execute();
scrollItem?.setValue(new Big(index));
clickTimer = setTimeout(() => {
this.setState({ clickDisabled: false });
}, 3000);
}
}
componentDidMount() {
const { scrollToItem, useItemLayout } = this.props
if (useItemLayout) {
setTimeout(() => {
if (useItemLayout) {
scrollToItem?.value ? this.scrollToOffset(this.state.scrollIndex) : null;
}
}, 100)
}
}
componentWillUnmount() {
const { scrollToItem } = this.props;
clearTimeout(clickTimer)
scrollToItem?.setValue(false)
}
}

78
src/CustomListView.xml Normal file
View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<widget id="incentro.customlistview.CustomListView" pluginWidget="true" needsEntityContext="true" offlineCapable="true"
supportedPlatform="Native"
xmlns="http://www.mendix.com/widget/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.mendix.com/widget/1.0/ ../node_modules/mendix/custom_widget.xsd">
<name>Custom ListView</name>
<description>Custom Listview</description>
<icon/>
<properties>
<propertyGroup caption="General">
<property key="ds" type="datasource" required="true" isList="true">
<caption>Datasource</caption>
<description>List of items</description>
</property>
<property key="container" type="widgets" dataSource="ds" required="true">
<caption>Container</caption>
<description></description>
</property>
<property key="scrollView" type="boolean" defaultValue="false">
<caption>Scroll View</caption>
<description>Use a scrollview instead of a flatlist. Flatlist functions will not work.</description>
</property>
</propertyGroup>
<propertyGroup caption="Flatlist">
<property key="onClick" type="action" required="false" dataSource="ds">
<caption>On click</caption>
<description>Action to perform when listview item is pressed.</description>
</property>
<property key="emptyMessage" type="string" defaultValue="Empty">
<caption>Empty message</caption>
<description>Message to show when list is empty.</description>
</property>
<property key="scrollToItem" type="attribute" required="false">
<caption>Scroll to item</caption>
<description>Attribute boolean to activate automatic scroll. Scroll item must also be filled!</description>
<attributeTypes>
<attributeType name="Boolean"/>
</attributeTypes>
</property>
<property key="scrollItem" type="attribute" required="false">
<caption>Scroll item</caption>
<description>Contains the index for where to scroll when scroll to item is set to true.</description>
<attributeTypes>
<attributeType name="Integer"/>
</attributeTypes>
</property>
<property key="windowSize" type="integer" defaultValue="21">
<caption>Window size</caption>
<description>The number passed here is a measurement unit where 1 is equivalent to your viewport height.</description>
</property>
<property key="initialNumToRender" type="integer" defaultValue="10">
<caption>Initial nr. of items</caption>
<description>Set initial number of items to render when component mounts.</description>
</property>
<property key="maxNumberToRenderPerBatch" type="integer" defaultValue="5">
<caption>Max. render per batch</caption>
<description>Set number of items to render while scrolling.</description>
</property>
<property key="cellBatchingSize" type="integer" defaultValue="100">
<caption>Batching delay</caption>
<description>Set delay in milliseconds between batch renders. </description>
</property>
<property key="removeClippedSubviews" type="boolean" defaultValue="false">
<caption>Remove clipped subviews</caption>
<description>Unmounts components that are outside the window.</description>
</property>
<property key="useItemLayout" type="boolean" defaultValue="false">
<caption>Use getItemLayout</caption>
<description>Use flatlist getItemLayout for scrolling performance. Needs a fixed item height, which can be altered below.</description>
</property>
<property key="itemSize" type="decimal" defaultValue="50">
<caption>Item height</caption>
<description>Set item height.</description>
</property>
</propertyGroup>
</properties>
</widget>

11
src/package.xml Normal file
View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<package xmlns="http://www.mendix.com/package/1.0/">
<clientModule name="CustomListView" version="1.0.0" xmlns="http://www.mendix.com/clientModule/1.0/">
<widgetFiles>
<widgetFile path="CustomListView.xml"/>
</widgetFiles>
<files>
<file path="incentro/customlistview"/>
</files>
</clientModule>
</package>