Pullable.ios.js
7.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
'use strict';
import React from 'react';
import {ListView, View, PanResponder, Animated, Easing, FlatList} from 'react-native';
import * as index from './info';
import PullRoot from './PullRoot'
export default class Pullable extends PullRoot {
constructor(props) {
super(props);
this.pullState = 'pulling'; //pulling,pullok,pullrelease
this.topIndicatorHeight = this.props.topIndicatorHeight ? this.props.topIndicatorHeight : index.defaultTopIndicatorHeight;
this.defaultXY = {x: 0, y: this.topIndicatorHeight * -1};
this.duration = this.props.duration ? this.props.duration : index.defaultDuration;
this.state = Object.assign({}, props, {
pullPan: new Animated.ValueXY(this.defaultXY),
atTop: true,
height: 0,
width: 0
});
this.panResponder = PanResponder.create({
onStartShouldSetPanResponder: this.onShouldSetPanResponder,
onStartShouldSetPanResponderCapture: this.onShouldSetPanResponder,
onMoveShouldSetPanResponder: this.onShouldSetPanResponder,
onMoveShouldSetPanResponderCapture: this.onShouldSetPanResponder,
onPanResponderTerminationRequest: (evt, gestureState) => false, //这个很重要,这边不放权
onPanResponderMove: this.onPanResponderMove,
onPanResponderRelease: this.onPanResponderRelease,
onPanResponderTerminate: this.onPanResponderRelease,
});
}
onShouldSetPanResponder = (e, gesture) => {
let y = 0
if (this.scroll instanceof ListView) { //ListView下的判断
y = this.scroll.scrollProperties.offset;
} else if (this.scroll instanceof FlatList) {//FlatList下的判断
y = this.scroll._listRef._getScrollMetrics().offset
}
//根据y的值来判断是否到达顶部
this.state.atTop = (y <= 0)
if (this.state.atTop && index.isDownGesture(gesture.dx, gesture.dy) && this.props.refreshable) {
this.lastY = this.state.pullPan.y._value;
return true;
}
return false;
}
onPanResponderMove = (e, gesture) => {
if (index.isDownGesture(gesture.dx, gesture.dy) && this.props.refreshable) { //下拉
this.state.pullPan.setValue({x: this.defaultXY.x, y: this.lastY + gesture.dy / 2});
this.onPullStateChange(gesture.dy)
}
}
onPanResponderRelease = (e, gesture) => {
if (this.pullState == 'pulling') { //没有下拉到位
this.resetDefaultXYHandler(); //重置状态
} else if (this.pullState == 'pullok') { //已经下拉到位了
//传入-1,表示此时进行的是释放刷新的操作
this.onPullStateChange(-1)
//进行下拉刷新的回调
this.props.onPullRelease && this.props.onPullRelease();
//重置刷新的头部到初始位置
Animated.timing(this.state.pullPan, {
toValue: {x: 0, y: 0},
easing: Easing.linear,
duration: this.duration
}).start();
}
}
//重置刷新的操作
resetDefaultXYHandler = () => {
Animated.timing(this.state.pullPan, {
toValue: this.defaultXY,
easing: Easing.linear,
duration: this.duration
}).start(() => {
//ui要进行刷新
this.onPullStateChange(-1)
});
}
/** 数据加载完成后调用此方法进行重置归位
*/
finishRefresh = () => {
if (this.pullState == 'pullrelease') { //仅触摸松开时才触发
this.resetDefaultXYHandler();
}
}
startRefresh = () => {
if (!this.props.refreshable) { //不支持下拉刷新的时候就不进行了
return;
}
//进行数据的回调
this.props.onPullRelease && this.props.onPullRelease();
//此时进行状态的改变
this.onPullStateChange(-1)
//动画的展示
Animated.timing(this.state.pullPan, {
toValue: {x: 0, y: 0},
easing: Easing.linear,
duration: this.duration
}).start();
}
onLayout = (e) => {
if (this.state.width != e.nativeEvent.layout.width || this.state.height != e.nativeEvent.layout.height) {
this.scrollContainer && this.scrollContainer.setNativeProps({
style: {
width: e.nativeEvent.layout.width,
height: e.nativeEvent.layout.height
}
});
this.state.width = e.nativeEvent.layout.width;
this.state.height = e.nativeEvent.layout.height;
}
}
render() {
return (
<View style={{flex: 1, flexGrow: 1, zIndex: -999}} {...this.panResponder.panHandlers} onLayout={this.onLayout}>
{this.props.isContentScroll ?
<View pointerEvents='box-none'>
<Animated.View style={[this.state.pullPan.getLayout()]}>
{this.renderTopIndicator()}
<View ref={(c) => {
this.scrollContainer = c;
}}
style={{width: this.state.width, height: this.state.height}}>
{this.getScrollable()}
</View>
</Animated.View>
</View> :
<View>
<View ref={(c) => {
this.scrollContainer = c;
}}
style={{width: this.state.width, height: this.state.height}}>
{this.getScrollable()}
</View>
<View pointerEvents='box-none'
style={{position: 'absolute', left: 0, right: 0, top: 0}}>
<Animated.View style={[this.state.pullPan.getLayout()]}>
{this.renderTopIndicator()}
</Animated.View>
</View>
</View>}
</View>
);
}
//下拉的时候根据高度进行对应的操作
onPullStateChange = (moveHeight) => {
//因为返回的moveHeight单位是px,所以要将this.topIndicatorHeight转化为px进行计算
let topHeight = index.dip2px(this.topIndicatorHeight)
if (moveHeight > 0 && moveHeight < topHeight) { //此时是下拉没有到位的状态
this.pullState = "pulling"
} else if (moveHeight >= topHeight) { //下拉刷新到位
this.pullState = "pullok"
} else { //下拉刷新释放,此时返回的值为-1
this.pullState = "pullrelease"
}
//默认的设置
this.defaultTopSetting()
//告诉外界是否要锁住
this.props.onPushing && this.props.onPushing(this.pullState != "pullrelease")
//进行状态和下拉距离的回调
this.props.onPullStateChangeHeight && this.props.onPullStateChangeHeight(this.pullState, moveHeight)
}
}