From 5039897c177a2f52ab3850c0e87e62163c005f56 Mon Sep 17 00:00:00 2001 From: Alexey Pikulik Date: Tue, 25 Jun 2019 19:09:00 +0300 Subject: [PATCH 1/2] Pass the currentPosition of the item on press event along with the item data. This is very useful when i.e. you need to render overlay view right on top of the pressed item. Introducing dragEnabled property (true by default) to block drag feature. --- src/draggable-grid.tsx | 81 +++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/src/draggable-grid.tsx b/src/draggable-grid.tsx index 4b61894..03e1f71 100644 --- a/src/draggable-grid.tsx +++ b/src/draggable-grid.tsx @@ -20,14 +20,15 @@ interface IBaseItemType { key:string; } -export interface IDraggableGridProps{ +export interface IDraggableGridProps { + dragEnabled:boolean; numColumns:number; data:DataType[]; renderItem:(item:DataType, order:number) => React.ReactElement; style?:ViewStyle; itemHeight?:number; dragStartAnimation?:StyleProp; - onItemPress?:(item:DataType) => void; + onItemPress?:(item:DataType, position:Animated.AnimatedValueXY) => void; onDragStart?:(item:DataType) => void; onDragRelease?:(newSortedData:DataType[]) => void; } @@ -61,7 +62,11 @@ export class DraggableGrid extends React.Compone private items: IItem[] = []; private blockPositions:IPositionOffset[] = []; private activeBlockOffset:IPositionOffset = {x:0, y:0}; - + + static defaultProps = { + dragEnabled: true, + }; + public constructor(props:IDraggableGridProps) { super(props); this.panResponderCapture = false; @@ -90,13 +95,13 @@ export class DraggableGrid extends React.Compone }, }; } - + private resetGridHeight = () => { const {props} = this; const rowCount = Math.ceil(props.data.length / props.numColumns); this.state.gridHeight.setValue(rowCount * this.state.blockHeight) } - + public componentWillReceiveProps(nextProps:IDraggableGridProps) { nextProps.data.forEach((item, index) => { if (this.orderMap[item.key]) { @@ -117,11 +122,11 @@ export class DraggableGrid extends React.Compone this.removeItem(item); }); } - + public componentDidUpdate() { this.resetGridHeight(); } - + private addItem = (item:DataType, index:number) => { this.blockPositions.push(this.getBlockPositionByOrder(this.items.length)); this.orderMap[item.key] = { @@ -132,16 +137,16 @@ export class DraggableGrid extends React.Compone itemData:item, currentPosition:new Animated.ValueXY(this.getBlockPositionByOrder(index)), }); - + } - + private removeItem = (item:IItem) => { const itemIndex = findIndex(this.items, (curItem) => curItem.key === item.key); this.items.splice(itemIndex, 1); this.blockPositions.pop(); delete this.orderMap[item.key]; } - + public componentWillMount() { this.items = this.props.data.map((item, index) => { this.orderMap[item.key] = { @@ -154,7 +159,7 @@ export class DraggableGrid extends React.Compone }; }) } - + public render() { return ( extends React.Compone ); } - + private onBlockPress(itemIndex:number) { - this.props.onItemPress && this.props.onItemPress(this.items[itemIndex].itemData); + this.props.onItemPress && this.props.onItemPress(this.items[itemIndex].itemData, this.items[itemIndex].currentPosition); } - + private getBlockStyle = (itemIndex:number) => { return [ { @@ -207,10 +212,14 @@ export class DraggableGrid extends React.Compone left:this.items[itemIndex].currentPosition.getLayout().left, }, ]; - + } - + private setActiveBlock = (itemIndex:number) => { + if (!this.props.dragEnabled) { + return false; + } + this.panResponderCapture = true; this.setState({ activeItemIndex:itemIndex, @@ -218,12 +227,12 @@ export class DraggableGrid extends React.Compone this.startDragStartAnimation(); }); } - + private getDragStartAnimation = (itemIndex:number) => { if (this.state.activeItemIndex != itemIndex) { return; } - + let dragStartAnimation; if (this.props.dragStartAnimation) { dragStartAnimation = this.props.dragStartAnimation; @@ -235,7 +244,7 @@ export class DraggableGrid extends React.Compone ...dragStartAnimation, }; } - + private getDefaultDragStartAnimation = () => { return { transform:[ @@ -252,7 +261,7 @@ export class DraggableGrid extends React.Compone }, }; } - + private startDragStartAnimation = () => { if (!this.props.dragStartAnimation) { this.state.dragStartAnimatedValue.setValue(1); @@ -262,7 +271,7 @@ export class DraggableGrid extends React.Compone }).start(); } } - + private getBlockPositionByOrder = (order:number) => { if (this.blockPositions[order]) { return this.blockPositions[order]; @@ -275,7 +284,7 @@ export class DraggableGrid extends React.Compone x,y } } - + private assessGridSize = (event:IOnLayoutEvent) => { if (!this.state.hadInitBlockSize) { let blockWidth,blockHeight; @@ -291,7 +300,7 @@ export class DraggableGrid extends React.Compone }); } } - + private initBlockPositions = () => { this.items.forEach((item, index) => { this.blockPositions[index] = this.getBlockPositionByOrder(index); @@ -301,18 +310,18 @@ export class DraggableGrid extends React.Compone }) this.setState({hadInitBlockSize:true}); } - + private getActiveItem = () => { if (this.state.activeItemIndex === undefined) return false; return this.items[this.state.activeItemIndex]; } - + private getDistance = (startOffset:IPositionOffset, endOffset:IPositionOffset) => { const xDistance = startOffset.x + this.activeBlockOffset.x - endOffset.x; const yDistance = startOffset.y + this.activeBlockOffset.y - endOffset.y; return Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2)); } - + private onStartDrag(nativeEvent:GestureResponderEvent, gestureState:PanResponderGestureState) { const activeItem = this.getActiveItem(); if (!activeItem) return false; @@ -334,15 +343,15 @@ export class DraggableGrid extends React.Compone y:moveY, }) } - + private onHandMove(nativeEvent:GestureResponderEvent, gestureState:PanResponderGestureState) { const activeItem = this.getActiveItem(); if (!activeItem) return false; const {moveX, moveY } = gestureState; - + const xChokeAmount = Math.max(0, (this.activeBlockOffset.x + moveX) - (this.state.gridLayout.width - this.state.blockWidth)); const xMinChokeAmount = Math.min(0, this.activeBlockOffset.x + moveX); - + const dragPosition = { x:moveX - xChokeAmount - xMinChokeAmount, y:moveY, @@ -350,10 +359,10 @@ export class DraggableGrid extends React.Compone const originPosition = this.blockPositions[this.orderMap[activeItem.key].order]; const dragPositionToActivePositionDistance = this.getDistance(dragPosition, originPosition); activeItem.currentPosition.setValue(dragPosition); - + let closetItemIndex = this.state.activeItemIndex as number; let closetDistance = dragPositionToActivePositionDistance; - + this.items.forEach((item, index) => { if ( index != this.state.activeItemIndex @@ -374,7 +383,7 @@ export class DraggableGrid extends React.Compone this.orderMap[activeItem.key].order = closetOrder; } } - + private resetBlockPositionByOrder = (startOrder:number, endOrder:number) => { if (startOrder > endOrder) { for (let i = startOrder - 1; i >= endOrder; i--) { @@ -390,7 +399,7 @@ export class DraggableGrid extends React.Compone } } } - + private moveBlockToBlockOrderPosition = (itemKey:string) => { const itemIndex = findIndex(this.items, (item) => item.key === itemKey); this.items[itemIndex].currentPosition.flattenOffset(); @@ -402,11 +411,11 @@ export class DraggableGrid extends React.Compone } ).start(); } - + private getKeyByOrder = (order:number) => { return findKey(this.orderMap, (item:IOrderMapItem) => item.order === order) as string; } - + private onHandRelease() { const activeItem = this.getActiveItem(); if (!activeItem) return false; @@ -432,4 +441,4 @@ const styles = StyleSheet.create({ flexDirection:'row', flexWrap:'wrap', }, -}); \ No newline at end of file +}); From c9e985687a38b0f4b8123d2213333ebb547006ff Mon Sep 17 00:00:00 2001 From: Alexey Pikulik Date: Tue, 25 Jun 2019 19:13:31 +0300 Subject: [PATCH 2/2] Bump package version. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6e1036b..72700c7 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "sortable", "grid" ], - "version": "1.1.0", + "version": "1.1.1", "description": "A draggable grid for react native", "main": "built/index.js", "types": "src/index.ts",