├── .gitignore ├── examples └── Demo │ ├── .watchmanconfig │ ├── .gitattributes │ ├── app.json │ ├── .eslintrc.js │ ├── babel.config.js │ ├── android │ ├── app │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── values │ │ │ │ │ │ ├── strings.xml │ │ │ │ │ │ └── styles.xml │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ │ └── mipmap-xxxhdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── java │ │ │ │ │ └── com │ │ │ │ │ │ └── demo │ │ │ │ │ │ ├── MainActivity.java │ │ │ │ │ │ └── MainApplication.java │ │ │ │ └── AndroidManifest.xml │ │ │ └── debug │ │ │ │ └── AndroidManifest.xml │ │ ├── debug.keystore │ │ ├── proguard-rules.pro │ │ ├── build_defs.bzl │ │ ├── _BUCK │ │ └── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── settings.gradle │ ├── gradle.properties │ ├── build.gradle │ ├── gradlew.bat │ └── gradlew │ ├── ios │ ├── Demo │ │ ├── Images.xcassets │ │ │ ├── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── AppDelegate.h │ │ ├── main.m │ │ ├── AppDelegate.m │ │ ├── Info.plist │ │ └── Base.lproj │ │ │ └── LaunchScreen.xib │ ├── Demo.xcworkspace │ │ └── contents.xcworkspacedata │ ├── DemoTests │ │ ├── Info.plist │ │ └── DemoTests.m │ ├── Demo-tvOSTests │ │ └── Info.plist │ ├── Demo-tvOS │ │ └── Info.plist │ ├── Podfile │ ├── Demo.xcodeproj │ │ ├── xcshareddata │ │ │ └── xcschemes │ │ │ │ ├── Demo.xcscheme │ │ │ │ └── Demo-tvOS.xcscheme │ │ └── project.pbxproj │ └── Podfile.lock │ ├── .buckconfig │ ├── .prettierrc.js │ ├── index.js │ ├── __tests__ │ └── App-test.tsx │ ├── metro.config.js │ ├── package.json │ ├── App.tsx │ ├── .gitignore │ ├── js │ ├── NestScrollView.tsx │ ├── Header.tsx │ └── FlatList.tsx │ └── tsconfig.json ├── screenshot └── demo.gif ├── yarn.lock ├── package.json ├── lib ├── PullToRefresh.d.ts └── PullToRefresh.js ├── README.md ├── tsconfig.json └── src └── PullToRefresh.tsx /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /examples/Demo/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /examples/Demo/.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /examples/Demo/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Demo", 3 | "displayName": "Demo" 4 | } -------------------------------------------------------------------------------- /examples/Demo/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native-community', 4 | }; 5 | -------------------------------------------------------------------------------- /examples/Demo/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:metro-react-native-babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /screenshot/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sophister/react-native-pull-to-refresh-custom/HEAD/screenshot/demo.gif -------------------------------------------------------------------------------- /examples/Demo/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Demo 3 | 4 | -------------------------------------------------------------------------------- /examples/Demo/ios/Demo/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /examples/Demo/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /examples/Demo/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sophister/react-native-pull-to-refresh-custom/HEAD/examples/Demo/android/app/debug.keystore -------------------------------------------------------------------------------- /examples/Demo/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bracketSpacing: false, 3 | jsxBracketSameLine: true, 4 | singleQuote: true, 5 | trailingComma: 'all', 6 | }; 7 | -------------------------------------------------------------------------------- /examples/Demo/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sophister/react-native-pull-to-refresh-custom/HEAD/examples/Demo/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /examples/Demo/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sophister/react-native-pull-to-refresh-custom/HEAD/examples/Demo/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/Demo/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sophister/react-native-pull-to-refresh-custom/HEAD/examples/Demo/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/Demo/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sophister/react-native-pull-to-refresh-custom/HEAD/examples/Demo/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/Demo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sophister/react-native-pull-to-refresh-custom/HEAD/examples/Demo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/Demo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sophister/react-native-pull-to-refresh-custom/HEAD/examples/Demo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/Demo/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sophister/react-native-pull-to-refresh-custom/HEAD/examples/Demo/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /examples/Demo/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sophister/react-native-pull-to-refresh-custom/HEAD/examples/Demo/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /examples/Demo/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sophister/react-native-pull-to-refresh-custom/HEAD/examples/Demo/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /examples/Demo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sophister/react-native-pull-to-refresh-custom/HEAD/examples/Demo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /examples/Demo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sophister/react-native-pull-to-refresh-custom/HEAD/examples/Demo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /examples/Demo/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'Demo' 2 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) 3 | include ':app' 4 | -------------------------------------------------------------------------------- /examples/Demo/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import {AppRegistry} from 'react-native'; 6 | import App from './App'; 7 | import {name as appName} from './app.json'; 8 | 9 | AppRegistry.registerComponent(appName, () => App); 10 | -------------------------------------------------------------------------------- /examples/Demo/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.5-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /examples/Demo/ios/Demo.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/Demo/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/Demo/__tests__/App-test.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import 'react-native'; 6 | import React from 'react'; 7 | import App from '../App'; 8 | 9 | // Note: test renderer must be required after react-native. 10 | import renderer from 'react-test-renderer'; 11 | 12 | it('renders correctly', () => { 13 | renderer.create(); 14 | }); 15 | -------------------------------------------------------------------------------- /examples/Demo/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/Demo/android/app/src/main/java/com/demo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.demo; 2 | 3 | import com.facebook.react.ReactActivity; 4 | 5 | public class MainActivity extends ReactActivity { 6 | 7 | /** 8 | * Returns the name of the main component registered from JavaScript. This is used to schedule 9 | * rendering of the component. 10 | */ 11 | @Override 12 | protected String getMainComponentName() { 13 | return "Demo"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/Demo/ios/Demo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (nonatomic, strong) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /examples/Demo/ios/Demo/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /examples/Demo/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | -------------------------------------------------------------------------------- /examples/Demo/android/app/build_defs.bzl: -------------------------------------------------------------------------------- 1 | """Helper definitions to glob .aar and .jar targets""" 2 | 3 | def create_aar_targets(aarfiles): 4 | for aarfile in aarfiles: 5 | name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")] 6 | lib_deps.append(":" + name) 7 | android_prebuilt_aar( 8 | name = name, 9 | aar = aarfile, 10 | ) 11 | 12 | def create_jar_targets(jarfiles): 13 | for jarfile in jarfiles: 14 | name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")] 15 | lib_deps.append(":" + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | -------------------------------------------------------------------------------- /examples/Demo/ios/Demo/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /examples/Demo/ios/DemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/Demo/metro.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Metro configuration for React Native 3 | * https://github.com/facebook/react-native 4 | * 5 | * @format 6 | */ 7 | 8 | const path = require('path'); 9 | 10 | const libSourceDir = path.resolve(__dirname, '../../src/'); 11 | console.log(`======, ${libSourceDir}`); 12 | 13 | module.exports = { 14 | watchFolders: [libSourceDir], 15 | 16 | resolver: { 17 | extraNodeModules: new Proxy( 18 | {}, 19 | { 20 | get: (target, name) => { 21 | // console.log('= ', name); 22 | return path.join(__dirname, `node_modules/${name}`); 23 | }, 24 | }, 25 | ), 26 | }, 27 | 28 | transformer: { 29 | getTransformOptions: async () => ({ 30 | transform: { 31 | experimentalImportSupport: false, 32 | inlineRequires: false, 33 | }, 34 | }), 35 | }, 36 | }; 37 | -------------------------------------------------------------------------------- /examples/Demo/ios/Demo-tvOSTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/Demo/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useAndroidX=true 21 | android.enableJetifier=true 22 | -------------------------------------------------------------------------------- /examples/Demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Demo", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "android": "react-native run-android", 7 | "ios": "react-native run-ios", 8 | "start": "react-native start", 9 | "test": "jest" 10 | }, 11 | "dependencies": { 12 | "react": "16.9.0", 13 | "react-native": "0.61.2" 14 | }, 15 | "devDependencies": { 16 | "@babel/core": "^7.6.2", 17 | "@babel/runtime": "^7.6.2", 18 | "@react-native-community/eslint-config": "^0.0.5", 19 | "@types/jest": "^24.0.18", 20 | "@types/react-native": "^0.60.21", 21 | "@types/react-test-renderer": "16.9.0", 22 | "babel-jest": "^24.9.0", 23 | "jest": "^24.9.0", 24 | "metro-react-native-babel-preset": "^0.56.0", 25 | "react-test-renderer": "16.9.0", 26 | "typescript": "^3.6.3" 27 | }, 28 | "jest": { 29 | "preset": "react-native", 30 | "moduleFileExtensions": [ 31 | "ts", 32 | "tsx", 33 | "js", 34 | "jsx", 35 | "json", 36 | "node" 37 | ] 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/Demo/App.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * 5 | * Generated with the TypeScript template 6 | * https://github.com/react-native-community/react-native-template-typescript 7 | * 8 | * @format 9 | */ 10 | 11 | import React from 'react'; 12 | import { 13 | SafeAreaView, 14 | StyleSheet, 15 | ScrollView, 16 | View, 17 | Text, 18 | StatusBar, 19 | } from 'react-native'; 20 | 21 | import { 22 | Header, 23 | LearnMoreLinks, 24 | Colors, 25 | DebugInstructions, 26 | ReloadInstructions, 27 | } from 'react-native/Libraries/NewAppScreen'; 28 | 29 | import DemoFlatList from './js/FlatList'; 30 | 31 | const App = () => { 32 | return ( 33 | 34 | 35 | 36 | ); 37 | }; 38 | 39 | const styles = StyleSheet.create({ 40 | container: { 41 | flex: 1, 42 | justifyContent: 'center', 43 | paddingTop: 20, 44 | backgroundColor: '#ecf0f1', 45 | padding: 0, 46 | }, 47 | }); 48 | 49 | export default App; 50 | -------------------------------------------------------------------------------- /examples/Demo/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 13 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/prop-types@*": 6 | version "15.7.1" 7 | resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.1.tgz#f1a11e7babb0c3cad68100be381d1e064c68f1f6" 8 | 9 | "@types/react-native@^0.57.65": 10 | version "0.57.65" 11 | resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.57.65.tgz#9da4773aaa95924bce42a54a5c19cfd8ffd5022b" 12 | dependencies: 13 | "@types/prop-types" "*" 14 | "@types/react" "*" 15 | 16 | "@types/react@*", "@types/react@^16.8.23": 17 | version "16.8.23" 18 | resolved "https://registry.yarnpkg.com/@types/react/-/react-16.8.23.tgz#ec6be3ceed6353a20948169b6cb4c97b65b97ad2" 19 | dependencies: 20 | "@types/prop-types" "*" 21 | csstype "^2.2.0" 22 | 23 | csstype@^2.2.0: 24 | version "2.6.6" 25 | resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.6.tgz#c34f8226a94bbb10c32cc0d714afdf942291fc41" 26 | 27 | typescript@^3.5.3: 28 | version "3.5.3" 29 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977" 30 | -------------------------------------------------------------------------------- /examples/Demo/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | 33 | # Visual Studio Code 34 | # 35 | .vscode/ 36 | 37 | # node.js 38 | # 39 | node_modules/ 40 | npm-debug.log 41 | yarn-error.log 42 | 43 | # BUCK 44 | buck-out/ 45 | \.buckd/ 46 | *.keystore 47 | !debug.keystore 48 | 49 | # fastlane 50 | # 51 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 52 | # screenshots whenever they are needed. 53 | # For more information about the recommended setup visit: 54 | # https://docs.fastlane.tools/best-practices/source-control/ 55 | 56 | */fastlane/report.xml 57 | */fastlane/Preview.html 58 | */fastlane/screenshots 59 | 60 | # Bundle artifact 61 | *.jsbundle 62 | 63 | # CocoaPods 64 | /ios/Pods/ 65 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-pull-to-refresh-custom", 3 | "version": "1.0.3", 4 | "description": " Custom pull to refresh Header supporting for React Native ScrollView/FlatList", 5 | "main": "lib/PullToRefresh.js", 6 | "types": "lib/PullToRefresh.d.ts", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "build": "tsc", 10 | "prepublishOnly": "npm run build" 11 | }, 12 | "files": [ 13 | "src", 14 | "lib", 15 | "README.md" 16 | ], 17 | "publishConfig": { 18 | "registry": "https://registry.npmjs.org/" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/sophister/react-native-pull-to-refresh-custom.git" 23 | }, 24 | "keywords": [ 25 | "React", 26 | "Native", 27 | "pull", 28 | "to", 29 | "refresh", 30 | "custom", 31 | "header" 32 | ], 33 | "author": "Jesse", 34 | "license": "ISC", 35 | "bugs": { 36 | "url": "https://github.com/sophister/react-native-pull-to-refresh-custom/issues" 37 | }, 38 | "homepage": "https://github.com/sophister/react-native-pull-to-refresh-custom#readme", 39 | "devDependencies": { 40 | "@types/react": "^16.8.23", 41 | "@types/react-native": "^0.57.65", 42 | "typescript": "^3.5.3" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /examples/Demo/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext { 5 | buildToolsVersion = "28.0.3" 6 | minSdkVersion = 16 7 | compileSdkVersion = 28 8 | targetSdkVersion = 28 9 | } 10 | repositories { 11 | jcenter() { url "https://maven.aliyun.com/repository/jcenter" } 12 | maven { url 'https://maven.aliyun.com/repository/google' } 13 | google() 14 | jcenter() 15 | } 16 | dependencies { 17 | classpath("com.android.tools.build:gradle:3.4.2") 18 | 19 | // NOTE: Do not place your application dependencies here; they belong 20 | // in the individual module build.gradle files 21 | } 22 | } 23 | 24 | allprojects { 25 | repositories { 26 | jcenter() { url "https://maven.aliyun.com/repository/jcenter" } 27 | maven { url 'https://maven.aliyun.com/repository/google' } 28 | mavenLocal() 29 | maven { 30 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 31 | url("$rootDir/../node_modules/react-native/android") 32 | } 33 | maven { 34 | // Android JSC is installed from npm 35 | url("$rootDir/../node_modules/jsc-android/dist") 36 | } 37 | 38 | google() 39 | jcenter() 40 | maven { url 'https://jitpack.io' } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/Demo/android/app/_BUCK: -------------------------------------------------------------------------------- 1 | # To learn about Buck see [Docs](https://buckbuild.com/). 2 | # To run your application with Buck: 3 | # - install Buck 4 | # - `npm start` - to start the packager 5 | # - `cd android` 6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 8 | # - `buck install -r android/app` - compile, install and run application 9 | # 10 | 11 | load(":build_defs.bzl", "create_aar_targets", "create_jar_targets") 12 | 13 | lib_deps = [] 14 | 15 | create_aar_targets(glob(["libs/*.aar"])) 16 | 17 | create_jar_targets(glob(["libs/*.jar"])) 18 | 19 | android_library( 20 | name = "all-libs", 21 | exported_deps = lib_deps, 22 | ) 23 | 24 | android_library( 25 | name = "app-code", 26 | srcs = glob([ 27 | "src/main/java/**/*.java", 28 | ]), 29 | deps = [ 30 | ":all-libs", 31 | ":build_config", 32 | ":res", 33 | ], 34 | ) 35 | 36 | android_build_config( 37 | name = "build_config", 38 | package = "com.demo", 39 | ) 40 | 41 | android_resource( 42 | name = "res", 43 | package = "com.demo", 44 | res = "src/main/res", 45 | ) 46 | 47 | android_binary( 48 | name = "app", 49 | keystore = "//android/keystores:debug", 50 | manifest = "src/main/AndroidManifest.xml", 51 | package_type = "debug", 52 | deps = [ 53 | ":app-code", 54 | ], 55 | ) 56 | -------------------------------------------------------------------------------- /examples/Demo/ios/Demo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import "AppDelegate.h" 9 | 10 | #import 11 | #import 12 | #import 13 | 14 | @implementation AppDelegate 15 | 16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 17 | { 18 | RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; 19 | RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge 20 | moduleName:@"Demo" 21 | initialProperties:nil]; 22 | 23 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 24 | 25 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 26 | UIViewController *rootViewController = [UIViewController new]; 27 | rootViewController.view = rootView; 28 | self.window.rootViewController = rootViewController; 29 | [self.window makeKeyAndVisible]; 30 | return YES; 31 | } 32 | 33 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge 34 | { 35 | #if DEBUG 36 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; 37 | #else 38 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 39 | #endif 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /examples/Demo/ios/Demo-tvOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | NSAppTransportSecurity 26 | 27 | NSExceptionDomains 28 | 29 | localhost 30 | 31 | NSExceptionAllowsInsecureHTTPLoads 32 | 33 | 34 | 35 | 36 | NSLocationWhenInUseUsageDescription 37 | 38 | UILaunchStoryboardName 39 | LaunchScreen 40 | UIRequiredDeviceCapabilities 41 | 42 | armv7 43 | 44 | UISupportedInterfaceOrientations 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UIViewControllerBasedStatusBarAppearance 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /examples/Demo/js/NestScrollView.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * test nested scrollview 3 | */ 4 | 5 | import React, { useRef } from 'react'; 6 | import { View, ScrollView, FlatList, NativeSyntheticEvent, NativeScrollEvent} from 'react-native'; 7 | import { userInfo } from 'os'; 8 | 9 | interface Props { 10 | children: JSX.Element; 11 | } 12 | 13 | export default function NestScrollView(props: Props) { 14 | const innerScrollRef = useRef(null); 15 | const scrollTop = useRef(0); 16 | function onTouchEnd() { 17 | console.log('====== nestscrollview onTouchEnd'); 18 | } 19 | function onScrollEndDrag() { 20 | console.log('====== nestscrollview onScrollEndDrag'); 21 | } 22 | function onOuterScroll(event: NativeSyntheticEvent) { 23 | console.log('====== nestscrollview outer scroll y=' + event.nativeEvent.contentOffset.y + ' contentSize=' + event.nativeEvent.contentSize.height); 24 | } 25 | function onInnerScroll() { 26 | console.log('====== nestscrollview inner scroll'); 27 | } 28 | function checkInnerScroll() { 29 | if (innerScrollRef.current) { 30 | 31 | } 32 | } 33 | 34 | return ( 35 | 43 | { 44 | React.cloneElement(props.children, { 45 | scrollEnabled: false, 46 | ref: innerScrollRef, 47 | onScroll: onInnerScroll, 48 | listKey: 'inner', 49 | }) 50 | } 51 | 52 | ); 53 | } -------------------------------------------------------------------------------- /examples/Demo/ios/Demo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | Demo 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | NSExceptionDomains 32 | 33 | localhost 34 | 35 | NSExceptionAllowsInsecureHTTPLoads 36 | 37 | 38 | 39 | 40 | NSLocationWhenInUseUsageDescription 41 | 42 | UILaunchStoryboardName 43 | LaunchScreen 44 | UIRequiredDeviceCapabilities 45 | 46 | armv7 47 | 48 | UISupportedInterfaceOrientations 49 | 50 | UIInterfaceOrientationPortrait 51 | UIInterfaceOrientationLandscapeLeft 52 | UIInterfaceOrientationLandscapeRight 53 | 54 | UIViewControllerBasedStatusBarAppearance 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /examples/Demo/ios/DemoTests/DemoTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | #import 10 | 11 | #import 12 | #import 13 | 14 | #define TIMEOUT_SECONDS 600 15 | #define TEXT_TO_LOOK_FOR @"Welcome to React" 16 | 17 | @interface DemoTests : XCTestCase 18 | 19 | @end 20 | 21 | @implementation DemoTests 22 | 23 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 24 | { 25 | if (test(view)) { 26 | return YES; 27 | } 28 | for (UIView *subview in [view subviews]) { 29 | if ([self findSubviewInView:subview matching:test]) { 30 | return YES; 31 | } 32 | } 33 | return NO; 34 | } 35 | 36 | - (void)testRendersWelcomeScreen 37 | { 38 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 39 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 40 | BOOL foundElement = NO; 41 | 42 | __block NSString *redboxError = nil; 43 | #ifdef DEBUG 44 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 45 | if (level >= RCTLogLevelError) { 46 | redboxError = message; 47 | } 48 | }); 49 | #endif 50 | 51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 54 | 55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 57 | return YES; 58 | } 59 | return NO; 60 | }]; 61 | } 62 | 63 | #ifdef DEBUG 64 | RCTSetLogFunction(RCTDefaultLogFunction); 65 | #endif 66 | 67 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 68 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 69 | } 70 | 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /examples/Demo/js/Header.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * custom header component for pull to refresh 3 | */ 4 | 5 | import * as React from 'react'; 6 | import { 7 | Text, 8 | View, 9 | ScrollView, 10 | FlatList, 11 | Animated, 12 | PanResponder, 13 | ViewStyle, 14 | TextStyle, 15 | Alert, 16 | } from 'react-native'; 17 | 18 | import PullToRefresh, { PullToRefreshHeaderProps } from '../../../src/PullToRefresh'; 19 | 20 | const { Component } = React; 21 | 22 | const headerStyle = { 23 | con: { 24 | height: 100, 25 | justifyContent: 'center', 26 | backgroundColor: 'yellow', 27 | } as ViewStyle, 28 | title: { 29 | fontSize: 22, 30 | } as TextStyle, 31 | }; 32 | 33 | interface ClassHeaderState { 34 | pullDistance: number; 35 | percent: number; 36 | } 37 | 38 | export default class Header extends Component { 39 | constructor(props: PullToRefreshHeaderProps) { 40 | super(props); 41 | this.state = { 42 | pullDistance: props.pullDistance, 43 | percent: props.percent, 44 | }; 45 | } 46 | 47 | setProgress({ pullDistance, percent }: { pullDistance: number; percent: number}) { 48 | this.setState({ 49 | pullDistance, 50 | percent, 51 | }); 52 | } 53 | 54 | UNSAFE_componentWillReceiveProps(nextProps: Readonly) { 55 | this.setState({ 56 | pullDistance: nextProps.pullDistance, 57 | percent: nextProps.percent, 58 | }); 59 | } 60 | 61 | render() { 62 | const { percentAnimatedValue, percent, refreshing } = this.props; 63 | const { percent: statePercent, pullDistance } = this.state; 64 | // console.log('header props 2222 ', statePercent, percent, refreshing); 65 | let text = 'pull to refresh '; 66 | if (statePercent >= 1) { 67 | if (refreshing) { 68 | text = 'refreshing...'; 69 | } else { 70 | text = 'release to refresh '; 71 | } 72 | } 73 | text += pullDistance.toFixed(2); 74 | return ( 75 | 76 | {text} 77 | 78 | ); 79 | } 80 | } -------------------------------------------------------------------------------- /examples/Demo/android/app/src/main/java/com/demo/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.demo; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import com.facebook.react.PackageList; 6 | import com.facebook.react.ReactApplication; 7 | import com.facebook.react.ReactNativeHost; 8 | import com.facebook.react.ReactPackage; 9 | import com.facebook.soloader.SoLoader; 10 | import java.lang.reflect.InvocationTargetException; 11 | import java.util.List; 12 | 13 | public class MainApplication extends Application implements ReactApplication { 14 | 15 | private final ReactNativeHost mReactNativeHost = 16 | new ReactNativeHost(this) { 17 | @Override 18 | public boolean getUseDeveloperSupport() { 19 | return BuildConfig.DEBUG; 20 | } 21 | 22 | @Override 23 | protected List getPackages() { 24 | @SuppressWarnings("UnnecessaryLocalVariable") 25 | List packages = new PackageList(this).getPackages(); 26 | // Packages that cannot be autolinked yet can be added manually here, for example: 27 | // packages.add(new MyReactNativePackage()); 28 | return packages; 29 | } 30 | 31 | @Override 32 | protected String getJSMainModuleName() { 33 | return "index"; 34 | } 35 | }; 36 | 37 | @Override 38 | public ReactNativeHost getReactNativeHost() { 39 | return mReactNativeHost; 40 | } 41 | 42 | @Override 43 | public void onCreate() { 44 | super.onCreate(); 45 | SoLoader.init(this, /* native exopackage */ false); 46 | initializeFlipper(this); // Remove this line if you don't want Flipper enabled 47 | } 48 | 49 | /** 50 | * Loads Flipper in React Native templates. 51 | * 52 | * @param context 53 | */ 54 | private static void initializeFlipper(Context context) { 55 | if (BuildConfig.DEBUG) { 56 | try { 57 | /* 58 | We use reflection here to pick up the class that initializes Flipper, 59 | since Flipper library is not available in release mode 60 | */ 61 | Class aClass = Class.forName("com.facebook.flipper.ReactNativeFlipper"); 62 | aClass.getMethod("initializeFlipper", Context.class).invoke(null, context); 63 | } catch (ClassNotFoundException e) { 64 | e.printStackTrace(); 65 | } catch (NoSuchMethodException e) { 66 | e.printStackTrace(); 67 | } catch (IllegalAccessException e) { 68 | e.printStackTrace(); 69 | } catch (InvocationTargetException e) { 70 | e.printStackTrace(); 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /lib/PullToRefresh.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Container for ScrollView/FlatList, providing custom pull-to-refresh Header support 3 | */ 4 | import { Component, ComponentType, RefAttributes } from 'react'; 5 | import { ViewStyle, Animated, PanResponderInstance, GestureResponderEvent, PanResponderGestureState, NativeSyntheticEvent, NativeScrollEvent } from 'react-native'; 6 | export interface PullToRefreshHeaderProps { 7 | pullDistance: number; 8 | percentAnimatedValue: Animated.AnimatedDivision; 9 | percent: number; 10 | refreshing: boolean; 11 | } 12 | export interface Props { 13 | style: ViewStyle; 14 | HeaderComponent: ComponentType>; 15 | headerHeight: number; 16 | refreshTriggerHeight?: number; 17 | refreshingHoldHeight?: number; 18 | refreshing: boolean; 19 | onRefresh: () => void; 20 | children: JSX.Element; 21 | topPullThreshold: number; 22 | } 23 | interface State { 24 | containerTop: Animated.Value; 25 | scrollEnabled: boolean; 26 | } 27 | export default class PullToRefresh extends Component { 28 | static defaultProps: { 29 | style: ViewStyle; 30 | refreshing: boolean; 31 | topPullThreshold: number; 32 | }; 33 | containerTranslateY: number; 34 | innerScrollTop: number; 35 | _panResponder: PanResponderInstance; 36 | headerRef: any; 37 | scrollRef: any; 38 | constructor(props: Props); 39 | updateInnerScrollRef: (ref: any) => void; 40 | onMoveShouldSetResponder(event: GestureResponderEvent, gestureState: PanResponderGestureState): boolean; 41 | onResponderGrant(event: GestureResponderEvent, gestureState: PanResponderGestureState): void; 42 | onResponderReject(event: GestureResponderEvent, gestureState: PanResponderGestureState): void; 43 | onPanResponderMove(event: GestureResponderEvent, gestureState: PanResponderGestureState): void; 44 | onPanResponderRelease(event: GestureResponderEvent, gestureState: PanResponderGestureState): void; 45 | onResponderTerminationRequest(event: GestureResponderEvent): boolean; 46 | onPanResponderTerminate(event: GestureResponderEvent, gestureState: PanResponderGestureState): void; 47 | _resetContainerPosition(): void; 48 | containerTopChange: ({ value }: { 49 | value: number; 50 | }) => void; 51 | innerScrollCallback: (event: NativeSyntheticEvent) => void; 52 | checkScroll: () => void; 53 | isInnerScrollTop(): boolean; 54 | componentDidUpdate(prevProps: Readonly, prevState: Readonly): void; 55 | componentWillUnmount(): void; 56 | renderHeader(): JSX.Element; 57 | render(): JSX.Element; 58 | } 59 | export {}; 60 | -------------------------------------------------------------------------------- /examples/Demo/ios/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '9.0' 2 | require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' 3 | 4 | target 'Demo' do 5 | # Pods for Demo 6 | pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector" 7 | pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec" 8 | pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired" 9 | pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety" 10 | pod 'React', :path => '../node_modules/react-native/' 11 | pod 'React-Core', :path => '../node_modules/react-native/' 12 | pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules' 13 | pod 'React-Core/DevSupport', :path => '../node_modules/react-native/' 14 | pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS' 15 | pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation' 16 | pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob' 17 | pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image' 18 | pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS' 19 | pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network' 20 | pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings' 21 | pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text' 22 | pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration' 23 | pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/' 24 | 25 | pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact' 26 | pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi' 27 | pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor' 28 | pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector' 29 | pod 'ReactCommon/jscallinvoker', :path => "../node_modules/react-native/ReactCommon" 30 | pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon" 31 | pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga' 32 | 33 | pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec' 34 | pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec' 35 | pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec' 36 | 37 | target 'DemoTests' do 38 | inherit! :search_paths 39 | # Pods for testing 40 | end 41 | 42 | use_native_modules! 43 | end 44 | 45 | target 'Demo-tvOS' do 46 | # Pods for Demo-tvOS 47 | 48 | target 'Demo-tvOSTests' do 49 | inherit! :search_paths 50 | # Pods for testing 51 | end 52 | 53 | end 54 | -------------------------------------------------------------------------------- /examples/Demo/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem http://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /examples/Demo/ios/Demo/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /examples/Demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "compilerOptions": { 4 | /* Basic Options */ 5 | "target": "esnext", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ 6 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 7 | "lib": ["es6"], /* Specify library files to be included in the compilation. */ 8 | "allowJs": true, /* Allow javascript files to be compiled. */ 9 | // "checkJs": true, /* Report errors in .js files. */ 10 | "jsx": "react-native", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 11 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 12 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 13 | // "outFile": "./", /* Concatenate and emit output to single file. */ 14 | // "outDir": "./", /* Redirect output structure to the directory. */ 15 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 16 | // "removeComments": true, /* Do not emit comments to output. */ 17 | "noEmit": true, /* Do not emit outputs. */ 18 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 19 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 20 | "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 21 | 22 | /* Strict Type-Checking Options */ 23 | "strict": true, /* Enable all strict type-checking options. */ 24 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 25 | // "strictNullChecks": true, /* Enable strict null checks. */ 26 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 27 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 28 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 29 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 30 | 31 | /* Additional Checks */ 32 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 33 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 34 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 35 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 36 | 37 | /* Module Resolution Options */ 38 | "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 39 | "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 40 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 41 | // "rootDirs": [ ".", "../../src/"], /* List of root folders whose combined content represents the structure of the project at runtime. */ 42 | // "typeRoots": [], /* List of folders to include type definitions from. */ 43 | // "types": [], /* Type declaration files to be included in compilation. */ 44 | "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 45 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 46 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 47 | 48 | /* Source Map Options */ 49 | // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 50 | // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ 51 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 52 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 53 | 54 | /* Experimental Options */ 55 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 56 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 57 | }, 58 | "exclude": [ 59 | "node_modules", "babel.config.js", "metro.config.js", "jest.config.js" 60 | ] 61 | } -------------------------------------------------------------------------------- /examples/Demo/ios/Demo.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /examples/Demo/ios/Demo.xcodeproj/xcshareddata/xcschemes/Demo-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-pull-to-refresh-custom 2 | 3 | Custom pull to refresh Header supporting for React Native ScrollView/FlatList 4 | 5 | React Native 自定义下拉刷新Header 6 | 7 | Online Expo demo here: [https://snack.expo.io/@sophister/custom-pull-to-refresh-header](https://snack.expo.io/@sophister/custom-pull-to-refresh-header) 8 | 9 | **WARN: use at your own risk!** 10 | 11 | ## Show Case 12 | 13 | ![running demo screenshot](./screenshot/demo.gif) 14 | 15 | ## Install 16 | 17 | ```shell 18 | npm i react-native-pull-to-refresh-custom 19 | ``` 20 | 21 | ## Usage 22 | 23 | **Notice:** It is only tested with `react-native@0.59.3` and `react-native@0.61.2`. 24 | 25 | `PullToRefresh` component can ONLY accept a **single** child, which must be one of `ScrollView`, `FlatList`. (I've only tested it with these two components. Theoretically, it *should* work with other **Scrollable** components such as `SectionList`). 26 | 27 | ```typescript 28 | //Props interface for PullToRefresh 29 | interface PullToRefreshProps { 30 | // container's style. You should give it a `backgroundColor`, without it, 31 | // the PanResponder will be terminated on iOS, according to my test 32 | style: ViewStyle; 33 | // your custom Header component, it will receive props of PullToRefreshHeaderProps 34 | HeaderComponent: ComponentType>; 35 | // Header component's height 36 | headerHeight: number; 37 | // pulling height to trigger `onRefresh` callback, default to `headerHeight` 38 | refreshTriggerHeight?: number; 39 | // container's sticky top position when `refreshing` is true, default to `headerHeight` 40 | refreshingHoldHeight?: number; 41 | // is refreshing 42 | refreshing: boolean; 43 | // parent's callback if user's pull distance trigger a refreshing 44 | onRefresh: () => void; 45 | // child component 46 | children: JSX.Element; 47 | // when the inner scrollable's contentOffset.y <= topPullThreshold, 48 | // pulling down will trigger container's translate 49 | topPullThreshold: number; 50 | } 51 | 52 | // Header component's Props interface 53 | interface PullToRefreshHeaderProps { 54 | // current pull distance of container component 55 | pullDistance: number; 56 | // current pull ratio range of [0, 1] 57 | percentAnimatedValue: Animated.AnimatedDivision; 58 | // current pull ratio, range of [0, 1] 59 | percent: number; 60 | // is currently refreshing 61 | refreshing: boolean; 62 | } 63 | ``` 64 | 65 | ```typescript 66 | import PullToRefresh, { PullToRefreshHeaderProps } from 'react-native-pull-to-refresh-custom'; 67 | 68 | class Header extends Component { 69 | // Header component **MUST** expose a `setProgress` method, 70 | // which is called when user is pulling container down 71 | // pullDistance is user's pull distance 72 | // percent is current pull ratio range of [0, 1] 73 | setProgress({ pullDistance, percent }: { pullDistance: number; percent: number}) { 74 | this.setState({ 75 | pullDistance, 76 | percent, 77 | }); 78 | } 79 | } 80 | 81 | 90 | 95 | 96 | ``` 97 | 98 | ### Header component WARNING 99 | 100 | Your custom `Header` component, **MUST** have a method called `setProgress`! 101 | 102 | Your custom `Header` component, **MUST** have a method called `setProgress`! 103 | 104 | Your custom `Header` component, **MUST** have a method called `setProgress`! 105 | 106 | **But why?** 107 | 108 | I've tried to pass the `pullDistance` and `percent` to header component through the traditional `React`'s props flow. To do so, I've to keep `pullDistance` on `PullToRefresh`'s `state`, and call `setState()` every time when user is pulling down the container. But it results in a janky animation. So, I decide to pass `pullDistance` to the header component through a method call. 109 | 110 | ### PullToRefresh style WARNING 111 | 112 | When I test `PullToRefresh` component on **iOS**, the container's pan responder will be terminated after it is granted, if I don't give it a `backgroundColor`. So, `PullToRefresh` will have a `white` background color default. 113 | 114 | ## Implementation detail 115 | 116 | Basically, `PullTeRefresh` is just a wrapper, the view hierarchy is simple like below: 117 | 118 | ```typescript 119 | 120 | 121 | 122 | 123 | 124 | 125 | ``` 126 | 127 | Your custom Header component is within an `Animated.View`, which is `absolute` positioned with `top` equals `- props.headerHeight`, so that the header is not visible by default. 128 | 129 | `PullToRefresh` has a **property** to track the scroll position of inner `FlatList`. 130 | When the inner `FlatList`'s scrollTop is `<=` `topPullThreshold` (which defaults to 2), and if user tries to pull down, the container will catch user's drag action. Along user pulling down, it translates the `Animated.View` into visible region, and passes the `pullDistance` and `percent` to your custom Header component constantly through calling Header's `setProgress` directly. 131 | 132 | When user releases their finger, `PullToRefresh` will check current `pullDistance`. If it's >= `props.refreshTriggerHeight`, it will call `props.onRefresh`; otherwise, it will animate the `Animated.View` back to it's hidden position. 133 | 134 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | // "incremental": true, /* Enable incremental compilation */ 5 | "target": "esnext", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ 6 | "module": "esnext", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 7 | "lib": ["esnext"], /* Specify library files to be included in the compilation. */ 8 | // "allowJs": true, /* Allow javascript files to be compiled. */ 9 | // "checkJs": true, /* Report errors in .js files. */ 10 | "jsx": "react-native", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 11 | "declaration": true, /* Generates corresponding '.d.ts' file. */ 12 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 13 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 14 | // "outFile": "./", /* Concatenate and emit output to single file. */ 15 | "outDir": "./lib", /* Redirect output structure to the directory. */ 16 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 17 | // "composite": true, /* Enable project compilation */ 18 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 19 | // "removeComments": true, /* Do not emit comments to output. */ 20 | // "noEmit": true, /* Do not emit outputs. */ 21 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 22 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 23 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 24 | 25 | /* Strict Type-Checking Options */ 26 | "strict": true, /* Enable all strict type-checking options. */ 27 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 28 | // "strictNullChecks": true, /* Enable strict null checks. */ 29 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 30 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 31 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 32 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 33 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 34 | 35 | /* Additional Checks */ 36 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 37 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 38 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 39 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 40 | 41 | /* Module Resolution Options */ 42 | "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 43 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 44 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 45 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 46 | // "typeRoots": [], /* List of folders to include type definitions from. */ 47 | // "types": [], /* Type declaration files to be included in compilation. */ 48 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 49 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 50 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 51 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 52 | 53 | /* Source Map Options */ 54 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 55 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 56 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 57 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 58 | 59 | /* Experimental Options */ 60 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 61 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 62 | "skipLibCheck": true 63 | }, 64 | "include": ["src"], 65 | "exclude": ["node_modules", "examples", "lib"] 66 | } 67 | -------------------------------------------------------------------------------- /examples/Demo/js/FlatList.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * demo of using FlatList with custom pull-to-refresh header 3 | */ 4 | import React, { useEffect } from 'react'; 5 | import { 6 | Text, 7 | View, 8 | ScrollView, 9 | FlatList, 10 | Animated, 11 | PanResponder, 12 | ViewStyle, 13 | TextStyle, 14 | Alert, 15 | } from 'react-native'; 16 | 17 | // import LottieView from 'lottie-react-native'; 18 | 19 | import PullToRefresh, { PullToRefreshHeaderProps } from '../../../src/PullToRefresh'; 20 | import Header from './Header'; 21 | import NestScrollView from './NestScrollView'; 22 | 23 | const { Component } = React; 24 | 25 | interface DataItem { 26 | key: string; 27 | text: string; 28 | on: boolean; 29 | } 30 | 31 | const data: DataItem[] = []; 32 | for (let i = 0; i < 500; i++) { 33 | data.push({ 34 | key: `data-${i}`, 35 | text: `number: ${i}`, 36 | on: false, 37 | }); 38 | } 39 | 40 | const pageStyle = { 41 | container: { 42 | flex: 1, 43 | justifyContent: 'center', 44 | backgroundColor: '#ecf0f1', 45 | padding: 0, 46 | } as ViewStyle, 47 | listCon: { 48 | flex: 1, 49 | backgroundColor: 'blue', 50 | } as ViewStyle, 51 | item: { 52 | flexDirection: 'row', 53 | height: 80, 54 | alignItems: 'center', 55 | paddingLeft: 15, 56 | backgroundColor: 'pink', 57 | } as ViewStyle, 58 | itemOdd: { 59 | backgroundColor: 'green', 60 | }, 61 | itemText: { 62 | color: '#fff', 63 | textAlign: 'left', 64 | fontSize: 28, 65 | } as TextStyle, 66 | }; 67 | 68 | interface State { 69 | refreshing: boolean; 70 | data: DataItem[]; 71 | } 72 | 73 | function ItemView({children, index}: { children: React.ReactElement, index: number}) { 74 | useEffect(function(){ 75 | console.log('====== item loaded = ' + index); 76 | }, []); 77 | return children; 78 | } 79 | 80 | export default class App extends React.Component<{}, State> { 81 | state = { 82 | data: data.slice(0, 50), 83 | refreshing: false, 84 | }; 85 | 86 | _renderItem = (item: DataItem, index: number, prefix = '') => { 87 | const conStyles = [pageStyle.item]; 88 | if (index % 2 === 1) { 89 | conStyles.push(pageStyle.itemOdd); 90 | } 91 | return ( 92 | 93 | 94 | { Alert.alert('click', item.text); }} style={pageStyle.itemText}>in page {prefix} {item.text} 95 | 96 | 97 | ); 98 | }; 99 | 100 | onRefresh = () => { 101 | this.setState({ 102 | refreshing: true, 103 | }); 104 | setTimeout(() => { 105 | this.setState((prevState) => { 106 | return { 107 | refreshing: false, 108 | data: prevState.data.concat(data.slice(prevState.data.length, prevState.data.length + 50)), 109 | }; 110 | }); 111 | }, 3000); 112 | }; 113 | 114 | // 测试 FlatList 嵌套 115 | flatListTest() { 116 | return ( 117 | 126 | { return this._renderItem(item, index, 'FlatList'); }} 132 | /> 133 | 134 | ); 135 | } 136 | 137 | scrollViewTest() { 138 | return ( 139 | 148 | 149 | {this.state.data.map((obj, index) =>{ 150 | return this._renderItem(obj, index, 'scroll3'); 151 | })} 152 | 153 | 154 | ); 155 | } 156 | 157 | nestScrollViewTest() { 158 | return ( 159 | 160 | { return this._renderItem(item, index, 'FlatList'); }} 166 | /> 167 | 168 | ); 169 | } 170 | 171 | nestScrollTest2() { 172 | return ( 173 | 174 | 175 | {this.state.data.map((obj, index) =>{ 176 | return this._renderItem(obj, index, 'scroll2'); 177 | })} 178 | 179 | 180 | ); 181 | } 182 | 183 | snapTest() { 184 | return ( 185 | { return this._renderItem(item, index, 'FlatList'); }} 192 | /> 193 | ); 194 | } 195 | 196 | render() { 197 | const { state } = this; 198 | return ( 199 | 200 | { this.scrollViewTest() } 201 | 202 | ); 203 | } 204 | } 205 | 206 | 207 | -------------------------------------------------------------------------------- /examples/Demo/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | # Determine the Java command to use to start the JVM. 86 | if [ -n "$JAVA_HOME" ] ; then 87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 88 | # IBM's JDK on AIX uses strange locations for the executables 89 | JAVACMD="$JAVA_HOME/jre/sh/java" 90 | else 91 | JAVACMD="$JAVA_HOME/bin/java" 92 | fi 93 | if [ ! -x "$JAVACMD" ] ; then 94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 95 | 96 | Please set the JAVA_HOME variable in your environment to match the 97 | location of your Java installation." 98 | fi 99 | else 100 | JAVACMD="java" 101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 102 | 103 | Please set the JAVA_HOME variable in your environment to match the 104 | location of your Java installation." 105 | fi 106 | 107 | # Increase the maximum file descriptors if we can. 108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 109 | MAX_FD_LIMIT=`ulimit -H -n` 110 | if [ $? -eq 0 ] ; then 111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 112 | MAX_FD="$MAX_FD_LIMIT" 113 | fi 114 | ulimit -n $MAX_FD 115 | if [ $? -ne 0 ] ; then 116 | warn "Could not set maximum file descriptor limit: $MAX_FD" 117 | fi 118 | else 119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 120 | fi 121 | fi 122 | 123 | # For Darwin, add options to specify how the application appears in the dock 124 | if $darwin; then 125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 126 | fi 127 | 128 | # For Cygwin, switch paths to Windows format before running java 129 | if $cygwin ; then 130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 132 | JAVACMD=`cygpath --unix "$JAVACMD"` 133 | 134 | # We build the pattern for arguments to be converted via cygpath 135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 136 | SEP="" 137 | for dir in $ROOTDIRSRAW ; do 138 | ROOTDIRS="$ROOTDIRS$SEP$dir" 139 | SEP="|" 140 | done 141 | OURCYGPATTERN="(^($ROOTDIRS))" 142 | # Add a user-defined pattern to the cygpath arguments 143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 145 | fi 146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 147 | i=0 148 | for arg in "$@" ; do 149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 151 | 152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 154 | else 155 | eval `echo args$i`="\"$arg\"" 156 | fi 157 | i=$((i+1)) 158 | done 159 | case $i in 160 | (0) set -- ;; 161 | (1) set -- "$args0" ;; 162 | (2) set -- "$args0" "$args1" ;; 163 | (3) set -- "$args0" "$args1" "$args2" ;; 164 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 165 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 166 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 167 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 168 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 169 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 170 | esac 171 | fi 172 | 173 | # Escape application args 174 | save () { 175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 176 | echo " " 177 | } 178 | APP_ARGS=$(save "$@") 179 | 180 | # Collect all arguments for the java command, following the shell quoting and substitution rules 181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 182 | 183 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 184 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 185 | cd "$(dirname "$0")" 186 | fi 187 | 188 | exec "$JAVACMD" "$@" 189 | -------------------------------------------------------------------------------- /examples/Demo/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | 3 | import com.android.build.OutputFile 4 | 5 | /** 6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets 7 | * and bundleReleaseJsAndAssets). 8 | * These basically call `react-native bundle` with the correct arguments during the Android build 9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the 10 | * bundle directly from the development server. Below you can see all the possible configurations 11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the 12 | * `apply from: "../../node_modules/react-native/react.gradle"` line. 13 | * 14 | * project.ext.react = [ 15 | * // the name of the generated asset file containing your JS bundle 16 | * bundleAssetName: "index.android.bundle", 17 | * 18 | * // the entry file for bundle generation 19 | * entryFile: "index.android.js", 20 | * 21 | * // https://facebook.github.io/react-native/docs/performance#enable-the-ram-format 22 | * bundleCommand: "ram-bundle", 23 | * 24 | * // whether to bundle JS and assets in debug mode 25 | * bundleInDebug: false, 26 | * 27 | * // whether to bundle JS and assets in release mode 28 | * bundleInRelease: true, 29 | * 30 | * // whether to bundle JS and assets in another build variant (if configured). 31 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants 32 | * // The configuration property can be in the following formats 33 | * // 'bundleIn${productFlavor}${buildType}' 34 | * // 'bundleIn${buildType}' 35 | * // bundleInFreeDebug: true, 36 | * // bundleInPaidRelease: true, 37 | * // bundleInBeta: true, 38 | * 39 | * // whether to disable dev mode in custom build variants (by default only disabled in release) 40 | * // for example: to disable dev mode in the staging build type (if configured) 41 | * devDisabledInStaging: true, 42 | * // The configuration property can be in the following formats 43 | * // 'devDisabledIn${productFlavor}${buildType}' 44 | * // 'devDisabledIn${buildType}' 45 | * 46 | * // the root of your project, i.e. where "package.json" lives 47 | * root: "../../", 48 | * 49 | * // where to put the JS bundle asset in debug mode 50 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", 51 | * 52 | * // where to put the JS bundle asset in release mode 53 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release", 54 | * 55 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 56 | * // require('./image.png')), in debug mode 57 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", 58 | * 59 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 60 | * // require('./image.png')), in release mode 61 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", 62 | * 63 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means 64 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to 65 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle 66 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ 67 | * // for example, you might want to remove it from here. 68 | * inputExcludes: ["android/**", "ios/**"], 69 | * 70 | * // override which node gets called and with what additional arguments 71 | * nodeExecutableAndArgs: ["node"], 72 | * 73 | * // supply additional arguments to the packager 74 | * extraPackagerArgs: [] 75 | * ] 76 | */ 77 | 78 | project.ext.react = [ 79 | entryFile: "index.js", 80 | enableHermes: false, // clean and rebuild if changing 81 | ] 82 | 83 | apply from: "../../node_modules/react-native/react.gradle" 84 | 85 | /** 86 | * Set this to true to create two separate APKs instead of one: 87 | * - An APK that only works on ARM devices 88 | * - An APK that only works on x86 devices 89 | * The advantage is the size of the APK is reduced by about 4MB. 90 | * Upload all the APKs to the Play Store and people will download 91 | * the correct one based on the CPU architecture of their device. 92 | */ 93 | def enableSeparateBuildPerCPUArchitecture = false 94 | 95 | /** 96 | * Run Proguard to shrink the Java bytecode in release builds. 97 | */ 98 | def enableProguardInReleaseBuilds = false 99 | 100 | /** 101 | * The preferred build flavor of JavaScriptCore. 102 | * 103 | * For example, to use the international variant, you can use: 104 | * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` 105 | * 106 | * The international variant includes ICU i18n library and necessary data 107 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that 108 | * give correct results when using with locales other than en-US. Note that 109 | * this variant is about 6MiB larger per architecture than default. 110 | */ 111 | def jscFlavor = 'org.webkit:android-jsc:+' 112 | 113 | /** 114 | * Whether to enable the Hermes VM. 115 | * 116 | * This should be set on project.ext.react and mirrored here. If it is not set 117 | * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode 118 | * and the benefits of using Hermes will therefore be sharply reduced. 119 | */ 120 | def enableHermes = project.ext.react.get("enableHermes", false); 121 | 122 | android { 123 | compileSdkVersion rootProject.ext.compileSdkVersion 124 | 125 | compileOptions { 126 | sourceCompatibility JavaVersion.VERSION_1_8 127 | targetCompatibility JavaVersion.VERSION_1_8 128 | } 129 | 130 | defaultConfig { 131 | applicationId "com.demo" 132 | minSdkVersion rootProject.ext.minSdkVersion 133 | targetSdkVersion rootProject.ext.targetSdkVersion 134 | versionCode 1 135 | versionName "1.0" 136 | } 137 | splits { 138 | abi { 139 | reset() 140 | enable enableSeparateBuildPerCPUArchitecture 141 | universalApk false // If true, also generate a universal APK 142 | include "armeabi-v7a", "x86", "arm64-v8a", "x86_64" 143 | } 144 | } 145 | signingConfigs { 146 | debug { 147 | storeFile file('debug.keystore') 148 | storePassword 'android' 149 | keyAlias 'androiddebugkey' 150 | keyPassword 'android' 151 | } 152 | } 153 | buildTypes { 154 | debug { 155 | signingConfig signingConfigs.debug 156 | } 157 | release { 158 | // Caution! In production, you need to generate your own keystore file. 159 | // see https://facebook.github.io/react-native/docs/signed-apk-android. 160 | signingConfig signingConfigs.debug 161 | minifyEnabled enableProguardInReleaseBuilds 162 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 163 | } 164 | } 165 | // applicationVariants are e.g. debug, release 166 | applicationVariants.all { variant -> 167 | variant.outputs.each { output -> 168 | // For each separate APK per architecture, set a unique version code as described here: 169 | // https://developer.android.com/studio/build/configure-apk-splits.html 170 | def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] 171 | def abi = output.getFilter(OutputFile.ABI) 172 | if (abi != null) { // null for the universal-debug, universal-release variants 173 | output.versionCodeOverride = 174 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode 175 | } 176 | 177 | } 178 | } 179 | } 180 | 181 | dependencies { 182 | implementation fileTree(dir: "libs", include: ["*.jar"]) 183 | implementation "com.facebook.react:react-native:+" // From node_modules 184 | 185 | if (enableHermes) { 186 | def hermesPath = "../../node_modules/hermes-engine/android/"; 187 | debugImplementation files(hermesPath + "hermes-debug.aar") 188 | releaseImplementation files(hermesPath + "hermes-release.aar") 189 | } else { 190 | implementation jscFlavor 191 | } 192 | } 193 | 194 | // Run this once to be able to run the application with BUCK 195 | // puts all compile dependencies into folder libs for BUCK to use 196 | task copyDownloadableDepsToLibs(type: Copy) { 197 | from configurations.compile 198 | into 'libs' 199 | } 200 | 201 | apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) 202 | -------------------------------------------------------------------------------- /lib/PullToRefresh.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Container for ScrollView/FlatList, providing custom pull-to-refresh Header support 3 | */ 4 | import React, { Component } from 'react'; 5 | import { View, Animated, PanResponder, } from 'react-native'; 6 | const styles = { 7 | con: { 8 | flex: 1, 9 | // Android上,不设置这个背景色,貌似会触发 onPanResponderTerminate !!! 10 | backgroundColor: '#fff', 11 | }, 12 | }; 13 | export default class PullToRefresh extends Component { 14 | constructor(props) { 15 | super(props); 16 | // 当前容器移动的距离 17 | this.containerTranslateY = 0; 18 | // 内部scroll容器顶部滚动的距离 19 | this.innerScrollTop = 0; 20 | // header 组件的引用 21 | this.headerRef = null; 22 | // inner scroll ref 23 | this.scrollRef = null; 24 | this.updateInnerScrollRef = (ref) => { 25 | // console.log('====== updateInnerScrollRef ', ref && ref.scrollToOffset); 26 | this.scrollRef = ref; 27 | }; 28 | // 下拉容器的过程中,动态传递下拉的距离给 header 组件,直接调用方法,不走本组件的 setState,避免卡顿 29 | this.containerTopChange = ({ value }) => { 30 | this.containerTranslateY = value; 31 | if (this.headerRef) { 32 | this.headerRef.setProgress({ 33 | pullDistance: value, 34 | percent: value / (this.props.refreshTriggerHeight || this.props.headerHeight), 35 | }); 36 | } 37 | }; 38 | this.innerScrollCallback = (event) => { 39 | this.innerScrollTop = event.nativeEvent.contentOffset.y; 40 | this.checkScroll(); 41 | }; 42 | this.checkScroll = () => { 43 | if (this.isInnerScrollTop()) { 44 | if (this.state.scrollEnabled) { 45 | this.setState({ 46 | scrollEnabled: false, 47 | }); 48 | } 49 | } 50 | else { 51 | if (!this.state.scrollEnabled) { 52 | this.setState({ 53 | scrollEnabled: true, 54 | }); 55 | } 56 | } 57 | }; 58 | this.state = { 59 | // 容器偏离顶部的距离 60 | containerTop: new Animated.Value(0), 61 | // 是否允许内部scrollview滚动 62 | scrollEnabled: false, 63 | }; 64 | this.state.containerTop.addListener(this.containerTopChange); 65 | // this.onStartShouldSetResponder = this.onStartShouldSetResponder.bind(this); 66 | this.onMoveShouldSetResponder = this.onMoveShouldSetResponder.bind(this); 67 | this.onResponderGrant = this.onResponderGrant.bind(this); 68 | this.onResponderReject = this.onResponderReject.bind(this); 69 | this.onPanResponderMove = this.onPanResponderMove.bind(this); 70 | this.onPanResponderRelease = this.onPanResponderRelease.bind(this); 71 | this.onPanResponderTerminate = this.onPanResponderTerminate.bind(this); 72 | this.onResponderTerminationRequest = this.onResponderTerminationRequest.bind(this); 73 | this._panResponder = PanResponder.create({ 74 | // onStartShouldSetPanResponder: this.onStartShouldSetResponder, 75 | onMoveShouldSetPanResponderCapture: this.onMoveShouldSetResponder, 76 | // onMoveShouldSetPanResponder: this.onMoveShouldSetResponder, 77 | onPanResponderGrant: this.onResponderGrant, 78 | onPanResponderReject: this.onResponderReject, 79 | onPanResponderMove: this.onPanResponderMove, 80 | onPanResponderRelease: this.onPanResponderRelease, 81 | onPanResponderTerminationRequest: this.onResponderTerminationRequest, 82 | onPanResponderTerminate: this.onPanResponderTerminate, 83 | onShouldBlockNativeResponder: (evt, gestureState) => { 84 | // Returns whether this component should block native components from becoming the JS 85 | // responder. Returns true by default. Is currently only supported on android. 86 | return true; 87 | }, 88 | }); 89 | } 90 | // updateInnerScrollState(enabled: boolean) { 91 | // if (this.scrollRef) { 92 | // console.log('====== innerScroll ', enabled); 93 | // this.scrollRef.setNativeProps({ 94 | // scrollEnabled: enabled, 95 | // }); 96 | // } 97 | // } 98 | // onStartShouldSetResponder(event, gestureState) { 99 | // console.log('onStartShouldSetResponder', gestureState); 100 | // return false; 101 | // } 102 | onMoveShouldSetResponder(event, gestureState) { 103 | if (this.props.refreshing) { 104 | // 正在刷新中,不接受再次下拉 105 | return false; 106 | } 107 | return !this.state.scrollEnabled; 108 | if (this.innerScrollTop <= this.props.topPullThreshold && gestureState.dy > 0) { 109 | console.log(`====== moveShouldSetResponder true`); 110 | return true; 111 | } 112 | console.log(`====== moveShouldSetResponder false`, this.innerScrollTop, gestureState.dy); 113 | return false; 114 | } 115 | onResponderGrant(event, gestureState) { 116 | // console.log(`====== grant`); 117 | } 118 | onResponderReject(event, gestureState) { 119 | // console.log(`====== reject`); 120 | } 121 | onPanResponderMove(event, gestureState) { 122 | if (gestureState.dy >= 0) { 123 | // const dy = Math.max(0, gestureState.dy); 124 | this.state.containerTop.setValue(gestureState.dy); 125 | } 126 | else { 127 | this.state.containerTop.setValue(0); 128 | if (this.scrollRef) { 129 | if (typeof this.scrollRef.scrollToOffset === 'function') { 130 | // inner is FlatList 131 | this.scrollRef.scrollToOffset({ 132 | offset: -gestureState.dy, 133 | animated: true, 134 | }); 135 | } 136 | else if (typeof this.scrollRef.scrollTo === 'function') { 137 | // inner is ScrollView 138 | this.scrollRef.scrollTo({ 139 | y: -gestureState.dy, 140 | animated: true, 141 | }); 142 | } 143 | } 144 | } 145 | } 146 | onPanResponderRelease(event, gestureState) { 147 | // 判断是否达到了触发刷新的条件 148 | const threshold = this.props.refreshTriggerHeight || this.props.headerHeight; 149 | if (this.containerTranslateY >= threshold) { 150 | // 触发刷新 151 | this.props.onRefresh(); 152 | } 153 | else { 154 | // 没到刷新的位置,回退到顶部 155 | this._resetContainerPosition(); 156 | } 157 | this.checkScroll(); 158 | } 159 | onResponderTerminationRequest(event) { 160 | // console.log(`====== terminate request`); 161 | return false; 162 | } 163 | onPanResponderTerminate(event, gestureState) { 164 | // console.log(`====== terminate`, this.innerScrollTop, gestureState.dy, gestureState.dy); 165 | this._resetContainerPosition(); 166 | this.checkScroll(); 167 | } 168 | _resetContainerPosition() { 169 | Animated.timing(this.state.containerTop, { 170 | toValue: 0, 171 | duration: 250, 172 | useNativeDriver: true, 173 | }).start(); 174 | } 175 | isInnerScrollTop() { 176 | return this.innerScrollTop <= this.props.topPullThreshold; 177 | } 178 | componentDidUpdate(prevProps, prevState) { 179 | if (!prevProps.refreshing && this.props.refreshing) { 180 | // 从 未加载 变化到 加载中 181 | const holdHeight = this.props.refreshingHoldHeight || this.props.headerHeight; 182 | Animated.timing(this.state.containerTop, { 183 | toValue: holdHeight, 184 | duration: 150, 185 | useNativeDriver: true, 186 | }).start(); 187 | } 188 | else if (prevProps.refreshing && !this.props.refreshing) { 189 | // 从 加载中 变化到 未加载 190 | Animated.timing(this.state.containerTop, { 191 | toValue: 0, 192 | duration: 250, 193 | useNativeDriver: true, 194 | }).start(); 195 | } 196 | } 197 | componentWillUnmount() { 198 | this.state.containerTop.removeAllListeners(); 199 | } 200 | renderHeader() { 201 | const style = { 202 | position: 'absolute', 203 | left: 0, 204 | width: '100%', 205 | top: -this.props.headerHeight, 206 | transform: [{ translateY: this.state.containerTop }], 207 | }; 208 | const percent = Animated.divide(this.state.containerTop, this.props.refreshTriggerHeight || this.props.headerHeight); 209 | const Header = this.props.HeaderComponent; 210 | return ( 211 |
{ this.headerRef = c; }} percentAnimatedValue={percent} pullDistance={this.containerTranslateY} percent={this.containerTranslateY / this.props.headerHeight} refreshing={this.props.refreshing}/> 212 | ); 213 | } 214 | render() { 215 | const child = React.cloneElement(this.props.children, { 216 | onScroll: this.innerScrollCallback, 217 | bounces: false, 218 | alwaysBounceVertical: false, 219 | scrollEnabled: this.state.scrollEnabled, 220 | ref: this.updateInnerScrollRef, 221 | }); 222 | return ( 223 | 224 | {child} 225 | 226 | {this.renderHeader()} 227 | ); 228 | } 229 | } 230 | PullToRefresh.defaultProps = { 231 | style: styles.con, 232 | refreshing: false, 233 | topPullThreshold: 2, 234 | }; 235 | -------------------------------------------------------------------------------- /src/PullToRefresh.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Container for ScrollView/FlatList, providing custom pull-to-refresh Header support 3 | */ 4 | 5 | import React, { Component, ComponentType, RefAttributes } from 'react'; 6 | import { 7 | View, 8 | ViewStyle, 9 | Animated, 10 | PanResponder, 11 | PanResponderInstance, 12 | GestureResponderEvent, 13 | PanResponderGestureState, 14 | NativeSyntheticEvent, 15 | NativeScrollEvent, 16 | } from 'react-native'; 17 | 18 | export interface PullToRefreshHeaderProps { 19 | // 当前下拉的距离,也穿给header,方便组件内部进行各种自定义计算 20 | pullDistance: number; 21 | // 当前下拉的百分比 [0, 1] 22 | percentAnimatedValue: Animated.AnimatedDivision; 23 | // 下拉百分比 [0, 1] 因为percentAnimatedValue 不能直接读取当前值,需要给header直接一个当前比例,方便内部处理 24 | percent: number; 25 | // 当前是否正在刷新中 26 | refreshing: boolean; 27 | } 28 | 29 | export interface Props { 30 | // 容器样式 31 | style: ViewStyle; 32 | // 下拉刷新的header组件类 33 | HeaderComponent: ComponentType>; 34 | // Header 组件的高度,也是触发刷新的下拉距离 35 | headerHeight: number; 36 | // 下拉过程中,可以触发刷新的下拉距离。不穿,则默认等于 headerHeight 37 | refreshTriggerHeight?: number; 38 | // 正在刷新时,容器保持的顶部距离,如果用户不传,则默认等于 headerHeight 39 | refreshingHoldHeight?: number; 40 | // 当前是否正在下拉刷新请求数据中 41 | refreshing: boolean; 42 | // 下拉刷新达到阈值时,回调父级 43 | onRefresh: () => void; 44 | // 子组件,只能是 ScrollView/FlatList 等 45 | children: JSX.Element; 46 | // 内部滚动组件,contentOffset.y <= topPullThreshold 时,触发顶部的下拉刷新动作 47 | topPullThreshold: number; 48 | } 49 | 50 | interface State { 51 | // 容器顶部的偏移距离 52 | containerTop: Animated.Value; 53 | scrollEnabled: boolean; 54 | } 55 | 56 | const styles = { 57 | con: { 58 | flex: 1, 59 | // Android上,不设置这个背景色,貌似会触发 onPanResponderTerminate !!! 60 | backgroundColor: '#fff', 61 | } as ViewStyle, 62 | }; 63 | 64 | export default class PullToRefresh extends Component { 65 | static defaultProps = { 66 | style: styles.con, 67 | refreshing: false, 68 | topPullThreshold: 2, 69 | }; 70 | 71 | // 当前容器移动的距离 72 | containerTranslateY: number = 0; 73 | 74 | // 内部scroll容器顶部滚动的距离 75 | innerScrollTop: number = 0; 76 | 77 | // 容器上的 PanResponder 78 | _panResponder: PanResponderInstance; 79 | 80 | // header 组件的引用 81 | headerRef: any = null; 82 | 83 | // inner scroll ref 84 | scrollRef: any = null; 85 | 86 | constructor(props: Props) { 87 | super(props); 88 | 89 | this.state = { 90 | // 容器偏离顶部的距离 91 | containerTop: new Animated.Value(0), 92 | // 是否允许内部scrollview滚动 93 | scrollEnabled: false, 94 | }; 95 | 96 | this.state.containerTop.addListener(this.containerTopChange); 97 | 98 | // this.onStartShouldSetResponder = this.onStartShouldSetResponder.bind(this); 99 | this.onMoveShouldSetResponder = this.onMoveShouldSetResponder.bind(this); 100 | this.onResponderGrant = this.onResponderGrant.bind(this); 101 | this.onResponderReject = this.onResponderReject.bind(this); 102 | this.onPanResponderMove = this.onPanResponderMove.bind(this); 103 | this.onPanResponderRelease = this.onPanResponderRelease.bind(this); 104 | this.onPanResponderTerminate = this.onPanResponderTerminate.bind(this); 105 | this.onResponderTerminationRequest = this.onResponderTerminationRequest.bind(this); 106 | 107 | this._panResponder = PanResponder.create({ 108 | // onStartShouldSetPanResponder: this.onStartShouldSetResponder, 109 | onMoveShouldSetPanResponderCapture: this.onMoveShouldSetResponder, 110 | // onMoveShouldSetPanResponder: this.onMoveShouldSetResponder, 111 | onPanResponderGrant: this.onResponderGrant, 112 | onPanResponderReject: this.onResponderReject, 113 | onPanResponderMove: this.onPanResponderMove, 114 | onPanResponderRelease: this.onPanResponderRelease, 115 | onPanResponderTerminationRequest: this.onResponderTerminationRequest, 116 | onPanResponderTerminate: this.onPanResponderTerminate, 117 | onShouldBlockNativeResponder: (evt, gestureState) => { 118 | // Returns whether this component should block native components from becoming the JS 119 | // responder. Returns true by default. Is currently only supported on android. 120 | return true; 121 | }, 122 | }); 123 | } 124 | 125 | updateInnerScrollRef = (ref: any) => { 126 | // console.log('====== updateInnerScrollRef ', ref && ref.scrollToOffset); 127 | this.scrollRef = ref; 128 | }; 129 | 130 | // updateInnerScrollState(enabled: boolean) { 131 | // if (this.scrollRef) { 132 | // console.log('====== innerScroll ', enabled); 133 | // this.scrollRef.setNativeProps({ 134 | // scrollEnabled: enabled, 135 | // }); 136 | // } 137 | // } 138 | 139 | // onStartShouldSetResponder(event, gestureState) { 140 | // console.log('onStartShouldSetResponder', gestureState); 141 | // return false; 142 | // } 143 | 144 | onMoveShouldSetResponder(event: GestureResponderEvent, gestureState: PanResponderGestureState) { 145 | if (this.props.refreshing) { 146 | // 正在刷新中,不接受再次下拉 147 | return false; 148 | } 149 | return !this.state.scrollEnabled; 150 | if (this.innerScrollTop <= this.props.topPullThreshold && gestureState.dy > 0) { 151 | console.log(`====== moveShouldSetResponder true`); 152 | return true; 153 | } 154 | console.log(`====== moveShouldSetResponder false`, this.innerScrollTop, gestureState.dy); 155 | return false; 156 | } 157 | 158 | onResponderGrant(event: GestureResponderEvent, gestureState: PanResponderGestureState) { 159 | // console.log(`====== grant`); 160 | } 161 | 162 | onResponderReject(event: GestureResponderEvent, gestureState: PanResponderGestureState) { 163 | // console.log(`====== reject`); 164 | } 165 | 166 | onPanResponderMove(event: GestureResponderEvent, gestureState: PanResponderGestureState) { 167 | if (gestureState.dy >= 0) { 168 | // const dy = Math.max(0, gestureState.dy); 169 | this.state.containerTop.setValue(gestureState.dy); 170 | } else { 171 | this.state.containerTop.setValue(0); 172 | if (this.scrollRef) { 173 | if (typeof this.scrollRef.scrollToOffset === 'function') { 174 | // inner is FlatList 175 | this.scrollRef.scrollToOffset({ 176 | offset: -gestureState.dy, 177 | animated: true, 178 | }); 179 | } else if(typeof this.scrollRef.scrollTo === 'function') { 180 | // inner is ScrollView 181 | this.scrollRef.scrollTo({ 182 | y: -gestureState.dy, 183 | animated: true, 184 | }); 185 | } 186 | } 187 | } 188 | } 189 | 190 | onPanResponderRelease(event: GestureResponderEvent, gestureState: PanResponderGestureState) { 191 | // 判断是否达到了触发刷新的条件 192 | const threshold = this.props.refreshTriggerHeight || this.props.headerHeight; 193 | if (this.containerTranslateY >= threshold) { 194 | // 触发刷新 195 | this.props.onRefresh(); 196 | } else { 197 | // 没到刷新的位置,回退到顶部 198 | this._resetContainerPosition(); 199 | } 200 | this.checkScroll(); 201 | } 202 | 203 | onResponderTerminationRequest(event: GestureResponderEvent): boolean { 204 | // console.log(`====== terminate request`); 205 | return false; 206 | } 207 | 208 | onPanResponderTerminate(event: GestureResponderEvent, gestureState: PanResponderGestureState) { 209 | // console.log(`====== terminate`, this.innerScrollTop, gestureState.dy, gestureState.dy); 210 | this._resetContainerPosition(); 211 | this.checkScroll(); 212 | } 213 | 214 | _resetContainerPosition() { 215 | Animated.timing(this.state.containerTop, { 216 | toValue: 0, 217 | duration: 250, 218 | useNativeDriver: true, 219 | }).start(); 220 | } 221 | 222 | // 下拉容器的过程中,动态传递下拉的距离给 header 组件,直接调用方法,不走本组件的 setState,避免卡顿 223 | containerTopChange = ({ value }: { value: number }) => { 224 | this.containerTranslateY = value; 225 | if (this.headerRef) { 226 | this.headerRef.setProgress({ 227 | pullDistance: value, 228 | percent: value / (this.props.refreshTriggerHeight || this.props.headerHeight), 229 | }); 230 | } 231 | }; 232 | 233 | innerScrollCallback = (event: NativeSyntheticEvent) => { 234 | this.innerScrollTop = event.nativeEvent.contentOffset.y; 235 | this.checkScroll(); 236 | }; 237 | 238 | checkScroll = () => { 239 | if (this.isInnerScrollTop()) { 240 | if (this.state.scrollEnabled) { 241 | this.setState({ 242 | scrollEnabled: false, 243 | }); 244 | } 245 | } else { 246 | if (!this.state.scrollEnabled) { 247 | this.setState({ 248 | scrollEnabled: true, 249 | }); 250 | } 251 | } 252 | }; 253 | 254 | isInnerScrollTop() { 255 | return this.innerScrollTop <= this.props.topPullThreshold; 256 | } 257 | 258 | componentDidUpdate(prevProps: Readonly, prevState: Readonly) { 259 | if (!prevProps.refreshing && this.props.refreshing) { 260 | // 从 未加载 变化到 加载中 261 | const holdHeight = this.props.refreshingHoldHeight || this.props.headerHeight; 262 | Animated.timing(this.state.containerTop, { 263 | toValue: holdHeight, 264 | duration: 150, 265 | useNativeDriver: true, 266 | }).start(); 267 | } else if (prevProps.refreshing && !this.props.refreshing) { 268 | // 从 加载中 变化到 未加载 269 | Animated.timing(this.state.containerTop, { 270 | toValue: 0, 271 | duration: 250, 272 | useNativeDriver: true, 273 | }).start(); 274 | } 275 | } 276 | 277 | componentWillUnmount() { 278 | this.state.containerTop.removeAllListeners(); 279 | } 280 | 281 | renderHeader() { 282 | const style = { 283 | position: 'absolute', 284 | left: 0, 285 | width: '100%', 286 | top: -this.props.headerHeight, 287 | transform: [{ translateY: this.state.containerTop }], 288 | }; 289 | const percent = Animated.divide(this.state.containerTop, this.props.refreshTriggerHeight || this.props.headerHeight); 290 | const Header = this.props.HeaderComponent; 291 | return ( 292 | 293 |
{ this.headerRef = c; }} 295 | percentAnimatedValue={percent} 296 | pullDistance={this.containerTranslateY} 297 | percent={this.containerTranslateY / this.props.headerHeight} 298 | refreshing={this.props.refreshing} 299 | /> 300 | 301 | ); 302 | } 303 | 304 | render() { 305 | const child = React.cloneElement(this.props.children, { 306 | onScroll: this.innerScrollCallback, 307 | bounces: false, 308 | alwaysBounceVertical: false, 309 | scrollEnabled: this.state.scrollEnabled, 310 | ref: this.updateInnerScrollRef, 311 | }); 312 | return ( 313 | 317 | 318 | {child} 319 | 320 | {this.renderHeader()} 321 | 322 | ); 323 | } 324 | } 325 | -------------------------------------------------------------------------------- /examples/Demo/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - boost-for-react-native (1.63.0) 3 | - DoubleConversion (1.1.6) 4 | - FBLazyVector (0.61.2) 5 | - FBReactNativeSpec (0.61.2): 6 | - Folly (= 2018.10.22.00) 7 | - RCTRequired (= 0.61.2) 8 | - RCTTypeSafety (= 0.61.2) 9 | - React-Core (= 0.61.2) 10 | - React-jsi (= 0.61.2) 11 | - ReactCommon/turbomodule/core (= 0.61.2) 12 | - Folly (2018.10.22.00): 13 | - boost-for-react-native 14 | - DoubleConversion 15 | - Folly/Default (= 2018.10.22.00) 16 | - glog 17 | - Folly/Default (2018.10.22.00): 18 | - boost-for-react-native 19 | - DoubleConversion 20 | - glog 21 | - glog (0.3.5) 22 | - RCTRequired (0.61.2) 23 | - RCTTypeSafety (0.61.2): 24 | - FBLazyVector (= 0.61.2) 25 | - Folly (= 2018.10.22.00) 26 | - RCTRequired (= 0.61.2) 27 | - React-Core (= 0.61.2) 28 | - React (0.61.2): 29 | - React-Core (= 0.61.2) 30 | - React-Core/DevSupport (= 0.61.2) 31 | - React-Core/RCTWebSocket (= 0.61.2) 32 | - React-RCTActionSheet (= 0.61.2) 33 | - React-RCTAnimation (= 0.61.2) 34 | - React-RCTBlob (= 0.61.2) 35 | - React-RCTImage (= 0.61.2) 36 | - React-RCTLinking (= 0.61.2) 37 | - React-RCTNetwork (= 0.61.2) 38 | - React-RCTSettings (= 0.61.2) 39 | - React-RCTText (= 0.61.2) 40 | - React-RCTVibration (= 0.61.2) 41 | - React-Core (0.61.2): 42 | - Folly (= 2018.10.22.00) 43 | - glog 44 | - React-Core/Default (= 0.61.2) 45 | - React-cxxreact (= 0.61.2) 46 | - React-jsi (= 0.61.2) 47 | - React-jsiexecutor (= 0.61.2) 48 | - Yoga 49 | - React-Core/CoreModulesHeaders (0.61.2): 50 | - Folly (= 2018.10.22.00) 51 | - glog 52 | - React-Core/Default 53 | - React-cxxreact (= 0.61.2) 54 | - React-jsi (= 0.61.2) 55 | - React-jsiexecutor (= 0.61.2) 56 | - Yoga 57 | - React-Core/Default (0.61.2): 58 | - Folly (= 2018.10.22.00) 59 | - glog 60 | - React-cxxreact (= 0.61.2) 61 | - React-jsi (= 0.61.2) 62 | - React-jsiexecutor (= 0.61.2) 63 | - Yoga 64 | - React-Core/DevSupport (0.61.2): 65 | - Folly (= 2018.10.22.00) 66 | - glog 67 | - React-Core/Default (= 0.61.2) 68 | - React-Core/RCTWebSocket (= 0.61.2) 69 | - React-cxxreact (= 0.61.2) 70 | - React-jsi (= 0.61.2) 71 | - React-jsiexecutor (= 0.61.2) 72 | - React-jsinspector (= 0.61.2) 73 | - Yoga 74 | - React-Core/RCTActionSheetHeaders (0.61.2): 75 | - Folly (= 2018.10.22.00) 76 | - glog 77 | - React-Core/Default 78 | - React-cxxreact (= 0.61.2) 79 | - React-jsi (= 0.61.2) 80 | - React-jsiexecutor (= 0.61.2) 81 | - Yoga 82 | - React-Core/RCTAnimationHeaders (0.61.2): 83 | - Folly (= 2018.10.22.00) 84 | - glog 85 | - React-Core/Default 86 | - React-cxxreact (= 0.61.2) 87 | - React-jsi (= 0.61.2) 88 | - React-jsiexecutor (= 0.61.2) 89 | - Yoga 90 | - React-Core/RCTBlobHeaders (0.61.2): 91 | - Folly (= 2018.10.22.00) 92 | - glog 93 | - React-Core/Default 94 | - React-cxxreact (= 0.61.2) 95 | - React-jsi (= 0.61.2) 96 | - React-jsiexecutor (= 0.61.2) 97 | - Yoga 98 | - React-Core/RCTImageHeaders (0.61.2): 99 | - Folly (= 2018.10.22.00) 100 | - glog 101 | - React-Core/Default 102 | - React-cxxreact (= 0.61.2) 103 | - React-jsi (= 0.61.2) 104 | - React-jsiexecutor (= 0.61.2) 105 | - Yoga 106 | - React-Core/RCTLinkingHeaders (0.61.2): 107 | - Folly (= 2018.10.22.00) 108 | - glog 109 | - React-Core/Default 110 | - React-cxxreact (= 0.61.2) 111 | - React-jsi (= 0.61.2) 112 | - React-jsiexecutor (= 0.61.2) 113 | - Yoga 114 | - React-Core/RCTNetworkHeaders (0.61.2): 115 | - Folly (= 2018.10.22.00) 116 | - glog 117 | - React-Core/Default 118 | - React-cxxreact (= 0.61.2) 119 | - React-jsi (= 0.61.2) 120 | - React-jsiexecutor (= 0.61.2) 121 | - Yoga 122 | - React-Core/RCTSettingsHeaders (0.61.2): 123 | - Folly (= 2018.10.22.00) 124 | - glog 125 | - React-Core/Default 126 | - React-cxxreact (= 0.61.2) 127 | - React-jsi (= 0.61.2) 128 | - React-jsiexecutor (= 0.61.2) 129 | - Yoga 130 | - React-Core/RCTTextHeaders (0.61.2): 131 | - Folly (= 2018.10.22.00) 132 | - glog 133 | - React-Core/Default 134 | - React-cxxreact (= 0.61.2) 135 | - React-jsi (= 0.61.2) 136 | - React-jsiexecutor (= 0.61.2) 137 | - Yoga 138 | - React-Core/RCTVibrationHeaders (0.61.2): 139 | - Folly (= 2018.10.22.00) 140 | - glog 141 | - React-Core/Default 142 | - React-cxxreact (= 0.61.2) 143 | - React-jsi (= 0.61.2) 144 | - React-jsiexecutor (= 0.61.2) 145 | - Yoga 146 | - React-Core/RCTWebSocket (0.61.2): 147 | - Folly (= 2018.10.22.00) 148 | - glog 149 | - React-Core/Default (= 0.61.2) 150 | - React-cxxreact (= 0.61.2) 151 | - React-jsi (= 0.61.2) 152 | - React-jsiexecutor (= 0.61.2) 153 | - Yoga 154 | - React-CoreModules (0.61.2): 155 | - FBReactNativeSpec (= 0.61.2) 156 | - Folly (= 2018.10.22.00) 157 | - RCTTypeSafety (= 0.61.2) 158 | - React-Core/CoreModulesHeaders (= 0.61.2) 159 | - React-RCTImage (= 0.61.2) 160 | - ReactCommon/turbomodule/core (= 0.61.2) 161 | - React-cxxreact (0.61.2): 162 | - boost-for-react-native (= 1.63.0) 163 | - DoubleConversion 164 | - Folly (= 2018.10.22.00) 165 | - glog 166 | - React-jsinspector (= 0.61.2) 167 | - React-jsi (0.61.2): 168 | - boost-for-react-native (= 1.63.0) 169 | - DoubleConversion 170 | - Folly (= 2018.10.22.00) 171 | - glog 172 | - React-jsi/Default (= 0.61.2) 173 | - React-jsi/Default (0.61.2): 174 | - boost-for-react-native (= 1.63.0) 175 | - DoubleConversion 176 | - Folly (= 2018.10.22.00) 177 | - glog 178 | - React-jsiexecutor (0.61.2): 179 | - DoubleConversion 180 | - Folly (= 2018.10.22.00) 181 | - glog 182 | - React-cxxreact (= 0.61.2) 183 | - React-jsi (= 0.61.2) 184 | - React-jsinspector (0.61.2) 185 | - React-RCTActionSheet (0.61.2): 186 | - React-Core/RCTActionSheetHeaders (= 0.61.2) 187 | - React-RCTAnimation (0.61.2): 188 | - React-Core/RCTAnimationHeaders (= 0.61.2) 189 | - React-RCTBlob (0.61.2): 190 | - React-Core/RCTBlobHeaders (= 0.61.2) 191 | - React-Core/RCTWebSocket (= 0.61.2) 192 | - React-jsi (= 0.61.2) 193 | - React-RCTNetwork (= 0.61.2) 194 | - React-RCTImage (0.61.2): 195 | - React-Core/RCTImageHeaders (= 0.61.2) 196 | - React-RCTNetwork (= 0.61.2) 197 | - React-RCTLinking (0.61.2): 198 | - React-Core/RCTLinkingHeaders (= 0.61.2) 199 | - React-RCTNetwork (0.61.2): 200 | - React-Core/RCTNetworkHeaders (= 0.61.2) 201 | - React-RCTSettings (0.61.2): 202 | - React-Core/RCTSettingsHeaders (= 0.61.2) 203 | - React-RCTText (0.61.2): 204 | - React-Core/RCTTextHeaders (= 0.61.2) 205 | - React-RCTVibration (0.61.2): 206 | - React-Core/RCTVibrationHeaders (= 0.61.2) 207 | - ReactCommon/jscallinvoker (0.61.2): 208 | - DoubleConversion 209 | - Folly (= 2018.10.22.00) 210 | - glog 211 | - React-cxxreact (= 0.61.2) 212 | - ReactCommon/turbomodule/core (0.61.2): 213 | - DoubleConversion 214 | - Folly (= 2018.10.22.00) 215 | - glog 216 | - React-Core (= 0.61.2) 217 | - React-cxxreact (= 0.61.2) 218 | - React-jsi (= 0.61.2) 219 | - ReactCommon/jscallinvoker (= 0.61.2) 220 | - Yoga (1.14.0) 221 | 222 | DEPENDENCIES: 223 | - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) 224 | - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) 225 | - FBReactNativeSpec (from `../node_modules/react-native/Libraries/FBReactNativeSpec`) 226 | - Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`) 227 | - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) 228 | - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) 229 | - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) 230 | - React (from `../node_modules/react-native/`) 231 | - React-Core (from `../node_modules/react-native/`) 232 | - React-Core/DevSupport (from `../node_modules/react-native/`) 233 | - React-Core/RCTWebSocket (from `../node_modules/react-native/`) 234 | - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) 235 | - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) 236 | - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) 237 | - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) 238 | - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) 239 | - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) 240 | - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) 241 | - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) 242 | - React-RCTImage (from `../node_modules/react-native/Libraries/Image`) 243 | - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`) 244 | - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`) 245 | - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) 246 | - React-RCTText (from `../node_modules/react-native/Libraries/Text`) 247 | - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) 248 | - ReactCommon/jscallinvoker (from `../node_modules/react-native/ReactCommon`) 249 | - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) 250 | - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) 251 | 252 | SPEC REPOS: 253 | https://github.com/cocoapods/specs.git: 254 | - boost-for-react-native 255 | 256 | EXTERNAL SOURCES: 257 | DoubleConversion: 258 | :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" 259 | FBLazyVector: 260 | :path: "../node_modules/react-native/Libraries/FBLazyVector" 261 | FBReactNativeSpec: 262 | :path: "../node_modules/react-native/Libraries/FBReactNativeSpec" 263 | Folly: 264 | :podspec: "../node_modules/react-native/third-party-podspecs/Folly.podspec" 265 | glog: 266 | :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" 267 | RCTRequired: 268 | :path: "../node_modules/react-native/Libraries/RCTRequired" 269 | RCTTypeSafety: 270 | :path: "../node_modules/react-native/Libraries/TypeSafety" 271 | React: 272 | :path: "../node_modules/react-native/" 273 | React-Core: 274 | :path: "../node_modules/react-native/" 275 | React-CoreModules: 276 | :path: "../node_modules/react-native/React/CoreModules" 277 | React-cxxreact: 278 | :path: "../node_modules/react-native/ReactCommon/cxxreact" 279 | React-jsi: 280 | :path: "../node_modules/react-native/ReactCommon/jsi" 281 | React-jsiexecutor: 282 | :path: "../node_modules/react-native/ReactCommon/jsiexecutor" 283 | React-jsinspector: 284 | :path: "../node_modules/react-native/ReactCommon/jsinspector" 285 | React-RCTActionSheet: 286 | :path: "../node_modules/react-native/Libraries/ActionSheetIOS" 287 | React-RCTAnimation: 288 | :path: "../node_modules/react-native/Libraries/NativeAnimation" 289 | React-RCTBlob: 290 | :path: "../node_modules/react-native/Libraries/Blob" 291 | React-RCTImage: 292 | :path: "../node_modules/react-native/Libraries/Image" 293 | React-RCTLinking: 294 | :path: "../node_modules/react-native/Libraries/LinkingIOS" 295 | React-RCTNetwork: 296 | :path: "../node_modules/react-native/Libraries/Network" 297 | React-RCTSettings: 298 | :path: "../node_modules/react-native/Libraries/Settings" 299 | React-RCTText: 300 | :path: "../node_modules/react-native/Libraries/Text" 301 | React-RCTVibration: 302 | :path: "../node_modules/react-native/Libraries/Vibration" 303 | ReactCommon: 304 | :path: "../node_modules/react-native/ReactCommon" 305 | Yoga: 306 | :path: "../node_modules/react-native/ReactCommon/yoga" 307 | 308 | SPEC CHECKSUMS: 309 | boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c 310 | DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2 311 | FBLazyVector: cb37b5590a27600f0a889222d7c1f019625f4168 312 | FBReactNativeSpec: 6fda0eee5b059ee8ea0f845f4060620ff96b5b55 313 | Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51 314 | glog: 1f3da668190260b06b429bb211bfbee5cd790c28 315 | RCTRequired: 81db8debffc2eb932841fa02dcf5a2e911af74c1 316 | RCTTypeSafety: 39a7d8643abe2460aef0adeb9acbe9401b579fff 317 | React: 89f2294058332cf7c4feee644e17d5024da1f531 318 | React-Core: c55956aa434fae94816b665f99d51d50f48d5993 319 | React-CoreModules: c70b9db4f48e31474bb022716fff41983b335ce2 320 | React-cxxreact: 1dbe583c02d15d269f13451d203e645bb233fc96 321 | React-jsi: f9126dd5818fbd8fbf869be9bbc1c0543973e1a1 322 | React-jsiexecutor: 752f034d0f007d1141a1c52ba9ef3fd9668fbfa7 323 | React-jsinspector: 044105eea064aec81adc5e4d777a8f6589e7d094 324 | React-RCTActionSheet: 49433f6e3659ba5d3ee650e44b9c18743ef9a7fc 325 | React-RCTAnimation: 12f86a4e3542032329366b03bca2cc254a7c64a9 326 | React-RCTBlob: ba90a4144ad478a022b79a4e8a1f150548d39425 327 | React-RCTImage: f652d97e49f4b0f26c7df336e723a0d259179967 328 | React-RCTLinking: e738422857085a1c40c57505a25920160d365783 329 | React-RCTNetwork: d0d635ad07deed0c05a1b1499d1ab4ce5c41ac97 330 | React-RCTSettings: ae6f8b64ee5c5e4fc629f5109042e122fd0fd14b 331 | React-RCTText: 3f24042210886ee8c02613758013010be04b291e 332 | React-RCTVibration: d55e1365be416980217914fe009e9d55dec02e03 333 | ReactCommon: eb96b70a2a5bed775e919151fd77699fed52944c 334 | Yoga: 6af72bedeaea291a3a3717772d6d41836f23a1b9 335 | 336 | PODFILE CHECKSUM: 21f9415cb3bb9c73865b7eac940cf31524c7fd73 337 | 338 | COCOAPODS: 1.5.3 339 | -------------------------------------------------------------------------------- /examples/Demo/ios/Demo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 00E356F31AD99517003FC87E /* DemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* DemoTests.m */; }; 11 | 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; 12 | 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; }; 13 | 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 14 | 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 15 | 2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; 16 | 2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 17 | 2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 18 | 2DCD954D1E0B4F2C00145EB5 /* DemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* DemoTests.m */; }; 19 | 7B7A0FB8694ACD28982BB767 /* libPods-Demo-tvOSTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 134EB46CB38BF570AF8BF23E /* libPods-Demo-tvOSTests.a */; }; 20 | 8568740EAEB04CC6B2CADB62 /* libPods-Demo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7210A60C815B72D73705D84F /* libPods-Demo.a */; }; 21 | F0F560A223C6A365228697CE /* libPods-Demo-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F9D72E20DD1781D341088877 /* libPods-Demo-tvOS.a */; }; 22 | FB682A29E8B3D7C18EA245A8 /* libPods-DemoTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A327033DD811C683D3629D23 /* libPods-DemoTests.a */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXContainerItemProxy section */ 26 | 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = { 27 | isa = PBXContainerItemProxy; 28 | containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; 29 | proxyType = 1; 30 | remoteGlobalIDString = 13B07F861A680F5B00A75B9A; 31 | remoteInfo = Demo; 32 | }; 33 | 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */ = { 34 | isa = PBXContainerItemProxy; 35 | containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; 36 | proxyType = 1; 37 | remoteGlobalIDString = 2D02E47A1E0B4A5D006451C7; 38 | remoteInfo = "Demo-tvOS"; 39 | }; 40 | /* End PBXContainerItemProxy section */ 41 | 42 | /* Begin PBXFileReference section */ 43 | 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; }; 44 | 00E356EE1AD99517003FC87E /* DemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 45 | 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 46 | 00E356F21AD99517003FC87E /* DemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DemoTests.m; sourceTree = ""; }; 47 | 134EB46CB38BF570AF8BF23E /* libPods-Demo-tvOSTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Demo-tvOSTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 48 | 13B07F961A680F5B00A75B9A /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = Demo/AppDelegate.h; sourceTree = ""; }; 50 | 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = Demo/AppDelegate.m; sourceTree = ""; }; 51 | 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 52 | 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Demo/Images.xcassets; sourceTree = ""; }; 53 | 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Demo/Info.plist; sourceTree = ""; }; 54 | 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Demo/main.m; sourceTree = ""; }; 55 | 244CDD526690313DCF0B32E3 /* Pods-Demo-tvOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Demo-tvOSTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Demo-tvOSTests/Pods-Demo-tvOSTests.debug.xcconfig"; sourceTree = ""; }; 56 | 2D02E47B1E0B4A5D006451C7 /* Demo-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Demo-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | 2D02E4901E0B4A5D006451C7 /* Demo-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Demo-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | 39DB6D0880DAF58ED4495B41 /* Pods-DemoTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DemoTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-DemoTests/Pods-DemoTests.release.xcconfig"; sourceTree = ""; }; 59 | 3E15239FDB3E4FE0F7544029 /* Pods-Demo-tvOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Demo-tvOSTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Demo-tvOSTests/Pods-Demo-tvOSTests.release.xcconfig"; sourceTree = ""; }; 60 | 590742726986E26385390A8D /* Pods-Demo-tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Demo-tvOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Demo-tvOS/Pods-Demo-tvOS.release.xcconfig"; sourceTree = ""; }; 61 | 5E34BC09AA37B2818989F8CB /* Pods-DemoTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DemoTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-DemoTests/Pods-DemoTests.debug.xcconfig"; sourceTree = ""; }; 62 | 7210A60C815B72D73705D84F /* libPods-Demo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Demo.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 63 | 9BED9C2BBC380B9A3CFF32BC /* Pods-Demo-tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Demo-tvOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Demo-tvOS/Pods-Demo-tvOS.debug.xcconfig"; sourceTree = ""; }; 64 | A20F0DE58415E444E526B526 /* Pods-Demo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Demo.release.xcconfig"; path = "Pods/Target Support Files/Pods-Demo/Pods-Demo.release.xcconfig"; sourceTree = ""; }; 65 | A327033DD811C683D3629D23 /* libPods-DemoTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-DemoTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 66 | DA320D1247B8DE0D98ADBF93 /* Pods-Demo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Demo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Demo/Pods-Demo.debug.xcconfig"; sourceTree = ""; }; 67 | ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; 68 | ED2971642150620600B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/JavaScriptCore.framework; sourceTree = DEVELOPER_DIR; }; 69 | F9D72E20DD1781D341088877 /* libPods-Demo-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Demo-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 70 | /* End PBXFileReference section */ 71 | 72 | /* Begin PBXFrameworksBuildPhase section */ 73 | 00E356EB1AD99517003FC87E /* Frameworks */ = { 74 | isa = PBXFrameworksBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | FB682A29E8B3D7C18EA245A8 /* libPods-DemoTests.a in Frameworks */, 78 | ); 79 | runOnlyForDeploymentPostprocessing = 0; 80 | }; 81 | 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { 82 | isa = PBXFrameworksBuildPhase; 83 | buildActionMask = 2147483647; 84 | files = ( 85 | 8568740EAEB04CC6B2CADB62 /* libPods-Demo.a in Frameworks */, 86 | ); 87 | runOnlyForDeploymentPostprocessing = 0; 88 | }; 89 | 2D02E4781E0B4A5D006451C7 /* Frameworks */ = { 90 | isa = PBXFrameworksBuildPhase; 91 | buildActionMask = 2147483647; 92 | files = ( 93 | F0F560A223C6A365228697CE /* libPods-Demo-tvOS.a in Frameworks */, 94 | ); 95 | runOnlyForDeploymentPostprocessing = 0; 96 | }; 97 | 2D02E48D1E0B4A5D006451C7 /* Frameworks */ = { 98 | isa = PBXFrameworksBuildPhase; 99 | buildActionMask = 2147483647; 100 | files = ( 101 | 7B7A0FB8694ACD28982BB767 /* libPods-Demo-tvOSTests.a in Frameworks */, 102 | ); 103 | runOnlyForDeploymentPostprocessing = 0; 104 | }; 105 | /* End PBXFrameworksBuildPhase section */ 106 | 107 | /* Begin PBXGroup section */ 108 | 00E356EF1AD99517003FC87E /* DemoTests */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 00E356F21AD99517003FC87E /* DemoTests.m */, 112 | 00E356F01AD99517003FC87E /* Supporting Files */, 113 | ); 114 | path = DemoTests; 115 | sourceTree = ""; 116 | }; 117 | 00E356F01AD99517003FC87E /* Supporting Files */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | 00E356F11AD99517003FC87E /* Info.plist */, 121 | ); 122 | name = "Supporting Files"; 123 | sourceTree = ""; 124 | }; 125 | 13B07FAE1A68108700A75B9A /* Demo */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | 008F07F21AC5B25A0029DE68 /* main.jsbundle */, 129 | 13B07FAF1A68108700A75B9A /* AppDelegate.h */, 130 | 13B07FB01A68108700A75B9A /* AppDelegate.m */, 131 | 13B07FB51A68108700A75B9A /* Images.xcassets */, 132 | 13B07FB61A68108700A75B9A /* Info.plist */, 133 | 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, 134 | 13B07FB71A68108700A75B9A /* main.m */, 135 | ); 136 | name = Demo; 137 | sourceTree = ""; 138 | }; 139 | 2D16E6871FA4F8E400B85C8A /* Frameworks */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | ED297162215061F000B7C4FE /* JavaScriptCore.framework */, 143 | ED2971642150620600B7C4FE /* JavaScriptCore.framework */, 144 | 7210A60C815B72D73705D84F /* libPods-Demo.a */, 145 | F9D72E20DD1781D341088877 /* libPods-Demo-tvOS.a */, 146 | 134EB46CB38BF570AF8BF23E /* libPods-Demo-tvOSTests.a */, 147 | A327033DD811C683D3629D23 /* libPods-DemoTests.a */, 148 | ); 149 | name = Frameworks; 150 | sourceTree = ""; 151 | }; 152 | 3AD86C8434E0E436E5889C56 /* Pods */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | DA320D1247B8DE0D98ADBF93 /* Pods-Demo.debug.xcconfig */, 156 | A20F0DE58415E444E526B526 /* Pods-Demo.release.xcconfig */, 157 | 9BED9C2BBC380B9A3CFF32BC /* Pods-Demo-tvOS.debug.xcconfig */, 158 | 590742726986E26385390A8D /* Pods-Demo-tvOS.release.xcconfig */, 159 | 244CDD526690313DCF0B32E3 /* Pods-Demo-tvOSTests.debug.xcconfig */, 160 | 3E15239FDB3E4FE0F7544029 /* Pods-Demo-tvOSTests.release.xcconfig */, 161 | 5E34BC09AA37B2818989F8CB /* Pods-DemoTests.debug.xcconfig */, 162 | 39DB6D0880DAF58ED4495B41 /* Pods-DemoTests.release.xcconfig */, 163 | ); 164 | name = Pods; 165 | sourceTree = ""; 166 | }; 167 | 832341AE1AAA6A7D00B99B32 /* Libraries */ = { 168 | isa = PBXGroup; 169 | children = ( 170 | ); 171 | name = Libraries; 172 | sourceTree = ""; 173 | }; 174 | 83CBB9F61A601CBA00E9B192 = { 175 | isa = PBXGroup; 176 | children = ( 177 | 13B07FAE1A68108700A75B9A /* Demo */, 178 | 832341AE1AAA6A7D00B99B32 /* Libraries */, 179 | 00E356EF1AD99517003FC87E /* DemoTests */, 180 | 83CBBA001A601CBA00E9B192 /* Products */, 181 | 2D16E6871FA4F8E400B85C8A /* Frameworks */, 182 | 3AD86C8434E0E436E5889C56 /* Pods */, 183 | ); 184 | indentWidth = 2; 185 | sourceTree = ""; 186 | tabWidth = 2; 187 | usesTabs = 0; 188 | }; 189 | 83CBBA001A601CBA00E9B192 /* Products */ = { 190 | isa = PBXGroup; 191 | children = ( 192 | 13B07F961A680F5B00A75B9A /* Demo.app */, 193 | 00E356EE1AD99517003FC87E /* DemoTests.xctest */, 194 | 2D02E47B1E0B4A5D006451C7 /* Demo-tvOS.app */, 195 | 2D02E4901E0B4A5D006451C7 /* Demo-tvOSTests.xctest */, 196 | ); 197 | name = Products; 198 | sourceTree = ""; 199 | }; 200 | /* End PBXGroup section */ 201 | 202 | /* Begin PBXNativeTarget section */ 203 | 00E356ED1AD99517003FC87E /* DemoTests */ = { 204 | isa = PBXNativeTarget; 205 | buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "DemoTests" */; 206 | buildPhases = ( 207 | F3B8308450FCB45A43D46E12 /* [CP] Check Pods Manifest.lock */, 208 | 00E356EA1AD99517003FC87E /* Sources */, 209 | 00E356EB1AD99517003FC87E /* Frameworks */, 210 | 00E356EC1AD99517003FC87E /* Resources */, 211 | ); 212 | buildRules = ( 213 | ); 214 | dependencies = ( 215 | 00E356F51AD99517003FC87E /* PBXTargetDependency */, 216 | ); 217 | name = DemoTests; 218 | productName = DemoTests; 219 | productReference = 00E356EE1AD99517003FC87E /* DemoTests.xctest */; 220 | productType = "com.apple.product-type.bundle.unit-test"; 221 | }; 222 | 13B07F861A680F5B00A75B9A /* Demo */ = { 223 | isa = PBXNativeTarget; 224 | buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Demo" */; 225 | buildPhases = ( 226 | DA552A6B84B7A27EF1E126D0 /* [CP] Check Pods Manifest.lock */, 227 | FD10A7F022414F080027D42C /* Start Packager */, 228 | 13B07F871A680F5B00A75B9A /* Sources */, 229 | 13B07F8C1A680F5B00A75B9A /* Frameworks */, 230 | 13B07F8E1A680F5B00A75B9A /* Resources */, 231 | 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, 232 | ); 233 | buildRules = ( 234 | ); 235 | dependencies = ( 236 | ); 237 | name = Demo; 238 | productName = Demo; 239 | productReference = 13B07F961A680F5B00A75B9A /* Demo.app */; 240 | productType = "com.apple.product-type.application"; 241 | }; 242 | 2D02E47A1E0B4A5D006451C7 /* Demo-tvOS */ = { 243 | isa = PBXNativeTarget; 244 | buildConfigurationList = 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "Demo-tvOS" */; 245 | buildPhases = ( 246 | B88E718B10D56A3CF7E01103 /* [CP] Check Pods Manifest.lock */, 247 | FD10A7F122414F3F0027D42C /* Start Packager */, 248 | 2D02E4771E0B4A5D006451C7 /* Sources */, 249 | 2D02E4781E0B4A5D006451C7 /* Frameworks */, 250 | 2D02E4791E0B4A5D006451C7 /* Resources */, 251 | 2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */, 252 | ); 253 | buildRules = ( 254 | ); 255 | dependencies = ( 256 | ); 257 | name = "Demo-tvOS"; 258 | productName = "Demo-tvOS"; 259 | productReference = 2D02E47B1E0B4A5D006451C7 /* Demo-tvOS.app */; 260 | productType = "com.apple.product-type.application"; 261 | }; 262 | 2D02E48F1E0B4A5D006451C7 /* Demo-tvOSTests */ = { 263 | isa = PBXNativeTarget; 264 | buildConfigurationList = 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "Demo-tvOSTests" */; 265 | buildPhases = ( 266 | FA3F2CA8AA256E52A8139A13 /* [CP] Check Pods Manifest.lock */, 267 | 2D02E48C1E0B4A5D006451C7 /* Sources */, 268 | 2D02E48D1E0B4A5D006451C7 /* Frameworks */, 269 | 2D02E48E1E0B4A5D006451C7 /* Resources */, 270 | ); 271 | buildRules = ( 272 | ); 273 | dependencies = ( 274 | 2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */, 275 | ); 276 | name = "Demo-tvOSTests"; 277 | productName = "Demo-tvOSTests"; 278 | productReference = 2D02E4901E0B4A5D006451C7 /* Demo-tvOSTests.xctest */; 279 | productType = "com.apple.product-type.bundle.unit-test"; 280 | }; 281 | /* End PBXNativeTarget section */ 282 | 283 | /* Begin PBXProject section */ 284 | 83CBB9F71A601CBA00E9B192 /* Project object */ = { 285 | isa = PBXProject; 286 | attributes = { 287 | LastUpgradeCheck = 0940; 288 | ORGANIZATIONNAME = Facebook; 289 | TargetAttributes = { 290 | 00E356ED1AD99517003FC87E = { 291 | CreatedOnToolsVersion = 6.2; 292 | TestTargetID = 13B07F861A680F5B00A75B9A; 293 | }; 294 | 2D02E47A1E0B4A5D006451C7 = { 295 | CreatedOnToolsVersion = 8.2.1; 296 | ProvisioningStyle = Automatic; 297 | }; 298 | 2D02E48F1E0B4A5D006451C7 = { 299 | CreatedOnToolsVersion = 8.2.1; 300 | ProvisioningStyle = Automatic; 301 | TestTargetID = 2D02E47A1E0B4A5D006451C7; 302 | }; 303 | }; 304 | }; 305 | buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Demo" */; 306 | compatibilityVersion = "Xcode 3.2"; 307 | developmentRegion = English; 308 | hasScannedForEncodings = 0; 309 | knownRegions = ( 310 | en, 311 | Base, 312 | ); 313 | mainGroup = 83CBB9F61A601CBA00E9B192; 314 | productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; 315 | projectDirPath = ""; 316 | projectRoot = ""; 317 | targets = ( 318 | 13B07F861A680F5B00A75B9A /* Demo */, 319 | 00E356ED1AD99517003FC87E /* DemoTests */, 320 | 2D02E47A1E0B4A5D006451C7 /* Demo-tvOS */, 321 | 2D02E48F1E0B4A5D006451C7 /* Demo-tvOSTests */, 322 | ); 323 | }; 324 | /* End PBXProject section */ 325 | 326 | /* Begin PBXResourcesBuildPhase section */ 327 | 00E356EC1AD99517003FC87E /* Resources */ = { 328 | isa = PBXResourcesBuildPhase; 329 | buildActionMask = 2147483647; 330 | files = ( 331 | ); 332 | runOnlyForDeploymentPostprocessing = 0; 333 | }; 334 | 13B07F8E1A680F5B00A75B9A /* Resources */ = { 335 | isa = PBXResourcesBuildPhase; 336 | buildActionMask = 2147483647; 337 | files = ( 338 | 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, 339 | 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, 340 | ); 341 | runOnlyForDeploymentPostprocessing = 0; 342 | }; 343 | 2D02E4791E0B4A5D006451C7 /* Resources */ = { 344 | isa = PBXResourcesBuildPhase; 345 | buildActionMask = 2147483647; 346 | files = ( 347 | 2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */, 348 | ); 349 | runOnlyForDeploymentPostprocessing = 0; 350 | }; 351 | 2D02E48E1E0B4A5D006451C7 /* Resources */ = { 352 | isa = PBXResourcesBuildPhase; 353 | buildActionMask = 2147483647; 354 | files = ( 355 | ); 356 | runOnlyForDeploymentPostprocessing = 0; 357 | }; 358 | /* End PBXResourcesBuildPhase section */ 359 | 360 | /* Begin PBXShellScriptBuildPhase section */ 361 | 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { 362 | isa = PBXShellScriptBuildPhase; 363 | buildActionMask = 2147483647; 364 | files = ( 365 | ); 366 | inputPaths = ( 367 | ); 368 | name = "Bundle React Native code and images"; 369 | outputPaths = ( 370 | ); 371 | runOnlyForDeploymentPostprocessing = 0; 372 | shellPath = /bin/sh; 373 | shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh"; 374 | }; 375 | 2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */ = { 376 | isa = PBXShellScriptBuildPhase; 377 | buildActionMask = 2147483647; 378 | files = ( 379 | ); 380 | inputPaths = ( 381 | ); 382 | name = "Bundle React Native Code And Images"; 383 | outputPaths = ( 384 | ); 385 | runOnlyForDeploymentPostprocessing = 0; 386 | shellPath = /bin/sh; 387 | shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh"; 388 | }; 389 | B88E718B10D56A3CF7E01103 /* [CP] Check Pods Manifest.lock */ = { 390 | isa = PBXShellScriptBuildPhase; 391 | buildActionMask = 2147483647; 392 | files = ( 393 | ); 394 | inputFileListPaths = ( 395 | ); 396 | inputPaths = ( 397 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 398 | "${PODS_ROOT}/Manifest.lock", 399 | ); 400 | name = "[CP] Check Pods Manifest.lock"; 401 | outputFileListPaths = ( 402 | ); 403 | outputPaths = ( 404 | "$(DERIVED_FILE_DIR)/Pods-Demo-tvOS-checkManifestLockResult.txt", 405 | ); 406 | runOnlyForDeploymentPostprocessing = 0; 407 | shellPath = /bin/sh; 408 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 409 | showEnvVarsInLog = 0; 410 | }; 411 | DA552A6B84B7A27EF1E126D0 /* [CP] Check Pods Manifest.lock */ = { 412 | isa = PBXShellScriptBuildPhase; 413 | buildActionMask = 2147483647; 414 | files = ( 415 | ); 416 | inputFileListPaths = ( 417 | ); 418 | inputPaths = ( 419 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 420 | "${PODS_ROOT}/Manifest.lock", 421 | ); 422 | name = "[CP] Check Pods Manifest.lock"; 423 | outputFileListPaths = ( 424 | ); 425 | outputPaths = ( 426 | "$(DERIVED_FILE_DIR)/Pods-Demo-checkManifestLockResult.txt", 427 | ); 428 | runOnlyForDeploymentPostprocessing = 0; 429 | shellPath = /bin/sh; 430 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 431 | showEnvVarsInLog = 0; 432 | }; 433 | F3B8308450FCB45A43D46E12 /* [CP] Check Pods Manifest.lock */ = { 434 | isa = PBXShellScriptBuildPhase; 435 | buildActionMask = 2147483647; 436 | files = ( 437 | ); 438 | inputFileListPaths = ( 439 | ); 440 | inputPaths = ( 441 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 442 | "${PODS_ROOT}/Manifest.lock", 443 | ); 444 | name = "[CP] Check Pods Manifest.lock"; 445 | outputFileListPaths = ( 446 | ); 447 | outputPaths = ( 448 | "$(DERIVED_FILE_DIR)/Pods-DemoTests-checkManifestLockResult.txt", 449 | ); 450 | runOnlyForDeploymentPostprocessing = 0; 451 | shellPath = /bin/sh; 452 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 453 | showEnvVarsInLog = 0; 454 | }; 455 | FA3F2CA8AA256E52A8139A13 /* [CP] Check Pods Manifest.lock */ = { 456 | isa = PBXShellScriptBuildPhase; 457 | buildActionMask = 2147483647; 458 | files = ( 459 | ); 460 | inputFileListPaths = ( 461 | ); 462 | inputPaths = ( 463 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 464 | "${PODS_ROOT}/Manifest.lock", 465 | ); 466 | name = "[CP] Check Pods Manifest.lock"; 467 | outputFileListPaths = ( 468 | ); 469 | outputPaths = ( 470 | "$(DERIVED_FILE_DIR)/Pods-Demo-tvOSTests-checkManifestLockResult.txt", 471 | ); 472 | runOnlyForDeploymentPostprocessing = 0; 473 | shellPath = /bin/sh; 474 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 475 | showEnvVarsInLog = 0; 476 | }; 477 | FD10A7F022414F080027D42C /* Start Packager */ = { 478 | isa = PBXShellScriptBuildPhase; 479 | buildActionMask = 2147483647; 480 | files = ( 481 | ); 482 | inputFileListPaths = ( 483 | ); 484 | inputPaths = ( 485 | ); 486 | name = "Start Packager"; 487 | outputFileListPaths = ( 488 | ); 489 | outputPaths = ( 490 | ); 491 | runOnlyForDeploymentPostprocessing = 0; 492 | shellPath = /bin/sh; 493 | shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n"; 494 | showEnvVarsInLog = 0; 495 | }; 496 | FD10A7F122414F3F0027D42C /* Start Packager */ = { 497 | isa = PBXShellScriptBuildPhase; 498 | buildActionMask = 2147483647; 499 | files = ( 500 | ); 501 | inputFileListPaths = ( 502 | ); 503 | inputPaths = ( 504 | ); 505 | name = "Start Packager"; 506 | outputFileListPaths = ( 507 | ); 508 | outputPaths = ( 509 | ); 510 | runOnlyForDeploymentPostprocessing = 0; 511 | shellPath = /bin/sh; 512 | shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n"; 513 | showEnvVarsInLog = 0; 514 | }; 515 | /* End PBXShellScriptBuildPhase section */ 516 | 517 | /* Begin PBXSourcesBuildPhase section */ 518 | 00E356EA1AD99517003FC87E /* Sources */ = { 519 | isa = PBXSourcesBuildPhase; 520 | buildActionMask = 2147483647; 521 | files = ( 522 | 00E356F31AD99517003FC87E /* DemoTests.m in Sources */, 523 | ); 524 | runOnlyForDeploymentPostprocessing = 0; 525 | }; 526 | 13B07F871A680F5B00A75B9A /* Sources */ = { 527 | isa = PBXSourcesBuildPhase; 528 | buildActionMask = 2147483647; 529 | files = ( 530 | 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, 531 | 13B07FC11A68108700A75B9A /* main.m in Sources */, 532 | ); 533 | runOnlyForDeploymentPostprocessing = 0; 534 | }; 535 | 2D02E4771E0B4A5D006451C7 /* Sources */ = { 536 | isa = PBXSourcesBuildPhase; 537 | buildActionMask = 2147483647; 538 | files = ( 539 | 2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */, 540 | 2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */, 541 | ); 542 | runOnlyForDeploymentPostprocessing = 0; 543 | }; 544 | 2D02E48C1E0B4A5D006451C7 /* Sources */ = { 545 | isa = PBXSourcesBuildPhase; 546 | buildActionMask = 2147483647; 547 | files = ( 548 | 2DCD954D1E0B4F2C00145EB5 /* DemoTests.m in Sources */, 549 | ); 550 | runOnlyForDeploymentPostprocessing = 0; 551 | }; 552 | /* End PBXSourcesBuildPhase section */ 553 | 554 | /* Begin PBXTargetDependency section */ 555 | 00E356F51AD99517003FC87E /* PBXTargetDependency */ = { 556 | isa = PBXTargetDependency; 557 | target = 13B07F861A680F5B00A75B9A /* Demo */; 558 | targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */; 559 | }; 560 | 2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */ = { 561 | isa = PBXTargetDependency; 562 | target = 2D02E47A1E0B4A5D006451C7 /* Demo-tvOS */; 563 | targetProxy = 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */; 564 | }; 565 | /* End PBXTargetDependency section */ 566 | 567 | /* Begin PBXVariantGroup section */ 568 | 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { 569 | isa = PBXVariantGroup; 570 | children = ( 571 | 13B07FB21A68108700A75B9A /* Base */, 572 | ); 573 | name = LaunchScreen.xib; 574 | path = Demo; 575 | sourceTree = ""; 576 | }; 577 | /* End PBXVariantGroup section */ 578 | 579 | /* Begin XCBuildConfiguration section */ 580 | 00E356F61AD99517003FC87E /* Debug */ = { 581 | isa = XCBuildConfiguration; 582 | baseConfigurationReference = 5E34BC09AA37B2818989F8CB /* Pods-DemoTests.debug.xcconfig */; 583 | buildSettings = { 584 | BUNDLE_LOADER = "$(TEST_HOST)"; 585 | GCC_PREPROCESSOR_DEFINITIONS = ( 586 | "DEBUG=1", 587 | "$(inherited)", 588 | ); 589 | INFOPLIST_FILE = DemoTests/Info.plist; 590 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 591 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 592 | OTHER_LDFLAGS = ( 593 | "-ObjC", 594 | "-lc++", 595 | "$(inherited)", 596 | ); 597 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; 598 | PRODUCT_NAME = "$(TARGET_NAME)"; 599 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Demo.app/Demo"; 600 | }; 601 | name = Debug; 602 | }; 603 | 00E356F71AD99517003FC87E /* Release */ = { 604 | isa = XCBuildConfiguration; 605 | baseConfigurationReference = 39DB6D0880DAF58ED4495B41 /* Pods-DemoTests.release.xcconfig */; 606 | buildSettings = { 607 | BUNDLE_LOADER = "$(TEST_HOST)"; 608 | COPY_PHASE_STRIP = NO; 609 | INFOPLIST_FILE = DemoTests/Info.plist; 610 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 611 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 612 | OTHER_LDFLAGS = ( 613 | "-ObjC", 614 | "-lc++", 615 | "$(inherited)", 616 | ); 617 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; 618 | PRODUCT_NAME = "$(TARGET_NAME)"; 619 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Demo.app/Demo"; 620 | }; 621 | name = Release; 622 | }; 623 | 13B07F941A680F5B00A75B9A /* Debug */ = { 624 | isa = XCBuildConfiguration; 625 | baseConfigurationReference = DA320D1247B8DE0D98ADBF93 /* Pods-Demo.debug.xcconfig */; 626 | buildSettings = { 627 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 628 | CURRENT_PROJECT_VERSION = 1; 629 | DEAD_CODE_STRIPPING = NO; 630 | INFOPLIST_FILE = Demo/Info.plist; 631 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 632 | OTHER_LDFLAGS = ( 633 | "$(inherited)", 634 | "-ObjC", 635 | "-lc++", 636 | ); 637 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; 638 | PRODUCT_NAME = Demo; 639 | VERSIONING_SYSTEM = "apple-generic"; 640 | }; 641 | name = Debug; 642 | }; 643 | 13B07F951A680F5B00A75B9A /* Release */ = { 644 | isa = XCBuildConfiguration; 645 | baseConfigurationReference = A20F0DE58415E444E526B526 /* Pods-Demo.release.xcconfig */; 646 | buildSettings = { 647 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 648 | CURRENT_PROJECT_VERSION = 1; 649 | INFOPLIST_FILE = Demo/Info.plist; 650 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 651 | OTHER_LDFLAGS = ( 652 | "$(inherited)", 653 | "-ObjC", 654 | "-lc++", 655 | ); 656 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; 657 | PRODUCT_NAME = Demo; 658 | VERSIONING_SYSTEM = "apple-generic"; 659 | }; 660 | name = Release; 661 | }; 662 | 2D02E4971E0B4A5E006451C7 /* Debug */ = { 663 | isa = XCBuildConfiguration; 664 | baseConfigurationReference = 9BED9C2BBC380B9A3CFF32BC /* Pods-Demo-tvOS.debug.xcconfig */; 665 | buildSettings = { 666 | ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; 667 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 668 | CLANG_ANALYZER_NONNULL = YES; 669 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 670 | CLANG_WARN_INFINITE_RECURSION = YES; 671 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 672 | DEBUG_INFORMATION_FORMAT = dwarf; 673 | ENABLE_TESTABILITY = YES; 674 | GCC_NO_COMMON_BLOCKS = YES; 675 | INFOPLIST_FILE = "Demo-tvOS/Info.plist"; 676 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 677 | OTHER_LDFLAGS = ( 678 | "$(inherited)", 679 | "-ObjC", 680 | "-lc++", 681 | ); 682 | PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.Demo-tvOS"; 683 | PRODUCT_NAME = "$(TARGET_NAME)"; 684 | SDKROOT = appletvos; 685 | TARGETED_DEVICE_FAMILY = 3; 686 | TVOS_DEPLOYMENT_TARGET = 9.2; 687 | }; 688 | name = Debug; 689 | }; 690 | 2D02E4981E0B4A5E006451C7 /* Release */ = { 691 | isa = XCBuildConfiguration; 692 | baseConfigurationReference = 590742726986E26385390A8D /* Pods-Demo-tvOS.release.xcconfig */; 693 | buildSettings = { 694 | ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; 695 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 696 | CLANG_ANALYZER_NONNULL = YES; 697 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 698 | CLANG_WARN_INFINITE_RECURSION = YES; 699 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 700 | COPY_PHASE_STRIP = NO; 701 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 702 | GCC_NO_COMMON_BLOCKS = YES; 703 | INFOPLIST_FILE = "Demo-tvOS/Info.plist"; 704 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 705 | OTHER_LDFLAGS = ( 706 | "$(inherited)", 707 | "-ObjC", 708 | "-lc++", 709 | ); 710 | PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.Demo-tvOS"; 711 | PRODUCT_NAME = "$(TARGET_NAME)"; 712 | SDKROOT = appletvos; 713 | TARGETED_DEVICE_FAMILY = 3; 714 | TVOS_DEPLOYMENT_TARGET = 9.2; 715 | }; 716 | name = Release; 717 | }; 718 | 2D02E4991E0B4A5E006451C7 /* Debug */ = { 719 | isa = XCBuildConfiguration; 720 | baseConfigurationReference = 244CDD526690313DCF0B32E3 /* Pods-Demo-tvOSTests.debug.xcconfig */; 721 | buildSettings = { 722 | BUNDLE_LOADER = "$(TEST_HOST)"; 723 | CLANG_ANALYZER_NONNULL = YES; 724 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 725 | CLANG_WARN_INFINITE_RECURSION = YES; 726 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 727 | DEBUG_INFORMATION_FORMAT = dwarf; 728 | ENABLE_TESTABILITY = YES; 729 | GCC_NO_COMMON_BLOCKS = YES; 730 | INFOPLIST_FILE = "Demo-tvOSTests/Info.plist"; 731 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 732 | OTHER_LDFLAGS = ( 733 | "$(inherited)", 734 | "-ObjC", 735 | "-lc++", 736 | ); 737 | PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.Demo-tvOSTests"; 738 | PRODUCT_NAME = "$(TARGET_NAME)"; 739 | SDKROOT = appletvos; 740 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Demo-tvOS.app/Demo-tvOS"; 741 | TVOS_DEPLOYMENT_TARGET = 10.1; 742 | }; 743 | name = Debug; 744 | }; 745 | 2D02E49A1E0B4A5E006451C7 /* Release */ = { 746 | isa = XCBuildConfiguration; 747 | baseConfigurationReference = 3E15239FDB3E4FE0F7544029 /* Pods-Demo-tvOSTests.release.xcconfig */; 748 | buildSettings = { 749 | BUNDLE_LOADER = "$(TEST_HOST)"; 750 | CLANG_ANALYZER_NONNULL = YES; 751 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 752 | CLANG_WARN_INFINITE_RECURSION = YES; 753 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 754 | COPY_PHASE_STRIP = NO; 755 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 756 | GCC_NO_COMMON_BLOCKS = YES; 757 | INFOPLIST_FILE = "Demo-tvOSTests/Info.plist"; 758 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 759 | OTHER_LDFLAGS = ( 760 | "$(inherited)", 761 | "-ObjC", 762 | "-lc++", 763 | ); 764 | PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.Demo-tvOSTests"; 765 | PRODUCT_NAME = "$(TARGET_NAME)"; 766 | SDKROOT = appletvos; 767 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Demo-tvOS.app/Demo-tvOS"; 768 | TVOS_DEPLOYMENT_TARGET = 10.1; 769 | }; 770 | name = Release; 771 | }; 772 | 83CBBA201A601CBA00E9B192 /* Debug */ = { 773 | isa = XCBuildConfiguration; 774 | buildSettings = { 775 | ALWAYS_SEARCH_USER_PATHS = NO; 776 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 777 | CLANG_CXX_LIBRARY = "libc++"; 778 | CLANG_ENABLE_MODULES = YES; 779 | CLANG_ENABLE_OBJC_ARC = YES; 780 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 781 | CLANG_WARN_BOOL_CONVERSION = YES; 782 | CLANG_WARN_COMMA = YES; 783 | CLANG_WARN_CONSTANT_CONVERSION = YES; 784 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 785 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 786 | CLANG_WARN_EMPTY_BODY = YES; 787 | CLANG_WARN_ENUM_CONVERSION = YES; 788 | CLANG_WARN_INFINITE_RECURSION = YES; 789 | CLANG_WARN_INT_CONVERSION = YES; 790 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 791 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 792 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 793 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 794 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 795 | CLANG_WARN_STRICT_PROTOTYPES = YES; 796 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 797 | CLANG_WARN_UNREACHABLE_CODE = YES; 798 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 799 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 800 | COPY_PHASE_STRIP = NO; 801 | ENABLE_STRICT_OBJC_MSGSEND = YES; 802 | ENABLE_TESTABILITY = YES; 803 | GCC_C_LANGUAGE_STANDARD = gnu99; 804 | GCC_DYNAMIC_NO_PIC = NO; 805 | GCC_NO_COMMON_BLOCKS = YES; 806 | GCC_OPTIMIZATION_LEVEL = 0; 807 | GCC_PREPROCESSOR_DEFINITIONS = ( 808 | "DEBUG=1", 809 | "$(inherited)", 810 | ); 811 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 812 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 813 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 814 | GCC_WARN_UNDECLARED_SELECTOR = YES; 815 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 816 | GCC_WARN_UNUSED_FUNCTION = YES; 817 | GCC_WARN_UNUSED_VARIABLE = YES; 818 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 819 | MTL_ENABLE_DEBUG_INFO = YES; 820 | ONLY_ACTIVE_ARCH = YES; 821 | SDKROOT = iphoneos; 822 | }; 823 | name = Debug; 824 | }; 825 | 83CBBA211A601CBA00E9B192 /* Release */ = { 826 | isa = XCBuildConfiguration; 827 | buildSettings = { 828 | ALWAYS_SEARCH_USER_PATHS = NO; 829 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 830 | CLANG_CXX_LIBRARY = "libc++"; 831 | CLANG_ENABLE_MODULES = YES; 832 | CLANG_ENABLE_OBJC_ARC = YES; 833 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 834 | CLANG_WARN_BOOL_CONVERSION = YES; 835 | CLANG_WARN_COMMA = YES; 836 | CLANG_WARN_CONSTANT_CONVERSION = YES; 837 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 838 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 839 | CLANG_WARN_EMPTY_BODY = YES; 840 | CLANG_WARN_ENUM_CONVERSION = YES; 841 | CLANG_WARN_INFINITE_RECURSION = YES; 842 | CLANG_WARN_INT_CONVERSION = YES; 843 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 844 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 845 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 846 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 847 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 848 | CLANG_WARN_STRICT_PROTOTYPES = YES; 849 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 850 | CLANG_WARN_UNREACHABLE_CODE = YES; 851 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 852 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 853 | COPY_PHASE_STRIP = YES; 854 | ENABLE_NS_ASSERTIONS = NO; 855 | ENABLE_STRICT_OBJC_MSGSEND = YES; 856 | GCC_C_LANGUAGE_STANDARD = gnu99; 857 | GCC_NO_COMMON_BLOCKS = YES; 858 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 859 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 860 | GCC_WARN_UNDECLARED_SELECTOR = YES; 861 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 862 | GCC_WARN_UNUSED_FUNCTION = YES; 863 | GCC_WARN_UNUSED_VARIABLE = YES; 864 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 865 | MTL_ENABLE_DEBUG_INFO = NO; 866 | SDKROOT = iphoneos; 867 | VALIDATE_PRODUCT = YES; 868 | }; 869 | name = Release; 870 | }; 871 | /* End XCBuildConfiguration section */ 872 | 873 | /* Begin XCConfigurationList section */ 874 | 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "DemoTests" */ = { 875 | isa = XCConfigurationList; 876 | buildConfigurations = ( 877 | 00E356F61AD99517003FC87E /* Debug */, 878 | 00E356F71AD99517003FC87E /* Release */, 879 | ); 880 | defaultConfigurationIsVisible = 0; 881 | defaultConfigurationName = Release; 882 | }; 883 | 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Demo" */ = { 884 | isa = XCConfigurationList; 885 | buildConfigurations = ( 886 | 13B07F941A680F5B00A75B9A /* Debug */, 887 | 13B07F951A680F5B00A75B9A /* Release */, 888 | ); 889 | defaultConfigurationIsVisible = 0; 890 | defaultConfigurationName = Release; 891 | }; 892 | 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "Demo-tvOS" */ = { 893 | isa = XCConfigurationList; 894 | buildConfigurations = ( 895 | 2D02E4971E0B4A5E006451C7 /* Debug */, 896 | 2D02E4981E0B4A5E006451C7 /* Release */, 897 | ); 898 | defaultConfigurationIsVisible = 0; 899 | defaultConfigurationName = Release; 900 | }; 901 | 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "Demo-tvOSTests" */ = { 902 | isa = XCConfigurationList; 903 | buildConfigurations = ( 904 | 2D02E4991E0B4A5E006451C7 /* Debug */, 905 | 2D02E49A1E0B4A5E006451C7 /* Release */, 906 | ); 907 | defaultConfigurationIsVisible = 0; 908 | defaultConfigurationName = Release; 909 | }; 910 | 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Demo" */ = { 911 | isa = XCConfigurationList; 912 | buildConfigurations = ( 913 | 83CBBA201A601CBA00E9B192 /* Debug */, 914 | 83CBBA211A601CBA00E9B192 /* Release */, 915 | ); 916 | defaultConfigurationIsVisible = 0; 917 | defaultConfigurationName = Release; 918 | }; 919 | /* End XCConfigurationList section */ 920 | }; 921 | rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; 922 | } 923 | --------------------------------------------------------------------------------