├── .DS_Store
├── ScrollableMixin.js
├── package.json
├── demo
├── ScrollView.js
└── ListView.js
├── README.md
└── PullRefreshScrollView.js
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lvming6816077/react-native-pullRefreshScrollView/HEAD/.DS_Store
--------------------------------------------------------------------------------
/ScrollableMixin.js:
--------------------------------------------------------------------------------
1 | let ScrollableMixin = {
2 | getInnerViewNode(): any {
3 | return this.getScrollResponder().getInnerViewNode();
4 | },
5 |
6 | scrollTo(destY?: number, destX?: number) {
7 | this.getScrollResponder().scrollTo(destY, destX);
8 | },
9 |
10 | scrollWithoutAnimationTo(destY?: number, destX?: number) {
11 | this.getScrollResponder().scrollWithoutAnimationTo(destY, destX);
12 | },
13 | };
14 |
15 | module.exports = ScrollableMixin;
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-pullrefresh-scrollview",
3 | "version": "1.1.2",
4 | "description": "",
5 | "main": "PullRefreshScrollView.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/lvming6816077/react-native-pullRefreshScrollView.git"
12 | },
13 | "author": "lvming",
14 | "license": "ISC",
15 | "keywords": [
16 | "react",
17 | "react-native",
18 | "react-component",
19 | "react-native-component",
20 | "pull-to-refresh",
21 | "ui"
22 | ],
23 | "bugs": {
24 | "url": "https://github.com/lvming6816077/react-native-pullRefreshScrollView/issues"
25 | },
26 | "homepage": "https://github.com/lvming6816077/react-native-pullRefreshScrollView#readme"
27 | }
--------------------------------------------------------------------------------
/demo/ScrollView.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React, { Component } from 'react';
4 | import {
5 | View,
6 | ListView,
7 | Image,
8 | Text,
9 | TouchableOpacity,
10 | TouchableHighlight,
11 | StyleSheet,
12 | Alert,
13 | ScrollView,
14 | Dimensions,
15 | InteractionManager,
16 | AppRegistry,
17 | } from 'react-native';
18 |
19 |
20 | import PullRefreshScrollView from 'react-native-pullrefresh-scrollview';
21 |
22 |
23 |
24 |
25 |
26 | export default class Projects extends Component {
27 | constructor(props) {
28 | super(props);
29 |
30 | }
31 |
32 | onRefresh(){
33 | console.log('refresh');
34 | var self = this;
35 | setTimeout(function(){
36 | self.refs.PullRefresh.onRefreshEnd();
37 | },2000);
38 | }
39 |
40 | render() {
41 |
42 |
43 | return (
44 |
11 |
12 |
13 | #### ListView:
14 |
15 |
16 |
17 | ## How to use
18 |
19 | ##### Download from npm
20 |
21 |
npm install --save react-native-pullrefresh-scrollview22 | 23 | ##### Use in Scrollview 24 | 25 | ```javascript 26 | import PullRefreshScrollView from 'react-native-pullrefresh-scrollview'; 27 | 28 | render() { 29 | 30 | return ( 31 |
57 |
58 | ##### Only text
59 |
60 |
61 |
62 | ##### Only image
63 |
64 |
65 |
66 | ##### LoadMore
67 |
68 |
69 |
70 | ##### End LoadMore
71 |
72 |
73 |
74 | ##### props
75 |
76 |
77 | onRefresh:
78 | refreshedText: ''
79 | refreshingText: ''
80 | refreshText:''
81 | useLoadMore:false
82 | endText:''
83 | endingText:''
84 | indicatorArrowImg: { // default arrow.png
85 | style:{},
86 | url:''
87 | }
88 | indicatorImg: { // default
89 | style:{},
90 | url:''
91 | }
92 | refreshType:'normal' // normal image text
93 |
94 |
95 | ##### Regain the PullRefresh
96 |
97 | ```javascript
98 | onRefresh(PullRefresh){
99 | PullRefresh.onRefreshEnd();
100 | }
101 | ```
102 | ##### End the LoadMore
103 |
104 | ```javascript
105 | onLoadMore(PullRefresh){
106 | PullRefresh.onLoadMoreEnd();
107 | }
108 | ```
109 | ## Advice
110 |
111 | mail:441403517@qq.com
112 |
113 | ## 中文 | [English](#user-content-english--中文)
114 |
115 | # react-native-pullRefreshScrollView
116 | React Native下拉刷新组件 ios 平台 支持ScrollView,ListView
117 |
118 | ## 效果展示
119 |
120 | #### ScrollView:
121 |
122 |
123 |
124 |
125 | #### ListView:
126 |
127 |
128 |
129 | ## 如何引入
130 |
131 | ##### 从npm上下载组件
132 |
133 | npm install --save react-native-pullrefresh-scrollview134 | 135 | ##### 在ScrollView中使用 136 | 137 | ```javascript 138 | import PullRefreshScrollView from 'react-native-pullrefresh-scrollview'; 139 | 140 | render() { 141 | 142 | return ( 143 |
169 |
170 | ##### 纯文字
171 |
172 |
173 |
174 | ##### 纯图片
175 |
176 |
177 |
178 | ##### 上拉加载
179 |
180 |
181 |
182 | ##### 上拉加载完成
183 |
184 |
185 |
186 | ##### props
187 |
188 |
189 | onRefresh:当触发刷新时的回调
190 | refreshedText: '释放立即刷新'
191 | refreshingText: '正在刷新数据中..'
192 | refreshText:'下拉可以刷新'
193 | useLoadMore:false //是否使用滚动加载功能 即上拉加载
194 | endText:'已经加载完成'
195 | endingText:'加载更多数据'
196 | indicatorArrowImg: { // 下拉箭头图片和样式 default arrow.png
197 | style:{},
198 | url:''
199 | }
200 | indicatorImg: { // loading图片和样式 default
201 | style:{},
202 | url:''
203 | }
204 | refreshType:'normal' // normal image text
205 |
206 |
207 | ##### 收回下拉刷新
208 |
209 | ```javascript
210 | onRefresh(PullRefresh){
211 | PullRefresh.onRefreshEnd();
212 | }
213 | ```
214 | ##### 结束滚动加载
215 |
216 | ```javascript
217 | onLoadMore(PullRefresh){
218 | PullRefresh.onLoadMoreEnd();
219 | }
220 | ```
221 | ## 建议和反馈
222 |
223 | 此组件还在不断更新中,如有需求欢迎提出反馈441403517@qq.com
224 |
225 | ## 合作开发
226 | 此组件目前仅支持ios平台,android平台暂不支持,欢迎有兴趣的小伙伴一起加入开发,将android版的开发出来!
227 |
--------------------------------------------------------------------------------
/PullRefreshScrollView.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | import React, { Component } from 'react';
3 | import {
4 | View,
5 | Text,
6 | Image,
7 | StyleSheet,
8 | AsyncStorage,
9 | Animated,
10 | Easing,
11 | ScrollView,
12 | ListView,
13 | ActivityIndicator,
14 | AppRegistry,
15 | } from 'react-native';
16 |
17 | import ScrollableMixin from './ScrollableMixin';
18 |
19 | export default class PullRefreshScrollView extends Component {
20 | constructor(props) {
21 | super(props);
22 | // = this.scrollView;
23 | this.refreshedText = props.refreshedText;
24 | this.refreshingText = props.refreshingText;
25 | this.refreshText = props.refreshText;
26 | this.endText = props.endText;
27 | this.endingText = props.endingText;
28 | this.useLoadMore = props.useLoadMore;
29 | this.state = {
30 | prTitle:this.refreshText,
31 | prState:0,
32 | prTimeDisplay:'暂无更新',
33 | prLoading:false,
34 | prArrowDeg:new Animated.Value(0),
35 | lmState:0
36 | };
37 |
38 |
39 | this.base64Icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAABQBAMAAAD8TNiNAAAAJ1BMVEUAAACqqqplZWVnZ2doaGhqampoaGhpaWlnZ2dmZmZlZWVmZmZnZ2duD78kAAAADHRSTlMAA6CYqZOlnI+Kg/B86E+1AAAAhklEQVQ4y+2LvQ3CQAxGLSHEBSg8AAX0jECTnhFosgcjZKr8StE3VHz5EkeRMkF0rzk/P58k9rgOW78j+TE99OoeKpEbCvcPVDJ0OvsJ9bQs6Jxs26h5HCrlr9w8vi8zHphfmI0fcvO/ZXJG8wDzcvDFO2Y/AJj9ADE7gXmlxFMIyVpJ7DECzC9J2EC2ECAAAAAASUVORK5CYII=';
40 | this.dragFlag = false; //scrollview是否处于拖动状态的标志
41 | this.prStoryKey = 'prtimekey';
42 |
43 |
44 |
45 | }
46 | // 滚动触发
47 | onScroll(e){
48 | let target = e.nativeEvent;
49 | let y = target.contentOffset.y;
50 |
51 | if (this.dragFlag) {
52 | if (y <= -70) {
53 | this.upState();
54 |
55 | } else {
56 | this.downState();
57 | }
58 | }
59 |
60 | this.onCheckEndReached(target);
61 |
62 |
63 | if (this.props.onScroll) {
64 | this.props.onScroll(e);
65 | }
66 | }
67 | // 高于临界值状态
68 | upState(){
69 | this.setState({
70 | prTitle:this.refreshedText,
71 | prState:1
72 | });
73 |
74 | Animated.timing(this.state.prArrowDeg, {
75 | toValue: 1,
76 | duration: 100,
77 | easing: Easing.inOut(Easing.quad)
78 | }).start();
79 | }
80 | // 低于临界值状态
81 | downState(){
82 | this.setState({
83 | prTitle:this.refreshText,
84 | prState:0
85 | });
86 | Animated.timing(this.state.prArrowDeg, {
87 | toValue: 0,
88 | duration: 100,
89 | easing: Easing.inOut(Easing.quad)
90 | }).start();
91 | }
92 |
93 | // 手指离开
94 | onScrollEndDrag(){
95 |
96 | this.dragFlag = false;
97 | if (this.state.prState) {
98 |
99 | // 回到待收起状态
100 | this.scrollView.scrollTo({x:0,y:-70,animated:true});
101 |
102 |
103 |
104 | this.setState({
105 | prTitle:this.refreshingText,
106 | prLoading:true,
107 | prArrowDeg:new Animated.Value(0),
108 |
109 | });
110 |
111 | // 触发外部的下拉刷新方法
112 | if (this.props.onRefresh) {
113 | this.props.onRefresh(this);
114 | }
115 | }
116 |
117 | }
118 | // 手指未离开
119 | onScrollBeginDrag(){
120 | this.setState({
121 | beginScroll: true
122 | });
123 | this.dragFlag = true;
124 |
125 | if (this.props.onScrollBeginDrag) {
126 | this.props.onScrollBeginDrag();
127 | }
128 | }
129 | onCheckEndReached(target){
130 | if (!this.useLoadMore || this.state.lmState) {
131 | return;
132 | }
133 | let contentSize = target.contentSize;
134 | let layoutMeasurement = target.layoutMeasurement;
135 | let y = target.contentOffset.y;
136 |
137 | if (contentSize.height - layoutMeasurement.height - y < 40) {
138 |
139 | // 触发外部的滚动加载方法
140 | if (this.props.onLoadMore && this.lastContentHeight != contentSize.height) {
141 | this.lastContentHeight = contentSize.height;
142 | this.props.onLoadMore(this);
143 | }
144 |
145 | }
146 |
147 | }
148 | onLoadMoreEnd(target){
149 | this.setState({
150 | lmState:1
151 | });
152 |
153 | }
154 | onBeginLoadMore(target){
155 | this.setState({
156 | lmState:0
157 | });
158 |
159 | }
160 | onRefreshEnd(){
161 | let now = new Date().getTime();
162 | this.setState({
163 | prTitle:this.refreshText,
164 | prLoading:false,
165 | beginScroll: false,
166 | prTimeDisplay:dateFormat(now,'yyyy-MM-dd hh:mm')
167 | });
168 |
169 | // 存一下刷新时间
170 | AsyncStorage.setItem(this.prStoryKey, now.toString());
171 | this.scrollView.scrollTo({x:0,y:0,animated:true});
172 | }
173 | componentDidMount(){
174 |
175 | AsyncStorage.getItem(this.prStoryKey, (error, result) => {
176 |
177 |
178 | if (result) {
179 | result = parseInt(result);
180 |
181 | //将时间传入下拉刷新的state
182 | this.setState({
183 | prTimeDisplay:dateFormat(new Date(result),'yyyy-MM-dd hh:mm'),
184 | });
185 |
186 | }
187 |
188 |
189 | });
190 | }
191 | renderNormalContent(){
192 | this.transform = [{rotate:this.state.prArrowDeg.interpolate({
193 | inputRange: [0,1],
194 | outputRange: ['0deg', '-180deg']
195 | })}];
196 | let jsxarr = [];
197 | let arrowStyle = {
198 | position:'absolute',
199 | width:14,
200 | height:23,
201 | left:-50,
202 | top:-4,
203 | transform:this.transform
204 | };
205 | let indicatorStyle = {
206 | position:'absolute',
207 | left:-40,
208 | top:-1,
209 | width:16,
210 | height:16
211 | };
212 |
213 | if (this.props.indicatorImg.url) {
214 | if (this.props.indicatorImg.style) {
215 | indicatorStyle = this.props.indicatorImg.style;
216 | }
217 | if (this.state.prLoading) {
218 | jsxarr.push(