├── .buckconfig ├── .flowconfig ├── .gitattributes ├── .gitignore ├── .npmignore ├── .travis.yml ├── .watchmanconfig ├── App.js ├── Examples ├── Home.js ├── LargeListExamples │ ├── BigMediaExample.js │ ├── ChatExample.js │ ├── ContactExample.js │ ├── DataSource.js │ ├── FlatListExample.js │ ├── HeightEqualExample.js │ ├── HeightUnequalExample.js │ ├── IntensiveSectionExample.js │ ├── LargeListExamples.js │ ├── MenuListExample.js │ ├── MessageExample.js │ ├── RefreshAndLoadingExample.js │ ├── icons │ │ ├── ScaleHeader.jpg │ │ ├── icon10@2x.png │ │ ├── icon10@3x.png │ │ ├── icon1@2x.png │ │ ├── icon1@3x.png │ │ ├── icon2@2x.png │ │ ├── icon2@3x.png │ │ ├── icon3@2x.png │ │ ├── icon3@3x.png │ │ ├── icon4@2x.png │ │ ├── icon4@3x.png │ │ ├── icon5.png │ │ ├── icon6@2x.png │ │ ├── icon6@3x.png │ │ ├── icon7@2x.png │ │ ├── icon7@3x.png │ │ ├── icon8@2x.png │ │ ├── icon8@3x.png │ │ ├── icon9@2x.png │ │ ├── icon9@3x.png │ │ ├── index.js │ │ └── loading.gif │ └── index.js ├── StickyFormExamples │ ├── StickyFormExample.js │ └── index.js ├── WaterfallListExamples │ ├── PictureExample.js │ ├── WaterfallListExample.js │ ├── WaterfallListExamples.js │ ├── data.json │ └── index.js └── index.js ├── LICENSE ├── README.md ├── __tests__ └── App-test.js ├── android ├── LargeListDemo.iml ├── app │ ├── BUCK │ ├── _BUCK │ ├── app.iml │ ├── build.gradle │ ├── build_defs.bzl │ ├── debug.keystore │ ├── proguard-rules.pro │ └── src │ │ ├── debug │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── largelistexample │ │ │ └── ReactNativeFlipper.java │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── largelistexample │ │ │ ├── MainActivity.java │ │ │ └── MainApplication.java │ │ └── res │ │ ├── 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 │ │ └── values │ │ ├── strings.xml │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── keystores │ ├── BUCK │ └── debug.keystore.properties └── settings.gradle ├── app.json ├── babel.config.js ├── docs ├── .nojekyll ├── _coverpage.md ├── _navbar.md ├── en │ ├── README.md │ ├── V3 │ │ ├── BasicUsage.md │ │ ├── BigMedia.md │ │ ├── CustomLoading.md │ │ ├── CustomRefresh.md │ │ ├── GettingStart.md │ │ ├── KnownIssues.md │ │ ├── Loading.md │ │ ├── Overview.md │ │ ├── Refresh.md │ │ ├── Scroll.md │ │ ├── StickyForm │ │ │ ├── Overview.md │ │ │ └── Usage.md │ │ ├── SupportedProps.md │ │ └── WaterfallList │ │ │ ├── Overview.md │ │ │ └── Usage.md │ └── _sidebar.md ├── index.html ├── res │ ├── BothDirections.gif │ ├── CustomizeLoading.gif │ ├── CustomizeRefreshing.gif │ ├── LoadingAndroid.gif │ ├── LoadingBottoming.gif │ ├── LoadingStickyContent.gif │ ├── LoadingStickyScrollView.gif │ ├── LottieLoading.gif │ ├── LottieRefreshing.gif │ ├── PictureExample.gif │ ├── RefreshAndLoading.gif │ ├── RefreshAndroid.gif │ ├── RefreshingStickyContent.gif │ ├── RefreshingStickyScrollView.gif │ ├── RefreshingTopping.gif │ ├── StickyFormExample.gif │ ├── StickyHeader.gif │ ├── StickySection.gif │ ├── Update.gif │ ├── WaterfallExample.gif │ ├── WaterfallExample.png │ ├── bounces.gif │ ├── directionalLockEnabled.gif │ ├── inverted.gif │ ├── numColumns.gif │ ├── preferColumnWidth.gif │ └── renderScaleHeaderBackground.gif └── zh-cn │ ├── README.md │ ├── V2 │ ├── BasicControl.md │ ├── CustomLoading.md │ ├── CustomRefresh.md │ ├── GettingStart.md │ ├── Loading.md │ ├── NativeBasicControl.md │ ├── README.md │ ├── Refresh.md │ ├── Scroll.md │ ├── Update.md │ ├── Usage.md │ └── res │ │ ├── LoadingAndroid.gif │ │ ├── LoadingIOS.gif │ │ ├── LoadingProcess.png │ │ ├── RefreshAndLoading.gif │ │ ├── RefreshAndroid.gif │ │ ├── RefreshIOS.gif │ │ ├── RefreshProcess.png │ │ ├── Update.gif │ │ └── list.png │ ├── V3 │ ├── BasicUsage.md │ ├── BigMedia.md │ ├── GettingStart.md │ ├── KnownIssues.md │ ├── Loading.md │ ├── Overview.md │ ├── Refresh.md │ ├── Scroll.md │ ├── StickyForm │ │ ├── Overview.md │ │ └── Usage.md │ ├── SupportedProps.md │ └── WaterfallList │ │ ├── Overview.md │ │ └── Usage.md │ └── _sidebar.md ├── index.js ├── ios ├── LargeListDemoTests │ ├── Info.plist │ └── LargeListDemoTests.m ├── LargeListExample-Bridging-Header.h ├── LargeListExample.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ └── LargeListExample.xcscheme ├── LargeListExample.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── LargeListExample │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Empty.swift │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Info.plist │ ├── LaunchScreen.storyboard │ └── main.m ├── LargeListExampleTests-Bridging-Header.h ├── LargeListExampleTests │ ├── Info.plist │ └── LargeListExampleTests.m ├── Podfile └── Podfile.lock ├── issue_template.md ├── metro.config.js ├── package.json ├── readme_resources ├── example.gif ├── largelist_advanced_usage.png ├── sample1.gif ├── sample2.gif ├── sample3.gif ├── sample4.gif ├── sample5.gif ├── sample6.gif ├── sample7.gif └── sample8.gif └── src ├── .npmignore ├── Group.js ├── LargeList.js ├── MediaWrapper.js ├── Section.js ├── StickyForm.js ├── Types.js ├── WaterfallItem.js ├── WaterfallList.js ├── idx.js ├── index.d.ts ├── index.js ├── package.json └── styles.js /.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore unexpected extra "@providesModule" 9 | .*/node_modules/.*/node_modules/fbjs/.* 10 | 11 | ; Ignore duplicate module providers 12 | ; For RN Apps installed via npm, "Libraries" folder is inside 13 | ; "node_modules/react-native" but in the source repo it is in the root 14 | .*/Libraries/react-native/React.js 15 | 16 | ; Ignore polyfills 17 | .*/Libraries/polyfills/.* 18 | 19 | [include] 20 | 21 | [libs] 22 | node_modules/react-native/Libraries/react-native/react-native-interface.js 23 | node_modules/react-native/flow/ 24 | 25 | [options] 26 | emoji=true 27 | 28 | module.system=haste 29 | 30 | munge_underscores=true 31 | 32 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' 33 | 34 | suppress_type=$FlowIssue 35 | suppress_type=$FlowFixMe 36 | suppress_type=$FlowFixMeProps 37 | suppress_type=$FlowFixMeState 38 | suppress_type=$FixMe 39 | 40 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(5[0-3]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 41 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(5[0-3]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 42 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 43 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 44 | 45 | unsafe.enable_getters_and_setters=true 46 | 47 | [version] 48 | ^0.53.0 49 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /.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 | 24 | # Android/IntelliJ 25 | # 26 | build/ 27 | .idea 28 | .gradle 29 | local.properties 30 | *.iml 31 | 32 | # node.js 33 | # 34 | node_modules/ 35 | npm-debug.log 36 | yarn-error.log 37 | yarn.lock 38 | 39 | # BUCK 40 | buck-out/ 41 | \.buckd/ 42 | *.keystore 43 | !debug.keystore 44 | 45 | # fastlane 46 | # 47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 48 | # screenshots whenever they are needed. 49 | # For more information about the recommended setup visit: 50 | # https://docs.fastlane.tools/best-practices/source-control/ 51 | 52 | */fastlane/report.xml 53 | */fastlane/Preview.html 54 | */fastlane/screenshots 55 | 56 | # Bundle artifact 57 | *.jsbundle 58 | 59 | # CocoaPods 60 | /ios/Pods/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | demo 2 | 3 | # OSX 4 | # 5 | .DS_Store 6 | 7 | # Xcode 8 | # 9 | build/ 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | *.xccheckout 20 | *.moved-aside 21 | DerivedData 22 | *.hmap 23 | *.ipa 24 | *.xcuserstate 25 | project.xcworkspace 26 | 27 | # Android/IntelliJ 28 | # 29 | build/ 30 | .idea 31 | .gradle 32 | local.properties 33 | *.iml 34 | 35 | # node.js 36 | # 37 | node_modules/ 38 | npm-debug.log 39 | yarn-error.log 40 | 41 | # BUCK 42 | buck-out/ 43 | \.buckd/ 44 | *.keystore 45 | 46 | # fastlane 47 | # 48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 49 | # screenshots whenever they are needed. 50 | # For more information about the recommended setup visit: 51 | # https://docs.fastlane.tools/best-practices/source-control/ 52 | 53 | */fastlane/report.xml 54 | */fastlane/Preview.html 55 | */fastlane/screenshots 56 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "10" 4 | os: 5 | - osx 6 | 7 | stages: 8 | - name: deploy 9 | 10 | jobs: 11 | include: 12 | - stage: deploy 13 | deploy: 14 | provider: npm 15 | email: shanshang130@gmail.com 16 | api_key: "$NPM_TOKEN" 17 | on: 18 | tags: true 19 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /App.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 石破天惊 3 | * @email: shanshang130@gmail.com 4 | * @Date: 2021-07-21 13:45:39 5 | * @LastEditTime: 2021-07-21 17:22:46 6 | * @LastEditors: 石破天惊 7 | * @Description: 8 | */ 9 | import React from "react"; 10 | import { NavigationContainer } from "@react-navigation/native"; 11 | import { createStackNavigator } from "@react-navigation/stack"; 12 | import * as Examples from "./Examples"; 13 | const Stack = createStackNavigator(); 14 | 15 | export default class App extends React.Component { 16 | render() { 17 | return ( 18 | 19 | 20 | {Object.keys(Examples).map((key) => ( 21 | 22 | ))} 23 | 24 | 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Examples/Home.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Created by Stone 4 | * https://github.com/bolan9999 5 | * Email: shanshang130@gmail.com 6 | * Date: 2019/2/25 7 | * 8 | */ 9 | 10 | import React from "react"; 11 | import { StyleSheet, Text, TouchableOpacity } from "react-native"; 12 | import { SpringScrollView } from "react-native-spring-scrollview"; 13 | 14 | export class Home extends React.Component { 15 | static navigationOptions = { 16 | title: "Home" 17 | }; 18 | 19 | render() { 20 | const examples = ["LargeListExamples", "WaterfallListExamples", "StickyFormExample"]; 21 | return ( 22 | 23 | {examples.map((str, index) => 24 | this.props.navigation.navigate(str)}> 25 | 26 | {str} 27 | 28 | 29 | )} 30 | 31 | ); 32 | } 33 | } 34 | 35 | const styles = StyleSheet.create({ 36 | container: { 37 | flex: 1 38 | }, 39 | text: { 40 | fontSize: 16, 41 | marginTop: 20, 42 | textAlign: "center" 43 | }, 44 | button: { alignItems: "center" } 45 | }); 46 | -------------------------------------------------------------------------------- /Examples/LargeListExamples/ContactExample.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Created by Stone 4 | * https://github.com/bolan9999 5 | * Email: shanshang130@gmail.com 6 | * Date: 2018/7/22 7 | * 8 | */ 9 | 10 | import React from "react"; 11 | import { View, Image, Text, Platform, TouchableOpacity, StyleSheet, TextInput } from "react-native"; 12 | import { LargeList } from "../../src"; 13 | import { contacts } from "./DataSource"; 14 | 15 | export class ContactExample extends React.Component { 16 | static navigationOptions = { 17 | title: "ContactExample" 18 | }; 19 | 20 | largeList; 21 | 22 | constructor(props) { 23 | super(props); 24 | this.state = { data: contacts }; 25 | } 26 | 27 | render() { 28 | return ( 29 | 40} 31 | renderSection={this._renderSection} 32 | heightForIndexPath={() => 60} 33 | renderIndexPath={this._renderItem} 34 | data={this.state.data} 35 | renderHeader={this._renderHeader} 36 | renderFooter={this._renderFooter} 37 | headerStickyEnabled 38 | initialContentOffset={{ x: 0, y: 1000 }} 39 | renderEmpty={this._renderEmpty} 40 | /> 41 | ); 42 | } 43 | 44 | _renderHeader = () => { 45 | return ( 46 | 47 | 53 | 54 | ); 55 | }; 56 | 57 | _renderEmpty = () => { 58 | return ( 59 | 60 | No results found 61 | 62 | ); 63 | }; 64 | 65 | _renderFooter = () => { 66 | return ( 67 | 68 | This is the footer 69 | 70 | ); 71 | }; 72 | 73 | _renderSection = (section: number) => { 74 | const contact = this.state.data[section]; 75 | return ( 76 | 77 | {contact.header} 78 | 79 | ); 80 | }; 81 | 82 | _renderItem = ({ section: section, row: row }) => { 83 | const contact = this.state.data[section].items[row]; 84 | return ( 85 | 86 | 87 | 88 | {contact.name} 89 | {contact.phone} 90 | 91 | 92 | ); 93 | }; 94 | 95 | _search = ({ nativeEvent: { text: text } }) => { 96 | const notFound = contacts.every(contract => { 97 | if (contract.header === text) { 98 | this.setState({ data: [contract] }); 99 | return false; 100 | } 101 | return true; 102 | }); 103 | if (notFound) { 104 | this.setState({ data: [] }); 105 | } 106 | }; 107 | } 108 | 109 | const styles = StyleSheet.create({ 110 | search: { 111 | margin: 10, 112 | fontSize: 18 113 | }, 114 | empty: { 115 | marginVertical: 20, 116 | alignSelf: "center" 117 | }, 118 | section: { 119 | flex: 1, 120 | backgroundColor: "#EEE", 121 | justifyContent: "center" 122 | }, 123 | sectionText: { 124 | fontSize: 20, 125 | marginLeft: 10 126 | }, 127 | row: {flex:1, flexDirection: "row", alignItems: "center" }, 128 | image: { marginLeft: 16, width: 44, height: 44 }, 129 | rContainer: { marginLeft: 20 }, 130 | title: { fontSize: 18 }, 131 | subtitle: { fontSize: 14, marginTop: 8 } 132 | }); 133 | -------------------------------------------------------------------------------- /Examples/LargeListExamples/FlatListExample.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Created by Stone 4 | * https://github.com/bolan9999 5 | * Email: shanshang130@gmail.com 6 | * Date: 2019/2/20 7 | * 8 | */ 9 | 10 | import React from "react"; 11 | import { FlatList, Image, Text, TouchableOpacity, View } from "react-native"; 12 | import { messages } from "./DataSource"; 13 | 14 | export class FlatListExample extends React.Component { 15 | static navigationOptions = { 16 | title: "FlatListExample" 17 | }; 18 | 19 | render() { 20 | return ( 21 | index.toString()} 24 | renderItem={this._renderItem} 25 | getItemLayout={(data, index) => ({ length: 88, offset: 88 * index, index })} 26 | /> 27 | ); 28 | } 29 | 30 | _renderItem = ({ item }) => { 31 | return ; 32 | }; 33 | } 34 | 35 | class Item extends React.PureComponent<{ msg: { icon: number, title: string, subtitle: string } }> { 36 | render() { 37 | const { msg } = this.props; 38 | return ( 39 | console.log("=====>")}> 40 | 41 | 42 | 43 | 44 | {msg.title} 45 | 46 | 47 | {msg.subtitle} 48 | 49 | 50 | 51 | 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Examples/LargeListExamples/HeightEqualExample.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Created by Stone 4 | * https://github.com/bolan9999 5 | * Email: shanshang130@gmail.com 6 | * Date: 2018/7/19 7 | * 8 | */ 9 | 10 | import React from "react"; 11 | import {ImageBackground, StyleSheet, Text, TouchableOpacity, View} from "react-native"; 12 | import { LargeList } from "../../src"; 13 | 14 | export class HeightEqualExample extends React.Component { 15 | static navigationOptions = { 16 | title: "HeightEqualExample" 17 | }; 18 | 19 | _sectionCount = 10; 20 | _rowCount = 10; 21 | 22 | constructor(props) { 23 | super(props); 24 | this.state = {}; 25 | } 26 | 27 | render() { 28 | const data = []; 29 | for (let section = 0; section < this._sectionCount; ++section) { 30 | const sContent = { items: [] }; 31 | for (let row = 0; row < this._rowCount; ++row) { 32 | sContent.items.push(row); 33 | } 34 | data.push(sContent); 35 | } 36 | return ( 37 | 50} 41 | renderSection={this._renderSection} 42 | heightForIndexPath={() => 50} 43 | renderIndexPath={this._renderIndexPath} 44 | renderHeader={this._renderHeader} 45 | renderFooter={this._renderFooter} 46 | renderScaleHeaderBackground={this._renderHeaderBackground} 47 | // onTouchBegin={()=>console.log("onTouchBegin")} 48 | // onTouchEnd={()=>console.log("onTouchEnd")} 49 | // onScroll={({nativeEvent:{contentOffset:{x,y}}})=>console.log("onScroll:",x,y)} 50 | /> 51 | ); 52 | } 53 | 54 | _renderSection = (section: number) => { 55 | return ( 56 | 57 | 58 | Section {section} 59 | 60 | 61 | ); 62 | }; 63 | 64 | _renderIndexPath = ({ section: section, row: row }) => { 65 | return ( 66 | 67 | 68 | Section {section} Row {row} 69 | 70 | 71 | 72 | ); 73 | }; 74 | 75 | _renderHeaderBackground = () => { 76 | return ; 77 | }; 78 | 79 | _renderHeader = () => { 80 | return ( 81 | console.log("_renderHeader")}> 82 | I am header 83 | 84 | ); 85 | }; 86 | 87 | _renderFooter = () => { 88 | return ( 89 | console.log("_renderFooter")}> 90 | I am Footer 91 | 92 | ); 93 | }; 94 | } 95 | 96 | const styles = StyleSheet.create({ 97 | container: { 98 | flex: 1 99 | }, 100 | header: { 101 | alignSelf: "center", 102 | marginVertical: 50 103 | }, 104 | section: { 105 | flex: 1, 106 | backgroundColor: "gray", 107 | justifyContent: "center", 108 | alignItems: "center" 109 | }, 110 | row: { 111 | flex:1, 112 | justifyContent: "center", 113 | alignItems: "center" 114 | }, 115 | line: { 116 | position: "absolute", 117 | left: 0, 118 | right: 0, 119 | bottom: 0, 120 | height: 1, 121 | backgroundColor: "#EEE" 122 | } 123 | }); 124 | -------------------------------------------------------------------------------- /Examples/LargeListExamples/HeightUnequalExample.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Created by Stone 4 | * https://github.com/bolan9999 5 | * Email: shanshang130@gmail.com 6 | * Date: 2018/7/18 7 | * 8 | */ 9 | 10 | import React from "react"; 11 | import { StyleSheet, Text, View } from "react-native"; 12 | import { LargeList } from "../../src"; 13 | import { CommonLottieHeader } from "react-native-spring-scrollview/Customize/CommonLottieHeader"; 14 | import { CommonLottieFooter } from "react-native-spring-scrollview/Customize/CommonLottieFooter"; 15 | export class HeightUnequalExample extends React.Component { 16 | static navigationOptions = { 17 | title: "HeightUnequalExample", 18 | }; 19 | 20 | _sectionCount = 1; 21 | _rowCount = 5; 22 | _list: LargeList; 23 | 24 | constructor(props) { 25 | super(props); 26 | this.state = { select: 0 }; 27 | } 28 | 29 | render() { 30 | const data = []; 31 | for (let section = 0; section < this._sectionCount; ++section) { 32 | const sContent = { items: [] }; 33 | for (let row = 0; row < this._rowCount; ++row) { 34 | sContent.items.push(row); 35 | } 36 | data.push(sContent); 37 | } 38 | return ( 39 | (this._list = ref)} 42 | heightForSection={() => 50} 43 | renderSection={this._renderSection} 44 | heightForIndexPath={({ section: section, row: row }) => 45 | row % 2 ? 50 : 100 46 | } 47 | renderIndexPath={this._renderIndexPath} 48 | refreshHeader={CommonLottieHeader} 49 | loadingFooter={CommonLottieFooter} 50 | onRefresh={this._onRefresh} 51 | onLoading={this._onLoading} 52 | /> 53 | ); 54 | } 55 | 56 | _onRefresh = () => { 57 | setTimeout(() => this._list.endRefresh(), 2000); 58 | }; 59 | _onLoading = () => { 60 | setTimeout(() => this._list.endLoading(true), 2000); 61 | }; 62 | 63 | _renderSection = (section: number) => { 64 | return ( 65 | 66 | Section {section} 67 | 68 | ); 69 | }; 70 | 71 | _renderIndexPath = ({ section: section, row: row }) => { 72 | return ( 73 | 74 | 75 | Section {section} Row {row} 76 | 77 | 78 | 79 | ); 80 | }; 81 | } 82 | 83 | const styles = StyleSheet.create({ 84 | section: { 85 | flex: 1, 86 | backgroundColor: "gray", 87 | justifyContent: "center", 88 | alignItems: "center", 89 | }, 90 | row: { 91 | flex:1, 92 | justifyContent: "center", 93 | alignItems: "center", 94 | }, 95 | line: { 96 | position: "absolute", 97 | left: 0, 98 | right: 0, 99 | bottom: 0, 100 | height: 1, 101 | backgroundColor: "#EEE", 102 | }, 103 | }); 104 | -------------------------------------------------------------------------------- /Examples/LargeListExamples/IntensiveSectionExample.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 石破天惊 3 | * @email: shanshang130@gmail.com 4 | * @Date: 2021-07-21 13:11:34 5 | * @LastEditTime: 2021-07-28 09:38:05 6 | * @LastEditors: 石破天惊 7 | * @Description: 8 | */ 9 | /* 10 | * 11 | * Created by Stone 12 | * https://github.com/bolan9999 13 | * Email: shanshang130@gmail.com 14 | * Date: 2018/7/25 15 | * 16 | */ 17 | 18 | import React from "react"; 19 | import { StyleSheet, Text, View } from "react-native"; 20 | import { LargeList } from "../../src"; 21 | 22 | export class IntensiveSectionExample extends React.Component { 23 | static navigationOptions = { 24 | title: "IntensiveSectionExample" 25 | }; 26 | 27 | _sectionCount = 100; 28 | _rowCount = 1; 29 | 30 | constructor(props) { 31 | super(props); 32 | this.state = {}; 33 | } 34 | 35 | render() { 36 | const data = []; 37 | for (let section = 0; section < this._sectionCount; ++section) { 38 | const sContent = { items: [] }; 39 | for (let row = 0; row < this._rowCount; ++row) { 40 | sContent.items.push(row); 41 | } 42 | data.push(sContent); 43 | } 44 | return ( 45 | 50} 48 | renderSection={this._renderSection} 49 | heightForIndexPath={() => 50} 50 | renderIndexPath={this._renderIndexPath} 51 | /> 52 | ); 53 | } 54 | 55 | _renderSection = (section: number) => { 56 | return ( 57 | 58 | 59 | Section {section} 60 | 61 | 62 | ); 63 | }; 64 | 65 | _renderIndexPath = ({ section: section, row: row }) => { 66 | return ( 67 | 68 | 69 | Section {section} Row {row} 70 | 71 | 72 | 73 | ); 74 | }; 75 | } 76 | 77 | const styles = StyleSheet.create({ 78 | section: { 79 | flex: 1, 80 | backgroundColor: "gray", 81 | justifyContent: "center", 82 | alignItems: "center" 83 | }, 84 | row: { 85 | flex:1, 86 | justifyContent: "center", 87 | alignItems: "center" 88 | }, 89 | line: { 90 | position: "absolute", 91 | left: 0, 92 | right: 0, 93 | bottom: 0, 94 | height: 1, 95 | backgroundColor: "#EEE" 96 | } 97 | }); 98 | -------------------------------------------------------------------------------- /Examples/LargeListExamples/LargeListExamples.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 石破天惊 3 | * @email: shanshang130@gmail.com 4 | * @Date: 2021-07-21 13:11:34 5 | * @LastEditTime: 2021-07-28 11:29:05 6 | * @LastEditors: 石破天惊 7 | * @Description: 8 | */ 9 | /* 10 | * 11 | * Created by Stone 12 | * https://github.com/bolan9999 13 | * Email: shanshang130@gmail.com 14 | * Date: 2019/2/25 15 | * 16 | */ 17 | 18 | import React from "react"; 19 | import { SpringScrollView } from "react-native-spring-scrollview"; 20 | import {StyleSheet, Text, TouchableOpacity} from "react-native"; 21 | 22 | export class LargeListExamples extends React.Component { 23 | static navigationOptions = { 24 | title: "LargeListExamples" 25 | }; 26 | 27 | render() { 28 | return ( 29 | 30 | {this.state.examples.map((example, index) => 31 | this.props.navigation.navigate(example)} 35 | > 36 | 37 | {example} 38 | 39 | 40 | )} 41 | 42 | ); 43 | } 44 | 45 | state = { 46 | examples: [ 47 | "HeightEqualExample", 48 | "HeightUnequalExample", 49 | "MessageExample", 50 | "ContactExample", 51 | "MenuListExample", 52 | "RefreshAndLoadingExample", 53 | "IntensiveSectionExample", 54 | "ChatExample", 55 | "FlatListExample", 56 | "BigMediaExample" 57 | ] 58 | }; 59 | } 60 | 61 | const styles = StyleSheet.create({ 62 | container: { 63 | flex: 1 64 | }, 65 | text: { 66 | fontSize: 16, 67 | marginTop: 20, 68 | textAlign: "center" 69 | }, 70 | button: { alignItems: "center" } 71 | }); 72 | -------------------------------------------------------------------------------- /Examples/LargeListExamples/MenuListExample.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Created by Stone 4 | * https://github.com/bolan9999 5 | * Email: shanshang130@gmail.com 6 | * Date: 2018/7/22 7 | * 8 | */ 9 | 10 | import React from "react"; 11 | import { 12 | View, 13 | Text, 14 | Image, 15 | TouchableOpacity, 16 | StyleSheet, 17 | Platform 18 | } from "react-native"; 19 | import { foods } from "./DataSource"; 20 | import { LargeList } from "../../src"; 21 | 22 | const leftData = [{ items: foods }]; 23 | 24 | export class MenuListExample extends React.Component { 25 | static navigationOptions = { 26 | title: "MenuListExample" 27 | }; 28 | 29 | selectedIndex: number = 0; 30 | _listRef: LargeList; 31 | indexes: LargeList; 32 | _buttonRefs: [] = []; 33 | 34 | constructor(props) { 35 | super(props); 36 | for (let s = 0; s < foods.length; ++s) { 37 | const refs = []; 38 | for (let r = 0; r < foods[s].items.length; ++r) { 39 | refs.push(React.createRef()); 40 | } 41 | this._buttonRefs.push(refs); 42 | } 43 | } 44 | 45 | render() { 46 | const buttons = []; 47 | this._buttonRefs.forEach(btn => buttons.concat(btn)); 48 | return ( 49 | 50 | (this.indexes = ref)} 53 | showsVerticalScrollIndicator={false} 54 | bounces={false} 55 | data={leftData} 56 | heightForIndexPath={() => 80} 57 | renderIndexPath={this.renderIndexes} 58 | /> 59 | (this._listRef = ref)} 61 | style={styles.rc} 62 | data={foods} 63 | heightForSection={() => 36} 64 | renderSection={this.renderSection} 65 | heightForIndexPath={() => 96} 66 | renderIndexPath={this.renderItem} 67 | /> 68 | 69 | ); 70 | } 71 | 72 | renderIndexes = ({ section: section, row: row }) => { 73 | const food = leftData[section].items[row]; 74 | return ( 75 | { 79 | this._listRef 80 | .scrollToIndexPath({ section: row, row: -1 }, true) 81 | .then(); 82 | }} 83 | > 84 | 85 | {food.header} 86 | 87 | 88 | 89 | ); 90 | }; 91 | 92 | renderSection = (section: number) => { 93 | const sectionData = foods[section]; 94 | return ( 95 | 96 | 97 | {sectionData.header} 98 | 99 | 100 | ); 101 | }; 102 | 103 | renderItem = ({ section: section, row: row }) => { 104 | let food = foods[section].items[row]; 105 | return ( 106 | 107 | 108 | 118 | 119 | 120 | {food.title} 121 | 122 | 123 | {food.subtitle} 124 | 125 | 126 | 127 | {food.sales} 128 | 129 | 130 | {food.praise} 131 | 132 | 133 | 136 | 137 | {food.prise} 138 | 139 | this.onBuy(food)} 146 | > 147 | 购买 148 | 149 | 150 | 151 | 152 | {row < foods[section].items.length - 1 && 153 | } 154 | 155 | ); 156 | }; 157 | 158 | onBuy = () => { 159 | console.log("buy"); 160 | }; 161 | } 162 | 163 | const styles = StyleSheet.create({ 164 | container: { 165 | flex: 1, 166 | flexDirection: "row" 167 | }, 168 | lc: { 169 | flex: 1 170 | }, 171 | rc: { 172 | flex: 4, 173 | flexGrow: 4 174 | }, 175 | indexes: { 176 | flex:1, 177 | backgroundColor: "#EEE", 178 | justifyContent: "center", 179 | alignItems: "center" 180 | }, 181 | line: { 182 | position: "absolute", 183 | left: 0, 184 | right: 0, 185 | bottom: 0, 186 | height: 1, 187 | backgroundColor: "#999" 188 | }, 189 | section: { flex: 1, backgroundColor: "#AAA", justifyContent: "center" }, 190 | sectionText: { marginLeft: 10, fontSize: 18 }, 191 | rowLine: { 192 | height: 1, 193 | backgroundColor: "#999", 194 | marginLeft: 16 195 | } 196 | }); 197 | 198 | -------------------------------------------------------------------------------- /Examples/LargeListExamples/MessageExample.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 石破天惊 3 | * @email: shanshang130@gmail.com 4 | * @Date: 2021-07-21 13:11:34 5 | * @LastEditTime: 2021-07-28 16:00:11 6 | * @LastEditors: 石破天惊 7 | * @Description: 8 | */ 9 | /* 10 | * 11 | * Created by Stone 12 | * https://github.com/bolan9999 13 | * Email: shanshang130@gmail.com 14 | * Date: 2018/7/20 15 | * 16 | */ 17 | 18 | import React from "react"; 19 | import { View, Image, Text, ScrollView, TouchableOpacity } from "react-native"; 20 | import { messages } from "./DataSource"; 21 | import { LargeList } from "../../src"; 22 | 23 | export class MessageExample extends React.Component { 24 | static navigationOptions = { 25 | title: "MessageExample", 26 | }; 27 | 28 | messages; 29 | largeList; 30 | 31 | constructor(props) { 32 | super(props); 33 | this.state = { refreshing: false }; 34 | this.messages = [...messages]; 35 | } 36 | 37 | render() { 38 | return ( 39 | (this.largeList = ref)} 42 | heightForSection={() => 0} 43 | renderSection={() => null} 44 | heightForIndexPath={() => 88} 45 | renderIndexPath={this._renderItem} 46 | data={this.messages} 47 | /> 48 | ); 49 | } 50 | 51 | _renderItem = ({ section: section, row: row }) => { 52 | let msg = this.messages[section].items[row]; 53 | return ( 54 | console.log("=====>")} 57 | > 58 | 59 | 63 | 64 | {msg.title} 65 | {msg.subtitle} 66 | 67 | 68 | 69 | ); 70 | }; 71 | } 72 | -------------------------------------------------------------------------------- /Examples/LargeListExamples/RefreshAndLoadingExample.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Created by Stone 4 | * https://github.com/bolan9999 5 | * Email: shanshang130@gmail.com 6 | * Date: 2018/7/24 7 | * 8 | */ 9 | 10 | import React from "react"; 11 | import { Image, StyleSheet, Text, TouchableOpacity, View } from "react-native"; 12 | import { NormalHeader } from "react-native-spring-scrollview/NormalHeader"; 13 | import { NormalFooter } from "react-native-spring-scrollview/NormalFooter"; 14 | import { LargeList } from "../../src"; 15 | import { contacts } from "./DataSource"; 16 | 17 | export class RefreshAndLoadingExample extends React.Component { 18 | 19 | static navigationOptions = { 20 | title: "RefreshAndLoadingExample" 21 | }; 22 | 23 | _largeList; 24 | _index = 0; 25 | 26 | state = { data: [contacts[0]], allLoaded: false }; 27 | 28 | render() { 29 | return ( 30 | (this._largeList = ref)} 32 | data={this.state.data} 33 | heightForSection={() => 40} 34 | renderSection={this._renderSection} 35 | heightForIndexPath={() => 60} 36 | renderIndexPath={this._renderItem} 37 | refreshHeader={NormalHeader} 38 | onRefresh={this._onRefresh} 39 | loadingFooter={NormalFooter} 40 | onLoading={this._onLoading} 41 | allLoaded={this.state.allLoaded} 42 | renderHeader={this._renderHeader} 43 | renderFooter={this._renderFooter} 44 | /> 45 | ); 46 | } 47 | _renderHeader = () => { 48 | return ( 49 | 50 | this._largeList.beginRefresh()}> 51 | I am header. Click to begin refresh 52 | 53 | 54 | ); 55 | }; 56 | 57 | _renderFooter = () => { 58 | return ( 59 | 60 | I am Footer 61 | 62 | ); 63 | }; 64 | 65 | _onRefresh = () => { 66 | setTimeout(() => { 67 | this._largeList.endRefresh(); 68 | this._index = 0; 69 | this.setState({ 70 | data: [contacts[this._index]], 71 | allLoaded: this._index > 2 72 | }); 73 | }, 2000); 74 | }; 75 | 76 | _onLoading = () => { 77 | setTimeout(() => { 78 | this._largeList.endLoading(); 79 | this.setState(p => ({ 80 | data: p.data.concat(contacts[++this._index]), 81 | allLoaded: this._index > 2 82 | })); 83 | }, 2000); 84 | }; 85 | 86 | _renderSection = (section: number) => { 87 | const contact = this.state.data[section]; 88 | return ( 89 | 90 | 91 | {contact.header} 92 | 93 | 94 | ); 95 | }; 96 | 97 | _renderItem = ({ section: section, row: row }) => { 98 | const contact = this.state.data[section].items[row]; 99 | return ( 100 | 101 | 102 | 103 | 104 | {contact.name} 105 | 106 | 107 | {contact.phone} 108 | 109 | 110 | 111 | ); 112 | }; 113 | } 114 | 115 | const styles = StyleSheet.create({ 116 | search: { 117 | marginTop: 20, 118 | fontSize: 18 119 | }, 120 | section: { 121 | flex: 1, 122 | backgroundColor: "#EEE", 123 | justifyContent: "center" 124 | }, 125 | sectionText: { 126 | fontSize: 20, 127 | marginLeft: 10 128 | }, 129 | header: { 130 | alignSelf: "center", 131 | marginVertical: 30 132 | }, 133 | row: { flex:1, flexDirection: "row", alignItems: "center" }, 134 | image: { marginLeft: 16, width: 44, height: 44 }, 135 | rContainer: { marginLeft: 20 }, 136 | title: { fontSize: 18 }, 137 | subtitle: { fontSize: 14, marginTop: 8 } 138 | }); 139 | -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/ScaleHeader.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/Examples/LargeListExamples/icons/ScaleHeader.jpg -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/icon10@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/Examples/LargeListExamples/icons/icon10@2x.png -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/icon10@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/Examples/LargeListExamples/icons/icon10@3x.png -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/icon1@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/Examples/LargeListExamples/icons/icon1@2x.png -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/icon1@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/Examples/LargeListExamples/icons/icon1@3x.png -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/icon2@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/Examples/LargeListExamples/icons/icon2@2x.png -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/icon2@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/Examples/LargeListExamples/icons/icon2@3x.png -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/icon3@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/Examples/LargeListExamples/icons/icon3@2x.png -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/icon3@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/Examples/LargeListExamples/icons/icon3@3x.png -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/icon4@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/Examples/LargeListExamples/icons/icon4@2x.png -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/icon4@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/Examples/LargeListExamples/icons/icon4@3x.png -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/icon5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/Examples/LargeListExamples/icons/icon5.png -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/icon6@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/Examples/LargeListExamples/icons/icon6@2x.png -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/icon6@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/Examples/LargeListExamples/icons/icon6@3x.png -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/icon7@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/Examples/LargeListExamples/icons/icon7@2x.png -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/icon7@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/Examples/LargeListExamples/icons/icon7@3x.png -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/icon8@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/Examples/LargeListExamples/icons/icon8@2x.png -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/icon8@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/Examples/LargeListExamples/icons/icon8@3x.png -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/icon9@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/Examples/LargeListExamples/icons/icon9@2x.png -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/icon9@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/Examples/LargeListExamples/icons/icon9@3x.png -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Created by Stone 4 | * https://github.com/bolan9999 5 | * Email: bolan999999@gmail.com 6 | * Date: 2017/12/14 7 | * 8 | */ 9 | 10 | let iconObject = { 11 | icon1: require("./icon1.png"), 12 | icon2: require("./icon2.png"), 13 | icon3: require("./icon3.png"), 14 | icon4: require("./icon4.png"), 15 | icon5: require("./icon5.png"), 16 | icon6: require("./icon6.png"), 17 | icon7: require("./icon7.png"), 18 | icon8: require("./icon8.png"), 19 | icon9: require("./icon9.png"), 20 | icon10: require("./icon10.png"), 21 | icon11: require("./icon8.png") 22 | }; 23 | 24 | let iconArray = Object.values(iconObject); 25 | 26 | export { iconObject, iconArray }; 27 | -------------------------------------------------------------------------------- /Examples/LargeListExamples/icons/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/Examples/LargeListExamples/icons/loading.gif -------------------------------------------------------------------------------- /Examples/LargeListExamples/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Created by Stone 4 | * https://github.com/bolan9999 5 | * Email: shanshang130@gmail.com 6 | * Date: 2019/2/25 7 | * 8 | */ 9 | 10 | export * from "./HeightUnequalExample"; 11 | export * from "./HeightEqualExample"; 12 | export * from "./MessageExample"; 13 | export * from "./ContactExample"; 14 | export * from "./MenuListExample"; 15 | export * from "./RefreshAndLoadingExample"; 16 | export * from "./IntensiveSectionExample"; 17 | export * from "./ChatExample"; 18 | export * from "./FlatListExample"; 19 | export * from "./LargeListExamples"; 20 | export * from "./BigMediaExample"; 21 | -------------------------------------------------------------------------------- /Examples/StickyFormExamples/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Created by Stone 4 | * https://github.com/bolan9999 5 | * Email: shanshang130@gmail.com 6 | * Date: 2019/2/25 7 | * 8 | */ 9 | 10 | export * from "./StickyFormExample"; 11 | -------------------------------------------------------------------------------- /Examples/WaterfallListExamples/PictureExample.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Created by Stone 4 | * https://github.com/bolan9999 5 | * Email: shanshang130@gmail.com 6 | * Date: 2019/2/20 7 | * 8 | */ 9 | 10 | import React from "react"; 11 | import { Image, SafeAreaView, Dimensions } from "react-native"; 12 | import { WaterfallList } from "../../src"; 13 | 14 | const cookData = require("./data.json").data.list; 15 | 16 | export class PictureExample extends React.Component { 17 | static navigationOptions = { 18 | title: "PictureExample" 19 | }; 20 | 21 | state = { data: [...cookData, ...cookData, ...cookData, ...cookData, ...cookData] }; 22 | 23 | render() { 24 | const screenWidth = Dimensions.get("window").width; 25 | return ( 26 | screenWidth / Math.floor(screenWidth / 150) * +item.showimg_height / +item.showimg_width} 29 | numColumns={2} 30 | // preferColumnWidth={150} 31 | renderItem={this._renderItem} 32 | /> 33 | ); 34 | } 35 | 36 | _renderItem = item => { 37 | return ; 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /Examples/WaterfallListExamples/WaterfallListExample.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Created by Stone 4 | * https://github.com/bolan9999 5 | * Email: shanshang130@gmail.com 6 | * Date: 2019/2/20 7 | * 8 | */ 9 | 10 | import React from "react"; 11 | import { WaterfallList } from "../../src"; 12 | import { Text, View } from "react-native"; 13 | 14 | export class WaterfallListExample extends React.Component { 15 | static navigationOptions = { 16 | title: "WaterfallListExample" 17 | }; 18 | 19 | state = { data: [...data, ...data, ...data, ...data, ...data, ...data, ...data, ...data, ...data] }; 20 | _list: WaterfallList; 21 | 22 | render() { 23 | return ( 24 | (this._list = ref)} 27 | heightForItem={item => item.height} 28 | preferColumnWidth={120} 29 | renderItem={this._renderItem} 30 | renderHeader={this._renderHeader} 31 | renderFooter={this._renderFooter} 32 | onRefresh={() => { 33 | setTimeout(() => this._list.endRefresh(), 2000); 34 | }} 35 | onLoading={() => { 36 | setTimeout(() => this._list.endLoading(), 2000); 37 | }} 38 | /> 39 | ); 40 | } 41 | 42 | _renderItem = (item, index) => { 43 | return ( 44 | 45 | 46 | index:{index}, height:{item.height} 47 | 48 | 49 | ); 50 | }; 51 | 52 | _renderHeader = () => { 53 | return ( 54 | 55 | I am header 56 | 57 | ); 58 | }; 59 | 60 | _renderFooter = () => { 61 | return ( 62 | 63 | I am footer 64 | 65 | ); 66 | }; 67 | } 68 | 69 | const data = [ 70 | { height: 40, color: "aliceblue" }, 71 | { height: 60, color: "antiquewhite" }, 72 | { height: 80, color: "aqua" }, 73 | { height: 100, color: "aquamarine" }, 74 | { height: 120, color: "azure" }, 75 | { height: 140, color: "beige" }, 76 | { height: 160, color: "bisque" }, 77 | { height: 40, color: "blue" }, 78 | { height: 60, color: "blueviolet" }, 79 | { height: 80, color: "brown" }, 80 | { height: 100, color: "burlywood" }, 81 | { height: 120, color: "cadetblue" }, 82 | { height: 140, color: "chartreuse" }, 83 | { height: 160, color: "chocolate" }, 84 | { height: 40, color: "coral" }, 85 | { height: 60, color: "cornflowerblue" }, 86 | { height: 80, color: "cornsilk" }, 87 | { height: 100, color: "crimson" }, 88 | { height: 120, color: "cyan" }, 89 | { height: 140, color: "darkblue" }, 90 | { height: 160, color: "darkcyan" }, 91 | { height: 40, color: "aliceblue" }, 92 | { height: 60, color: "antiquewhite" }, 93 | { height: 80, color: "aqua" }, 94 | { height: 100, color: "aquamarine" }, 95 | { height: 120, color: "azure" }, 96 | { height: 140, color: "beige" }, 97 | { height: 160, color: "bisque" }, 98 | { height: 40, color: "blue" }, 99 | { height: 60, color: "blueviolet" }, 100 | { height: 80, color: "brown" }, 101 | { height: 100, color: "burlywood" }, 102 | { height: 120, color: "cadetblue" }, 103 | { height: 140, color: "chartreuse" }, 104 | { height: 160, color: "chocolate" }, 105 | { height: 40, color: "coral" }, 106 | { height: 60, color: "cornflowerblue" }, 107 | { height: 80, color: "cornsilk" }, 108 | { height: 100, color: "crimson" }, 109 | { height: 120, color: "cyan" }, 110 | { height: 140, color: "darkblue" }, 111 | { height: 160, color: "darkcyan" } 112 | ]; 113 | -------------------------------------------------------------------------------- /Examples/WaterfallListExamples/WaterfallListExamples.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Created by Stone 4 | * https://github.com/bolan9999 5 | * Email: shanshang130@gmail.com 6 | * Date: 2019/2/25 7 | * 8 | */ 9 | 10 | import React from "react"; 11 | import { SpringScrollView } from "react-native-spring-scrollview"; 12 | import { StyleSheet, Text, TouchableOpacity } from "react-native"; 13 | import { WaterfallListExample } from "./WaterfallListExample"; 14 | import { PictureExample } from "./PictureExample"; 15 | 16 | export class WaterfallListExamples extends React.Component { 17 | static navigationOptions = { 18 | title: "WaterfallListExamples" 19 | }; 20 | 21 | render() { 22 | return ( 23 | 24 | {this.state.examples.map((example, index) => 25 | this.props.navigation.navigate(example)}> 26 | 27 | {example} 28 | 29 | 30 | )} 31 | 32 | ); 33 | } 34 | 35 | state = { 36 | examples: ["WaterfallListExample", "PictureExample"] 37 | }; 38 | } 39 | 40 | const styles = StyleSheet.create({ 41 | container: { 42 | flex: 1 43 | }, 44 | text: { 45 | fontSize: 16, 46 | marginTop: 20, 47 | textAlign: "center" 48 | }, 49 | button: { alignItems: "center" } 50 | }); 51 | -------------------------------------------------------------------------------- /Examples/WaterfallListExamples/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Created by Stone 4 | * https://github.com/bolan9999 5 | * Email: shanshang130@gmail.com 6 | * Date: 2019/2/25 7 | * 8 | */ 9 | 10 | export * from "./WaterfallListExamples"; 11 | export * from "./PictureExample"; 12 | export * from "./WaterfallListExample" 13 | -------------------------------------------------------------------------------- /Examples/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Created by Stone 4 | * https://github.com/bolan9999 5 | * Email: bolan999999@gmail.com 6 | * Date: 2017/12/2 7 | * 8 | */ 9 | 10 | export * from "./LargeListExamples"; 11 | export * from "./StickyFormExamples"; 12 | export * from "./WaterfallListExamples"; 13 | export * from "./Home"; 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 bolan9999 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 9 | # react-native-largelist 10 | 11 | **React-native-largelist** is a very high performance large list component for React-Native. (iOS & Android) 12 | ## Features 13 | 14 | * Large data source list component, items reused by group, Less CPU/Memory usage. Never blanks. 15 | * Fully Cross-platform bounces (iOS & Android). 16 | * Highly customize Refreshing and Loading. Fully support `react-native-lottie`. More smoothly animation. 17 | * Big media optimization. (New) 18 | * Nested support. (New) 19 | * Paging enabled. (New) 20 | 21 | ## Preview 22 | ![Preview](./docs/res/LottieRefreshing.gif) 23 | ![Preview](./docs/res/LottieLoading.gif) 24 | ![WaterfallExample](./docs/res/WaterfallExample.gif) 25 | ![PictureExample](./docs/res/PictureExample.gif) 26 | 27 | ## Installation 28 | 29 | ``` 30 | yarn add react-native-spring-scrollview react-native-largelist 31 | 32 | ``` 33 | RN 0.50-59 without pod 34 | ``` 35 | react-native link react-native-spring-scrollview 36 | ``` 37 | 38 | RN 0.60+ with pod 39 | ``` 40 | npx pod-install 41 | ``` 42 | 43 | ## Documentation 44 | 45 | API reference and more: [Documentation Reference](https://bolan9999.github.io/react-native-largelist/) 46 | 47 | ## License 48 | 49 | react-native-largelist is released under the MIT license. View LICENSE for details. 50 | 51 | 52 | -------------------------------------------------------------------------------- /__tests__/App-test.js: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /android/LargeListDemo.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /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.largelistdemo", 39 | ) 40 | 41 | android_resource( 42 | name = "res", 43 | package = "com.largelistdemo", 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 | -------------------------------------------------------------------------------- /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.largelistexample", 39 | ) 40 | 41 | android_resource( 42 | name = "res", 43 | package = "com.largelistexample", 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/android/app/debug.keystore -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /android/app/src/debug/java/com/largelistexample/ReactNativeFlipper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | *

This source code is licensed under the MIT license found in the LICENSE file in the root 5 | * directory of this source tree. 6 | */ 7 | package com.largelistexample; 8 | 9 | import android.content.Context; 10 | import com.facebook.flipper.android.AndroidFlipperClient; 11 | import com.facebook.flipper.android.utils.FlipperUtils; 12 | import com.facebook.flipper.core.FlipperClient; 13 | import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin; 14 | import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin; 15 | import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin; 16 | import com.facebook.flipper.plugins.inspector.DescriptorMapping; 17 | import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin; 18 | import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; 19 | import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; 20 | import com.facebook.flipper.plugins.react.ReactFlipperPlugin; 21 | import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; 22 | import com.facebook.react.ReactInstanceManager; 23 | import com.facebook.react.bridge.ReactContext; 24 | import com.facebook.react.modules.network.NetworkingModule; 25 | import okhttp3.OkHttpClient; 26 | 27 | public class ReactNativeFlipper { 28 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { 29 | if (FlipperUtils.shouldEnableFlipper(context)) { 30 | final FlipperClient client = AndroidFlipperClient.getInstance(context); 31 | 32 | client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults())); 33 | client.addPlugin(new ReactFlipperPlugin()); 34 | client.addPlugin(new DatabasesFlipperPlugin(context)); 35 | client.addPlugin(new SharedPreferencesFlipperPlugin(context)); 36 | client.addPlugin(CrashReporterPlugin.getInstance()); 37 | 38 | NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin(); 39 | NetworkingModule.setCustomClientBuilder( 40 | new NetworkingModule.CustomClientBuilder() { 41 | @Override 42 | public void apply(OkHttpClient.Builder builder) { 43 | builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin)); 44 | } 45 | }); 46 | client.addPlugin(networkFlipperPlugin); 47 | client.start(); 48 | 49 | // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized 50 | // Hence we run if after all native modules have been initialized 51 | ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); 52 | if (reactContext == null) { 53 | reactInstanceManager.addReactInstanceEventListener( 54 | new ReactInstanceManager.ReactInstanceEventListener() { 55 | @Override 56 | public void onReactContextInitialized(ReactContext reactContext) { 57 | reactInstanceManager.removeReactInstanceEventListener(this); 58 | reactContext.runOnNativeModulesQueueThread( 59 | new Runnable() { 60 | @Override 61 | public void run() { 62 | client.addPlugin(new FrescoFlipperPlugin()); 63 | } 64 | }); 65 | } 66 | }); 67 | } else { 68 | client.addPlugin(new FrescoFlipperPlugin()); 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 13 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/largelistexample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.largelistexample; 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 "LargeListExample"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/largelistexample/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.largelistexample; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | import com.bolan9999.SpringScrollViewPackage; 7 | import com.facebook.react.PackageList; 8 | import com.facebook.react.ReactApplication; 9 | import com.facebook.react.ReactInstanceManager; 10 | import com.facebook.react.ReactNativeHost; 11 | import com.facebook.react.ReactPackage; 12 | import com.facebook.soloader.SoLoader; 13 | import java.lang.reflect.InvocationTargetException; 14 | import java.util.List; 15 | 16 | public class MainApplication extends Application implements ReactApplication { 17 | 18 | private final ReactNativeHost mReactNativeHost = 19 | new ReactNativeHost(this) { 20 | @Override 21 | public boolean getUseDeveloperSupport() { 22 | return BuildConfig.DEBUG; 23 | } 24 | 25 | @Override 26 | protected List getPackages() { 27 | @SuppressWarnings("UnnecessaryLocalVariable") 28 | List packages = new PackageList(this).getPackages(); 29 | // Packages that cannot be autolinked yet can be added manually here, for example: 30 | // packages.add(new SpringScrollViewPackage()); 31 | return packages; 32 | } 33 | 34 | @Override 35 | protected String getJSMainModuleName() { 36 | return "index"; 37 | } 38 | }; 39 | 40 | @Override 41 | public ReactNativeHost getReactNativeHost() { 42 | return mReactNativeHost; 43 | } 44 | 45 | @Override 46 | public void onCreate() { 47 | super.onCreate(); 48 | SoLoader.init(this, /* native exopackage */ false); 49 | initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); 50 | } 51 | 52 | /** 53 | * Loads Flipper in React Native templates. Call this in the onCreate method with something like 54 | * initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); 55 | * 56 | * @param context 57 | * @param reactInstanceManager 58 | */ 59 | private static void initializeFlipper( 60 | Context context, ReactInstanceManager reactInstanceManager) { 61 | if (BuildConfig.DEBUG) { 62 | try { 63 | /* 64 | We use reflection here to pick up the class that initializes Flipper, 65 | since Flipper library is not available in release mode 66 | */ 67 | Class aClass = Class.forName("com.largelistexample.ReactNativeFlipper"); 68 | aClass 69 | .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class) 70 | .invoke(null, context, reactInstanceManager); 71 | } catch (ClassNotFoundException e) { 72 | e.printStackTrace(); 73 | } catch (NoSuchMethodException e) { 74 | e.printStackTrace(); 75 | } catch (IllegalAccessException e) { 76 | e.printStackTrace(); 77 | } catch (InvocationTargetException e) { 78 | e.printStackTrace(); 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | LargeListExample 3 | 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /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 = "29.0.3" 6 | minSdkVersion = 21 7 | compileSdkVersion = 29 8 | targetSdkVersion = 29 9 | ndkVersion = "20.1.5948944" 10 | } 11 | repositories { 12 | google() 13 | jcenter() 14 | } 15 | dependencies { 16 | classpath('com.android.tools.build:gradle:4.1.1') 17 | // NOTE: Do not place your application dependencies here; they belong 18 | // in the individual module build.gradle files 19 | } 20 | } 21 | 22 | allprojects { 23 | repositories { 24 | mavenLocal() 25 | maven { 26 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 27 | url("$rootDir/../node_modules/react-native/android") 28 | } 29 | maven { 30 | // Android JSC is installed from npm 31 | url("$rootDir/../node_modules/jsc-android/dist") 32 | } 33 | 34 | google() 35 | jcenter() 36 | maven { url 'https://www.jitpack.io' } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /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 | # AndroidX package structure to make it clearer which packages are bundled with the 21 | # Android operating system, and which are packaged with your app's APK 22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 23 | android.useAndroidX=true 24 | # Automatically convert third-party libraries to use AndroidX 25 | android.enableJetifier=true 26 | 27 | # Version of flipper SDK to use with React Native 28 | FLIPPER_VERSION=0.75.1 29 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /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 https://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 Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /android/keystores/BUCK: -------------------------------------------------------------------------------- 1 | keystore( 2 | name = "debug", 3 | properties = "debug.keystore.properties", 4 | store = "debug.keystore", 5 | visibility = [ 6 | "PUBLIC", 7 | ], 8 | ) 9 | -------------------------------------------------------------------------------- /android/keystores/debug.keystore.properties: -------------------------------------------------------------------------------- 1 | key.store=debug.keystore 2 | key.alias=androiddebugkey 3 | key.store.password=android 4 | key.alias.password=android 5 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'LargeListExample' 2 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) 3 | include ':react-native-spring-scrollview' 4 | project(':react-native-spring-scrollview').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-spring-scrollview/android') 5 | include ':app' 6 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "LargeListExample", 3 | "displayName": "LargeListExample" 4 | } -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:metro-react-native-babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/.nojekyll -------------------------------------------------------------------------------- /docs/_coverpage.md: -------------------------------------------------------------------------------- 1 | # React Native Large List 2 | 3 | > The best large list component for React Native. 4 | 5 | [github](https://github.com/bolan9999/react-native-largelist) 6 | [Get Started](en/) 7 | [中文文档](zh-cn/) 8 | -------------------------------------------------------------------------------- /docs/_navbar.md: -------------------------------------------------------------------------------- 1 | * [English](/en/) 2 | * [简体中文](/zh-cn/) 3 | -------------------------------------------------------------------------------- /docs/en/README.md: -------------------------------------------------------------------------------- 1 | 9 | # **React Native Large List V3** 10 | **React Native Large List V3** is the best large list component(iOS & Android)。Its items are all reused, and it is highly performance. 11 | 12 | ### Features 13 | 14 | * Support large data source, highly reused, high performance.Less CPU/Memory usage. 15 | * Cross-platform bounces.(iOS & Android) 16 | * Highly customize Refreshing and Loading.Fully support `react-native-lottie`. More smoothly animation. 17 | * Support header and footer. 18 | * Native onScroll Listener supported. 19 | * Sticky headers supported. 20 | * Support inverted. 21 | * Never blanks. 22 | * Support pagingEnabled (New) 23 | * Big picture or video optimization (New) 24 | 25 | ### What's updated in V3.1 26 | * SpringScrollView bug fix on android 27 | * Support pagingEnabled 28 | * Big picture or video optimization 29 | * Support beginRefresh 30 | * `renderHeader`,`renderIndexPath` Updated. 31 | 32 | ### LargeList 33 | 34 | All the features below are supported on both iOS and Android. 35 | 36 | ##### Sticky section support 37 | 38 |       ![StickySection](../res/StickySection.gif) 39 | 40 | ##### Fully Cross-platform bounces (iOS & Android). 41 | 42 |       ![bounces](../res/bounces.gif) 43 | 44 | ##### Customize refreshing (Support `lottie-react-native` progress with `useNativeDriver`) 45 | 46 |       ![CustomizeRefreshing](../res/CustomizeRefreshing.gif) 47 | 48 | ##### Customize loading (Support `lottie-react-native` progress with `useNativeDriver`) 49 | 50 |       ![CustomizeLoading](../res/CustomizeLoading.gif) 51 | 52 | ##### Slide on both horizontal and vertical directions. 53 | 54 |       ![BothDirections](../res/BothDirections.gif) 55 | 56 | ##### Sticky header support. 57 | 58 |       ![StickyHeader](../res/StickyHeader.gif) 59 | 60 | ##### directionalLockEnabled 61 | 62 |       ![directionalLockEnabled](../res/directionalLockEnabled.gif) 63 | 64 | ##### Support `inverted` 65 | 66 |       ![inverted](../res/inverted.gif) 67 | 68 | ##### Drag to scale header background: renderScaleHeaderBackground 69 | 70 |       ![renderScaleHeaderBackground](../res/renderScaleHeaderBackground.gif) 71 | 72 | ### WaterfallList 73 | 74 | ##### Complex situation 75 | 76 |       ![WaterfallExample](../res/WaterfallExample.png) 77 | 78 | ##### preferColumnWidth 79 | 80 |       ![preferColumnWidth](../res/preferColumnWidth.gif) 81 | 82 | ##### numColumns 83 | 84 |       ![numColumns](../res/numColumns.gif) 85 | 86 | ### StickyForm 87 | 88 | ##### example 89 | 90 |       ![StickyFormExample](../res/StickyFormExample.gif) 91 | -------------------------------------------------------------------------------- /docs/en/V3/BasicUsage.md: -------------------------------------------------------------------------------- 1 | # Simple Usage 2 | 3 | Import: 4 | ```$js 5 | import { LargeList } from "react-native-largelist"; 6 | ``` 7 | 8 | Check weather the installation is correct with the code below: 9 | 10 | ``` 11 | import React from "react"; 12 | import { StyleSheet, Text, View } from "react-native"; 13 | import { LargeList } from "react-native-largelist"; 14 | 15 | export class HeightEqualExample extends React.Component { 16 | _sectionCount = 10; 17 | _rowCount = 10; 18 | 19 | render() { 20 | const data = []; 21 | for (let section = 0; section < this._sectionCount; ++section) { 22 | const sContent = { items: [] }; 23 | for (let row = 0; row < this._rowCount; ++row) { 24 | sContent.items.push(row); 25 | } 26 | data.push(sContent); 27 | } 28 | return ( 29 | 50} 33 | renderSection={this._renderSection} 34 | heightForIndexPath={() => 50} 35 | renderIndexPath={this._renderIndexPath} 36 | /> 37 | ); 38 | } 39 | 40 | _renderSection = (section: number) => { 41 | return ( 42 | 43 | 44 | Section {section} 45 | 46 | 47 | ); 48 | }; 49 | 50 | _renderIndexPath = ({ section: section, row: row }) => { 51 | return ( 52 | 53 | 54 | Section {section} Row {row} 55 | 56 | 57 | 58 | ); 59 | }; 60 | } 61 | 62 | const styles = StyleSheet.create({ 63 | container: { 64 | flex: 1 65 | }, 66 | section: { 67 | flex: 1, 68 | backgroundColor: "gray", 69 | justifyContent: "center", 70 | alignItems: "center" 71 | }, 72 | row: { 73 | flex: 1, 74 | justifyContent: "center", 75 | alignItems: "center" 76 | }, 77 | line: { 78 | position: "absolute", 79 | left: 0, 80 | right: 0, 81 | bottom: 0, 82 | height: 1, 83 | backgroundColor: "#EEE" 84 | } 85 | }); 86 | ``` 87 | 88 | [More Examples](https://github.com/bolan9999/react-native-largelist/tree/master/Examples) 89 | -------------------------------------------------------------------------------- /docs/en/V3/BigMedia.md: -------------------------------------------------------------------------------- 1 | 9 | 10 | # Big Picture or View Optimization 11 | 12 | 17 | ``` 18 | renderIndexPath = (indexPath, mediaWrapperParam)=>{ 19 | return 20 | ()} 23 | loadEndFunc="onLoadEnd"> 24 | 25 | 26 | 27 | } 28 | ``` 29 | Props: 30 | 31 | Props | Type | Default | Description   32 | ---- | ------ | --------- | -------- 33 | mediaWrapperParam | Object | required | Pass the 2nd parameter of the `renderIndexPath`to `MediaWrapper`。 34 | renderLoading | ()=> React.ReactElement <any> | required | Render Element of the Loading indicator. 35 | loadEndFunc | string | required | The complete function name of the Media. For example:`Image from react-native` => `onLoadEnd`, `Video from react-native-video` => `onLoad` 36 | 37 | MediaWrapper's Children must be only one. 38 | 39 | 40 | 完整的示例: [BigMediaExample](https://github.com/bolan9999/react-native-largelist/tree/master/Examples/LargeListExamples/BigMediaExample.js) -------------------------------------------------------------------------------- /docs/en/V3/CustomLoading.md: -------------------------------------------------------------------------------- 1 | # Customize loading 2 | 3 | 在我们自定义上拉加载之前, 我们需要先了解一个上拉加载各个状态: 4 | 5 | Understand the refreshing status before customizing refreshing: 6 | 7 | * "waiting": The content view is not out of the bottom yet. 8 | * "dragging": The content view is out of the bottom but not too more to load. 9 | * "draggingEnough": It is enough to load,but the finger has not touched up, and will load more data at once if touching up. 10 | * "draggingCancel": Drag back after the `draggingEnough` status. 11 | * "loading": Loading data. 12 | * "rebound": The loading has been completed and it is rebounding. 13 | * "allLoaded": Whether the data is all loaded. 14 | 15 | ### Customize 16 | 17 | #### Import 18 | ```$js 19 | import { LoadingFooter } from "react-native-spring-scrollview/LoadingFooter"; 20 | ``` 21 | 22 | #### Extends `LoadingFooter` 23 | ```$js 24 | class MyFooter extends LoadingFooter{} 25 | ``` 26 | 27 | #### Overwrite `render` 28 | ```$js 29 | render() { 30 | return {this.state.status} 31 | } 32 | ``` 33 | 34 | LoadingFooter has these props and states extended from its parent. You can use it directly. 35 | * this.props.maxHeight: The type is `number`, it is the height for the loading footer. 36 | * this.props.offset: The type is `Animated.Value`, Animated value for contentOffset.y of the SpringScrollView 37 | * this.state.status: The type is `FooterStatus`, it is the status of the loading footer. 38 | ```$js 39 | export type FooterStatus = 40 | | "waiting" 41 | | "dragging" 42 | | "draggingEnough" 43 | | "draggingCancel" 44 | | "releaseRebound" 45 | | "loading" 46 | | "rebound" 47 | | "allLoaded"; 48 | ``` 49 | 50 | #### Customize the height of the loading footer 51 | Overwrite the static var `height` to change the height of the loading footer. 52 | ```$js 53 | class MyFooter extends LoadingFooter{ 54 | static height:number = 50; 55 | } 56 | ``` 57 | 58 | #### Select the loading style 59 | 60 | Overwrite the static var `style` to change the style of the loading footer. 61 | ``` 62 | class MyFooter extends LoadingFooter{ 63 | static style:string = "stickyContent"; 64 | } 65 | ``` 66 | 67 | LargeList supports 3 kinds of style for loading footer,default is `stickyContent` : 68 | 69 | style | preview 70 | ---- | ------ 71 | "bottoming" | ![bottoming](../../res/LoadingBottoming.gif) 72 | "stickyScrollView" | ![stickyScrollView](../../res/LoadingStickyScrollView.gif) 73 | "stickyContent" | ![stickyContent](../../res/LoadingStickyContent.gif) 74 | 75 | #### Apply your customize loading footer toLargeList 76 | ```$js 77 | 78 | ``` 79 | 80 | Fully example is here [NormalFooter](https://github.com/bolan9999/react-native-spring-scrollview/blob/master/src/LoadingFooter.js) 81 | 82 | #### Native interpolate animation 83 | 84 | this.props.offset: Native driver animated value for contentOffset.y of the LargeList, you can use it to make a native animation. 85 | 86 | Example: 87 | 88 | ```$js 89 | 104 | ``` 105 | 106 | Fully example is here [NormalFooter](https://github.com/bolan9999/react-native-spring-scrollview/blob/master/src/NormalFooter.js) 107 | 108 | #### Lottie animation support 109 | 110 | ``` 111 | export class CommonLottieFooter extends RefreshHeader { 112 | static height: number = 100; 113 | 114 | render() { 115 | if (this.state.status === "allLoaded") return null; 116 | const { offset, bottomOffset } = this.props; 117 | let progress = offset.interpolate({ 118 | inputRange: [ 119 | bottomOffset + 50, 120 | bottomOffset + 500 121 | ], 122 | outputRange: [0, 1] 123 | }); 124 | if (this.state.status === "loading") { 125 | progress = undefined; 126 | } 127 | return ( 128 | 129 | 137 | 138 | ); 139 | } 140 | } 141 | ``` 142 | Full lottie animation example is here [CommonLottieFooter](https://github.com/bolan9999/react-native-spring-scrollview/blob/master/src/Customize/CommonLottieFooter.js) 143 | 144 | ### Contribute your awesome loading footer 145 | 146 | Fork [react-native-spring-scrollview](https://github.com/bolan9999/react-native-spring-scrollview), make awesome loading footer in the [Customize](https://github.com/bolan9999/react-native-spring-scrollview/tree/master/src/Customize) dir, and pull a request to me. 147 | -------------------------------------------------------------------------------- /docs/en/V3/CustomRefresh.md: -------------------------------------------------------------------------------- 1 | # Customize refreshing 2 | 3 | Understand the refreshing status before customizing refreshing: 4 | 5 | * `waiting`: The content view is not out of the top yet. 6 | * `pulling`: The content view is out of the top but not too more to refresh. 7 | * `pullingEnough`: It is enough to refresh,but the finger has not touched up, and will refresh at once if touching up. 8 | * `pullingCancel`: Drag back after the `pullingEnough` status. 9 | * `refreshing`: Refreshing 10 | * `rebound`: The refreshing has been completed and it is rebounding. 11 | 12 | ### Customize 13 | 14 | #### Import 15 | ```$js 16 | import { RefreshHeader } from "react-native-spring-scrollview/RefreshHeader"; 17 | ``` 18 | 19 | #### Extends `RefreshHeader` 20 | ```$js 21 | class MyHeader extends RefreshHeader{} 22 | ``` 23 | 24 | #### Overwrite `render` 25 | ```$js 26 | render() { 27 | return {this.state.status} 28 | } 29 | ``` 30 | 31 | RefreshHeader has these props and states extended from its parent. You can use it directly. 32 | 33 | * this.props.maxHeight: The type is `number`, it is the height for the refreshing header. 34 | * this.props.offset: The type is `Animated.Value`, Animated value for contentOffset.y of the SpringScrollView 35 | * this.state.status: The type is `HeaderStatus`, it is the status of the refreshing header. 36 | ```$js 37 | export type HeaderStatus = 38 | | "waiting" 39 | | "pulling" 40 | | "pullingEnough" 41 | | "pullingCancel" 42 | | "refreshing" 43 | | "rebound"; 44 | ``` 45 | 46 | #### Customize the height of the refreshing header 47 | 48 | Overwrite the static var `height` to change the height of the refreshing header. 49 | ``` 50 | class MyHeader extends RefreshHeader{ 51 | static height:number = 50; 52 | } 53 | ``` 54 | 55 | #### Select the refreshing style 56 | 57 | Overwrite the static var `style` to change the style of the refreshing header.,default is "stickyContent": 58 | ``` 59 | class MyHeader extends RefreshHeader{ 60 | static style:string = "stickyContent"; 61 | } 62 | ``` 63 | 64 | LargeList supports 3 kinds of style for refreshing header: 65 | 66 | style | preview 67 | ---- | ------ 68 | "topping" | ![topping](../../res/RefreshingTopping.gif) 69 | "stickyScrollView" | ![stickyScrollView](../../res/RefreshingStickyScrollView.gif) 70 | "stickyContent" | ![stickyContent](../../res/RefreshingStickyContent.gif) 71 | 72 | #### Apply your customize refreshing header to LargeList 73 | ```$js 74 | 75 | ``` 76 | 77 | Fully example is here [NormalHeader](https://github.com/bolan9999/react-native-spring-scrollview/blob/master/src/NormalHeader.js) 78 | 79 | #### Native interpolate animation 80 | 81 | this.props.offset: Native driver animated value for contentOffset.y of the LargeList, you can use it to make a native animation. 82 | 83 | Example: 84 | 85 | ```$js 86 | 96 | ``` 97 | 98 | Fully example is here [NormalHeader](https://github.com/bolan9999/react-native-spring-scrollview/blob/master/src/NormalHeader.js) 99 | 100 | #### Lottie animation support 101 | 102 | Example: 103 | ``` 104 | export class CommonLottieHeader extends RefreshHeader { 105 | static height: number = 100; 106 | 107 | render() { 108 | let progress = this.props.offset.interpolate({ 109 | inputRange: [-200, -150, -150, -100, -100, -50], 110 | outputRange: [1, 0, 1, 0, 1, 0] 111 | }); 112 | if (this.state.status === "refreshing") { 113 | progress = undefined; 114 | } 115 | return ( 116 | 117 | 125 | 126 | ); 127 | } 128 | } 129 | ``` 130 | 131 | Full example is here [CommonLottieHeader](https://github.com/bolan9999/react-native-spring-scrollview/blob/master/src/Customize/CommonLottieHeader.js) 132 | 133 | ### Contribute your awesome refreshing headers 134 | 135 | Fork [react-native-spring-scrollview](https://github.com/bolan9999/react-native-spring-scrollview), make awesome refreshing header in the [Customize](https://github.com/bolan9999/react-native-spring-scrollview/tree/master/src/Customize) dir, and pull a request to me. 136 | 137 | -------------------------------------------------------------------------------- /docs/en/V3/GettingStart.md: -------------------------------------------------------------------------------- 1 | 10 | # Getting Started 11 | 12 | ### New installation code 13 | 14 | ``` 15 | yarn add react-native-spring-scrollview react-native-largelist 16 | ``` 17 | RN 0.50-0.59 without pod 18 | ``` 19 | react-native link react-native-spring-scrollview 20 | ``` 21 | RN 0.60+ with pod 22 | ``` 23 | npx pod-install 24 | ``` 25 | It is completed if you do not get an error. But for some reason, you should check your native installation 26 | 27 | ### Check native installation(0.50-0.59) 28 | 29 | ##### iOS 30 | * Make sure `ProjectPath ==> Libraries ==> RNSpringScrollView.xcodeproj` is in your project. 31 | * Make sure `ProjectPath ==> TARGETS ==> BuildPhases ==> Link Binary With Libraries ==> libRNSpringScrollView.a` is linked to your project. 32 | 33 | ##### Android 34 | * Make sure `YourProject/android/settings.gradle` contains the information below 35 | ``` 36 | include ':react-native-spring-scrollview' 37 | project(':react-native-spring-scrollview').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-spring-scrollview/android') 38 | ``` 39 | 40 | * Make sure `YourProject/android/app/build.gradle` contains the information below 41 | ``` 42 | dependencies { 43 | compile project(':react-native-spring-scrollview') 44 | compile fileTree(include: ['*.jar'], dir: 'libs') 45 | compile 'com.android.support:appcompat-v7:26.0.0' 46 | compile 'com.facebook.react:react-native:+' 47 | // From node_modules 48 | } 49 | ``` 50 | 51 | * Make sure `new SpringScrollViewPackage()` is in your `MainApplication.java` 52 | ``` 53 | @Override 54 | protected List getPackages() { 55 | return Arrays.asList( 56 | new MainReactPackage(), 57 | new SpringScrollViewPackage() 58 | ); 59 | } 60 | ``` 61 | 62 | ### iOS common installation problems 63 | 1. Can not find files `RCTXXXX.h`: 64 | 65 | [Click here to find a solution](https://github.com/facebook/react-native/issues/22000#issuecomment-438201084) 66 | 67 | 2. Pod install problem: 68 | 69 | add this to your pod file: 70 | ``` 71 | pod 'RNSpringScrollView', :path => '../node_modules/react-native-spring-scrollview/ios' 72 | ``` 73 | 74 | ### Android common installation problems 75 | 76 | 1. Can not find files `android/drawable/XXXXXX`, '`android/res/XXXXXX`' ... 77 | 78 | Check the compile SDK version is over API 26, or you can modify the version in react-native-spring-scrollview 79 | 80 | Make sure `YourProject/android/app/build.gradle` contains google maven: 81 | ``` 82 | allprojects { 83 | repositories { 84 | mavenLocal() 85 | jcenter() 86 | maven { 87 | url 'https://maven.google.com' 88 | } 89 | maven { 90 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 91 | url "$rootDir/../node_modules/react-native/android" 92 | } 93 | } 94 | } 95 | ``` 96 | -------------------------------------------------------------------------------- /docs/en/V3/KnownIssues.md: -------------------------------------------------------------------------------- 1 | # Known issues 2 | 1. Nested SpringScrollView is not supported now 3 | 2. Sliding on the horizontal direction to edit cell is not supported now 4 | -------------------------------------------------------------------------------- /docs/en/V3/Overview.md: -------------------------------------------------------------------------------- 1 | 9 | # Overview 10 | 11 | LargeList V3 depends on `react-native-spring-scrollview@^2.0.3`, and supports almost all props in SpringScrollView. 12 | 13 | As the same as SpringScrollView,LargeList must have a bounded height in order to work, since they contain many cells children into a bounded container (via a scroll interaction). In order to bound the height of a LargeList, either set the height of the view directly (discouraged) or make sure all parent views have bounded height. LargeList default has a `{flex:1}` style,please be sure its parent has a bounded height. Note that in order to optimize performance, the height of each item and each section must be given. 14 | 15 | ### Basic Props 16 | 17 | Props | Type | Default |  Description   18 | ---- | ------ | --------- | -------- 19 | [...SpringScrollView](https://bolan9999.github.io/react-native-spring-scrollview/#/) | - | - | Support almost all props in SpringScrollView 20 | data | { items: any[] }[] | required | The data source of the large list. The outer array is the number of sections. And the inner array:`items` is the items of the section. 21 | contentStyle | ViewStyle | { height } | The content view style of LargeList. 22 | heightForSection | (section: number) => number | ()=>0 | The height function for every Section 23 | renderSection | (section: number) => React.ReactElement <any> | ()=>null | The render function for every Section 24 | heightForIndexPath | (indexPath: IndexPath) => number | required | The height function for every IndexPath 25 | renderIndexPath | (indexPath: IndexPath) => React.ReactElement <any, , mediaWrapperParam:Object> | required | The render function for every IndexPath, mediaWrapperParam is the parameter of big pic/video optimization. View [Big picture or Video optimization](./BigMedia) 26 | renderHeader | ()=> React.ReactElement <any> | undefined | The render function of largelist header 27 | renderFooter | ()=> React.ReactElement <any> | undefined | The render function of largelist footer 28 | inverted | boolean | false | Inverted the data source, see [ChatExample](https://github.com/bolan9999/react-native-largelist/tree/master/Examples/LargeListExamples/ChatExample.js) for example. 29 | directionalLockEnabled | boolean | false | When true, the SpringScrollView will try to lock to only vertical or horizontal scrolling while dragging. 30 | headerStickyEnabled | boolean | false | Sticky the header of the LargeList on the top. And then sticky Section on the bottom of the header. 31 | renderScaleHeaderBackground | ()=> React.ReactElement <any> | undefined | Render the scale header background when dragging. See [HeightEqualExample](https://github.com/bolan9999/react-native-largelist/tree/master/Examples/LargeListExamples/HeightEqualExample.js) 32 | 33 | ### Simple Usage 34 | 35 | ``` 36 | 50} 40 | renderSection={this._renderSection} 41 | heightForIndexPath={() => 50} 42 | renderIndexPath={this._renderIndexPath} 43 | /> 44 | ``` 45 | 46 | ### Precautions 47 | * LargeList default has a `{flex:1}` style,please be sure its parent has abounded height. 48 | * After V3, LargeList will no longer slice on `renderHeader`,`renderFooter`,`renderIndexPath`. `{flex:1}` is required in `renderIndexPath`. 49 | 50 | -------------------------------------------------------------------------------- /docs/en/V3/Scroll.md: -------------------------------------------------------------------------------- 1 | 9 | # Scroll to 10 | 11 | It is easy to scrollTo: 12 | 13 | ### Firstly,get the reference of the LargeList的 14 | ```$js 15 | (this._list = ref)} /> 16 | ``` 17 | 18 | ### Secondly, call `scrollTo` 19 | ```$js 20 | this._list && this._list.scrollTo({x:0,y:100}).then().catch(); 21 | ``` 22 | ### Available scrolling methods 23 | scrollTo({x:number, y:number}, animated:boolean=true):Promise<void> 24 | 25 | scrollToIndexPath({section:number, row:number}, animated: boolean = true):Promise<void> 26 | 27 | # onScroll listener on Javascript 28 | 29 | ### onScroll : ({nativeEvent:{contentOffset:{x:number, y:number}}})=>any 30 | 31 | ```$js 32 | { 33 | console.log("offset : x=", x, "y=", y); 34 | }/> 35 | ``` 36 | 37 | 注意: 38 | 39 | **Precautions:** 40 | 41 | * The `contentOffset` can be able to out of content view range. 42 | * As the `onScroll` on the official React Native, you can use `Animated.createAnimatedComponent` to support `useNativeDriver`. Or you can use `onNativeContentOffsetExtract` . 43 | * It supports `react-native-reanimated`. 44 | 45 | # Native onScroll listener 46 | 47 | ### onNativeContentOffsetExtract : {x?:Animated.Value, y?:Animated.Value} 48 | 49 | Example: 50 | 51 | ```$js 52 | _nativeOffset = { 53 | y: new Animated.Value(0) 54 | }; 55 | 56 | render(){ 57 | return 58 | } 59 | 60 | ``` 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /docs/en/V3/StickyForm/Overview.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | StickyForm is a form that support sticky header, section on the top. And it will also sticky the first element of `renderHeader`,`renderSection`,`renderIndexPath`,`renderFooter` element on the left of the StickyForm. 3 | 4 | ### 预览 5 | 6 | ![StickyFormExample](../../../res/StickyFormExample.gif) 7 | -------------------------------------------------------------------------------- /docs/en/V3/StickyForm/Usage.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | Props | Type | Default |  Description   4 | ---- | ------ | --------- | -------- 5 | ...LargeList | - | - | Support all props in LargeList 6 | directionalLockEnabled | boolean | true | When true, the StickyForm will try to lock to only vertical or horizontal scrolling while dragging. 7 | headerStickyEnabled | boolean | true | Sticky the header of the StickyForm on the top. And then sticky the Section on the bottom of the header. 8 | 9 | 10 | ### Precautions 11 | StickyForm will sticky the first element of `renderHeader`,`renderSection`,`renderIndexPath`,`renderFooter` element on the left of the StickyForm. See [StickyFormExample](https://github.com/bolan9999/react-native-largelist/blob/master/Examples/StickyFormExamples/StickyFormExample.js) for more information. 12 | 13 | -------------------------------------------------------------------------------- /docs/en/V3/SupportedProps.md: -------------------------------------------------------------------------------- 1 | 9 | # All supported props 10 | 11 | Props | Type | Default |  Description   12 | ---- | ------ | --------- | -------- 13 | [...Animated.View](http://facebook.github.io/react-native/docs/view) | - | - | Support all props of View 14 | bounces | boolean | true | Bounces if the content offset is out of the content view. It won't be bounces on the horizontal direction if the content view is not wider than the wrapper view although bounces is true. But it will on the vertical direction. 15 | scrollEnabled | boolean | true | scrollEnabled 16 | contentStyle | ViewStyle | { height } | The content view style of LargeList. 17 | initialContentOffset | {x:number, y:number} | {x:0,y:0} | initial content offset. Only works when initiation. 18 | showsVerticalScrollIndicator | boolean | true | showsVerticalScrollIndicator 19 | showsHorizontalScrollIndicator | boolean | true | showsHorizontalScrollIndicator(Only works when content view is wider than wrapper view) 20 | directionalLockEnabled | boolean | false | When true, the SpringScrollView will try to lock to only vertical or horizontal scrolling while dragging. 21 | headerStickyEnabled | boolean | false | Sticky the header of the LargeList on the top. And then sticky Section on the bottom of the header. 22 | tapToHideKeyboard | boolean | true | tapToHideKeyboard 23 | data | { items: any[] }[] | required | The data source of largelist 24 | heightForSection | (section: number) => number | ()=>0 | The height function for every Section 25 | renderSection | (section: number) => React.ReactElement <any> | ()=>null | The render function for every Section 26 | heightForIndexPath | (indexPath: IndexPath) => number | required | The height function for every IndexPath 27 | renderIndexPath | (indexPath: IndexPath) => React.ReactElement <any, , mediaWrapperParam:Object> | required | The render function for every IndexPath, mediaWrapperParam is the parameter of big pic/video optimization. View [Big picture or Video optimization](./BigMedia) 28 | renderHeader | ()=> React.ReactElement <any> | undefined | The render function of largelist header 29 | renderFooter | ()=> React.ReactElement <any> | undefined | The render function of largelist footer 30 | inverted | boolean | false | Inverted the data source, see [ChatExample](https://github.com/bolan9999/react-native-largelist/tree/master/Examples/LargeListExamples/ChatExample.js) for example. 31 | onRefresh | ()=>any | undefined | The callback when refreshing. When this props is configured, a refresh header will be add on the top of the LargeList 32 | refreshHeader | [RefreshHeader](https://github.com/bolan9999/react-native-spring-scrollview/blob/master/src/RefreshHeader.js) | NormalHeader | Select a refreshing header , The headers in the Customize dir are all supported 33 | onLoading | ()=>any | undefined | The callback of loading. If set this prop, a loading footer will add to the bottom of the LargeLIst 34 | allLoaded | boolean | false | Whether the data is all loaded. 35 | loadingFooter | [LoadingFooter](https://github.com/bolan9999/react-native-spring-scrollview/blob/master/src/LoadingFooter.js) | NormalFooter | The footer component of loading. If you want to customize loading footer , this will be helpful [Customize Loading] (CustomLoading) 36 | onScroll | ({nativeEvent:{contentOffset:{x, y}}})=>any | undefined | onScroll(on JavaScript) 37 | onNativeContentOffsetExtract | {x?:Animated.Value, y?:Animated.Value} | undefined | Native Animated.View of contentOffset.y of LargeList. 38 | onTouchBegin | ()=>any | undefined | callback when touching begin. 39 | onTouchEnd | ()=>any | undefined | callback when touching end. 40 | onMomentumScrollBegin | ()=>any | undefined | callback when momentum scroll begin. 41 | onMomentumScrollEnd | ()=>any | undefined | callback when momentum scroll end. 42 | textInputRefs | TextInput[] | [] | Keyboard avoiding 43 | tapToHideKeyboard | boolean | true | Tap to hide keyboard. 44 | inputToolBarHeight | number | 44 | inputToolBarHeight 45 | -------------------------------------------------------------------------------- /docs/en/V3/WaterfallList/Overview.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | WaterfallList is a waterfall large list component with high performance. It extends the bounces, refreshing, loading features from SpringScrollView. And also it extends the high performance of LargeList(Never blank). Note that in order to optimize performance, the height of each item must be given. 3 | 4 | ### 预览 5 | ![WaterfallExample](../../../res/WaterfallExample.png) 6 | ![WaterfallExample](../../../res/WaterfallExample.gif) 7 | ![PictureExample](../../../res/PictureExample.gif) 8 | -------------------------------------------------------------------------------- /docs/en/V3/WaterfallList/Usage.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | Props | Type | Default |  Description   4 | ---- | ------ | --------- | -------- 5 | [...SpringScrollView](https://bolan9999.github.io/react-native-spring-scrollview/#/) | - | - | Support almost all props in SpringScrollView 6 | data | any[] | required | The data source of WaterfallList 7 | heightForItem | (item:any,index:number)=> number | required | The function of the height of every Item. 8 | renderItem | (item:any,index:number)=> React.ReactElement<any> | required | The render function of your Item. 9 | preferColumnWidth | number | undefined | The prefer column width of your item.(At least one of `preferColumnWidth` and `numColumns` must be required. ) 10 | numColumns | number | undefined | The column count of WaterfallList. (At least one of `preferColumnWidth` and `numColumns` must be required. ) 11 | renderHeader | ()=> React.ReactElement <any> | undefined | The render function of WaterfallList header 12 | renderFooter | ()=> React.ReactElement <any> | undefined | The render function of WaterfallList footer 13 | 14 | -------------------------------------------------------------------------------- /docs/en/_sidebar.md: -------------------------------------------------------------------------------- 1 | 9 | * [Version 3 (Latest)](en/README) 10 | * [Welcome](en/README) 11 | * [Getting Started](en/V3/GettingStart) 12 | * [Simple Usage](en/V3/BasicUsage) 13 | * LargeList 14 | * [Basic Usage](en/V3/Overview) 15 | * [Pull to refresh](en/V3/Refresh) 16 | * [Drag to Load data](en/V3/Loading) 17 | * [onScroll & Scroll Listener](en/V3/Scroll) 18 | * [Big picture or Video optimization](en/V3/BigMedia) 19 | * [All supported props](en/V3/SupportedProps) 20 | * [Known Issues](en/V3/KnownIssues) 21 | 22 | * WaterfallList 23 | * [Overview](en/V3/WaterfallList/Overview) 24 | * [Usage](en/V3/WaterfallList/Usage) 25 | 26 | * StickyForm 27 | * [Overview](en/V3/StickyForm/Overview) 28 | * [Usage](en/V3/StickyForm/Usage) 29 | 30 | * Precautions 31 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | React Native LargeList 12 | 13 | 15 | 16 | 17 | 19 | 20 | 21 | 23 | 24 | 25 | 27 | 28 | 29 | 34 | 35 | 36 | 37 | 38 |

39 | 52 | 53 | 56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /docs/res/BothDirections.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/BothDirections.gif -------------------------------------------------------------------------------- /docs/res/CustomizeLoading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/CustomizeLoading.gif -------------------------------------------------------------------------------- /docs/res/CustomizeRefreshing.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/CustomizeRefreshing.gif -------------------------------------------------------------------------------- /docs/res/LoadingAndroid.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/LoadingAndroid.gif -------------------------------------------------------------------------------- /docs/res/LoadingBottoming.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/LoadingBottoming.gif -------------------------------------------------------------------------------- /docs/res/LoadingStickyContent.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/LoadingStickyContent.gif -------------------------------------------------------------------------------- /docs/res/LoadingStickyScrollView.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/LoadingStickyScrollView.gif -------------------------------------------------------------------------------- /docs/res/LottieLoading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/LottieLoading.gif -------------------------------------------------------------------------------- /docs/res/LottieRefreshing.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/LottieRefreshing.gif -------------------------------------------------------------------------------- /docs/res/PictureExample.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/PictureExample.gif -------------------------------------------------------------------------------- /docs/res/RefreshAndLoading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/RefreshAndLoading.gif -------------------------------------------------------------------------------- /docs/res/RefreshAndroid.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/RefreshAndroid.gif -------------------------------------------------------------------------------- /docs/res/RefreshingStickyContent.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/RefreshingStickyContent.gif -------------------------------------------------------------------------------- /docs/res/RefreshingStickyScrollView.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/RefreshingStickyScrollView.gif -------------------------------------------------------------------------------- /docs/res/RefreshingTopping.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/RefreshingTopping.gif -------------------------------------------------------------------------------- /docs/res/StickyFormExample.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/StickyFormExample.gif -------------------------------------------------------------------------------- /docs/res/StickyHeader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/StickyHeader.gif -------------------------------------------------------------------------------- /docs/res/StickySection.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/StickySection.gif -------------------------------------------------------------------------------- /docs/res/Update.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/Update.gif -------------------------------------------------------------------------------- /docs/res/WaterfallExample.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/WaterfallExample.gif -------------------------------------------------------------------------------- /docs/res/WaterfallExample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/WaterfallExample.png -------------------------------------------------------------------------------- /docs/res/bounces.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/bounces.gif -------------------------------------------------------------------------------- /docs/res/directionalLockEnabled.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/directionalLockEnabled.gif -------------------------------------------------------------------------------- /docs/res/inverted.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/inverted.gif -------------------------------------------------------------------------------- /docs/res/numColumns.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/numColumns.gif -------------------------------------------------------------------------------- /docs/res/preferColumnWidth.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/preferColumnWidth.gif -------------------------------------------------------------------------------- /docs/res/renderScaleHeaderBackground.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/res/renderScaleHeaderBackground.gif -------------------------------------------------------------------------------- /docs/zh-cn/README.md: -------------------------------------------------------------------------------- 1 | 9 | # **React Native Large List V3** 10 | **React Native Large List V3** 是原生桥接实现的一组高性能弹性大列表组件(iOS & Android)。组件内容高度重用,极大地优化了列表性能。 11 | 12 | ### 功能特性 13 | 14 | * 支持超大数据源,高度重用,极大地优化了性能,滑动更跟手,完全可以媲美原生列表。CPU和内存占用比官方的SectionList明显少很多。 15 | * 跨平台(iOS & Android)的弹性列表,安卓端拥有真正的拖拽感,用户体验更好。(V3解决了V2在某些暴力情况下无法回弹到正确位置的问题) 16 | * 高度自定义的高性能下拉刷新和上拉加载的支持(根本上解决了在某些暴力情况下,由于react-native本身bug偶尔无法回调onRefresh或者onLoading的情况) 全力支持`react-native-lottie`,支持更顺滑地控制动画进度。 17 | * 头部和尾部组件支持 18 | * 支持原生监听滚动,支持高性能滑动动画 19 | * 粘性组头支持 20 | * 支持inverted,适配聊天App 21 | * 永不白板 22 | * 支持pagingEnabled (新特性) 23 | * 大图片大视频优化方案 (新特性) 24 | 25 | ### V3.1更新 26 | * 优化了SpringScrollView在安卓上的流畅性 27 | * 支持pagingEnabled 28 | * 提供一种解决大图片大视频列表的优化方案 29 | * 支持主动刷新beginRefresh 30 | * `renderHeader`,`renderFooter`,`renderIndexPath`不再执行切片操作. 31 | 32 | ### LargeList 33 | 34 | All the features below are supported on both iOS and Android. 35 | 36 | ##### Sticky section support 37 | 38 |       ![StickySection](../res/StickySection.gif) 39 | 40 | ##### Fully Cross-platform bounces (iOS & Android). 41 | 42 |       ![bounces](../res/bounces.gif) 43 | 44 | ##### Customize refreshing (Support `lottie-react-native` progress with `useNativeDriver`) 45 | 46 |       ![CustomizeRefreshing](../res/CustomizeRefreshing.gif) 47 | 48 | ##### Customize loading (Support `lottie-react-native` progress with `useNativeDriver`) 49 | 50 |       ![CustomizeLoading](../res/CustomizeLoading.gif) 51 | 52 | ##### Slide on both horizontal and vertical directions. 53 | 54 |       ![BothDirections](../res/BothDirections.gif) 55 | 56 | ##### Sticky header support. 57 | 58 |       ![StickyHeader](../res/StickyHeader.gif) 59 | 60 | ##### directionalLockEnabled 61 | 62 |       ![directionalLockEnabled](../res/directionalLockEnabled.gif) 63 | 64 | ##### Support `inverted` 65 | 66 |       ![inverted](../res/inverted.gif) 67 | 68 | ##### Drag to scale header background: renderScaleHeaderBackground 69 | 70 |       ![renderScaleHeaderBackground](../res/renderScaleHeaderBackground.gif) 71 | 72 | ### WaterfallList 73 | 74 | ##### Complex situation 75 | 76 |       ![WaterfallExample](../res/WaterfallExample.png) 77 | 78 | ##### preferColumnWidth 79 | 80 |       ![preferColumnWidth](../res/preferColumnWidth.gif) 81 | 82 | ##### numColumns 83 | 84 |       ![numColumns](../res/numColumns.gif) 85 | 86 | ### StickyForm 87 | 88 | ##### example 89 | 90 |       ![StickyFormExample](../res/StickyFormExample.gif) 91 | -------------------------------------------------------------------------------- /docs/zh-cn/V2/BasicControl.md: -------------------------------------------------------------------------------- 1 | # Basic 2 | LargeList depends on [VerticalScrollViewProps](https://bolan9999.github.io/react-native-spring-scrollview), and all the props are supported in [VerticalScrollViewProps](https://bolan9999.github.io/react-native-spring-scrollview) 3 | LargeList supports cross-platform bounces and customizing refreshing and loading more data. But maybe it will a little stuck in some complicated scenarios.If you care this , use NativeLargeList please. 4 | 5 | ### Basic Props 6 | 7 | Props | Type | Default |  Effect   8 | ---- | ------ | --------- | -------- 9 | ...[VerticalScrollViewProps](https://bolan9999.github.io/react-native-spring-scrollview) | - | - | All props of VerticalScrollView 10 | data | { items: any[] }[] | required | The data source of largelist 11 | heightForSection | (section: number) => number | ()=>0 | The height function for every Section 12 | renderSection | (section: number) => React.ReactElement <any> | ()=>null | The render function for every Section 13 | heightForIndexPath | (indexPath: IndexPath) => number | required | The height function for every IndexPath 14 | renderIndexPath | (indexPath: IndexPath) => React.ReactElement <any> | required | The render function for every IndexPath 15 | renderHeader | ()=> React.ReactElement <any> | undefined | The render function of largelist header 16 | renderFooter | ()=> React.ReactElement <any> | undefined | The render function of largelist footer 17 | 18 | ### Usage 19 | 20 | ```$js 21 | 50} 25 | renderSection={this._renderSection} 26 | heightForIndexPath={() => 50} 27 | renderIndexPath={this._renderIndexPath} 28 | /> 29 | ``` 30 | 31 | 32 | ### Precautions 33 | 34 | 1. LargeList's height can not be propped up from its children, you should figure it out or use `flex` from a bounded height parent. 35 | 36 | 2. The parent node's width and height of `renderSection` and `renderIndexPath` is bounded. You can use `Flex`. 37 | Conversely, The parent node's width and height of `renderHeader` and `renderFooter` is not bounded. Children must prop up parent node. 38 | -------------------------------------------------------------------------------- /docs/zh-cn/V2/CustomLoading.md: -------------------------------------------------------------------------------- 1 | # 自定义上拉加载 2 | 3 | 在我们自定义上拉加载之前, 我们需要先了解一个上拉加载各个状态: 4 | 5 | * "waiting": 准备状态:视图还没有碰边 6 | * "dragging": 上拉状态:视图已经碰到边缘,但是还没有达到组件的高度,此时松手不具备加载的条件 7 | * "draggingEnough": 上拉足够态:视图已经达到组件的高度,但是用户还没有松手,松手即可进入加载态 8 | * "draggingCancel": 上拉取消态: 当用户上拉经历过上拉足够态,但是又往下拉,达不到加载的高度,则进入此状态,如果用户不松手,重新上拉可再次进入上拉足够态 9 | * "loading": 加载态:onLoading,此时正在加载中 10 | * "cancelLoading": 取消加载态: 在数据加载过程中,如果用户下拉,则会进入此状态 11 | * "rebound": 回弹态: 已经加载完成,正在往回弹的状态 12 | * "allLoaded": 数据加载完成态,此状态下不会触发刷新,该状态由allLoaded属性控制 13 | 14 | ### 流程 15 | 16 | ![LoadingProcess](./res/LoadingProcess.png) 17 | 18 | ### 自定义 19 | 20 | #### 导入 21 | ```$js 22 | import { LoadingFooter } from "react-native-spring-scrollview/LoadingFooter"; 23 | ``` 24 | 25 | #### 继承LoadingFooter 26 | ```$js 27 | class MyFooter extends LoadingFooter{} 28 | ``` 29 | 30 | #### 重写render 31 | ```$js 32 | render() { 33 | return {this.state.status} 34 | } 35 | ``` 36 | 37 | LoadingFooter自带有两个Props, 和一个状态status,在子类里面可以直接使用 38 | ```$js 39 | export type FooterStatus = 40 | | "waiting" 41 | | "dragging" 42 | | "draggingEnough" 43 | | "draggingCancel" 44 | | "releaseRebound" 45 | | "loading" 46 | | "cancelLoading" 47 | | "rebound" 48 | | "allLoaded"; 49 | 50 | interface FooterPropType { 51 | offset?: Animated.Value, 52 | maxHeight?: number 53 | } 54 | 55 | interface FooterStateType { 56 | status?: FooterStatus 57 | } 58 | ``` 59 | 60 | * this.props.maxHeight: 加载组件的高度 61 | * this.props.offset: 表示当前的Footer偏移量动画值,取值范围是[-this.props.maxHeight, 0] 62 | * this.state.status: 表示当前加载组件正处在的状态 63 | 64 | 65 | #### 将自定义的加载组件应用到LargeList 66 | ```$js 67 | 68 | ``` 69 | 70 | 完整的示例可以查看[NormalFooter](https://github.com/bolan9999/react-native-spring-scrollview/blob/master/src/LoadingFooter.js) 71 | 72 | ### 性能优化 73 | 74 | #### 避免无用的状态改变带来的无用更新 75 | 你可以通过重写onStateChange(oldStatus: HeaderStatus, newStatus: HeaderStatus)来阻止不需要的状态更新带来的re-render 76 | 77 | 举个例子,如果你只需要区分正在加载和没有加载两种状态,那么你可以像下面这样优化它 78 | ```$js 79 | onStateChange(oldStatus: HeaderStatus, newStatus: HeaderStatus) { 80 | if (oldStatus === "loading" || newStatus==="loading") { 81 | this.setState({status:newStatus}); 82 | } 83 | } 84 | ``` 85 | 86 | 除此之外,加载控件应当设计得足够简单(DOM节点数量不能太多,太多会造成卡顿) 87 | 88 | #### 渐变动画 89 | 90 | this.props.offset: 表示当前的Header偏移量动画值,取值范围是[ -this.props.maxHeight,0 ], 你可以使用这个值来自定义你的动画: 91 | 92 | 举个例子,如果你有个箭头图标,希望在上拉过程中旋转角度,当到达加载状态的时候,完全反转角度,那么你可以这样写 93 | 94 | ```$js 95 | return ( 96 | 109 | ); 110 | ``` 111 | 112 | 完整的示例可以查看[NormalFooter](https://github.com/bolan9999/react-native-spring-scrollview/blob/master/src/NormalFooter.js) 113 | 114 | ### 贡献您的自定义上拉加载组件 115 | 116 | 欢迎Fork react-native-spring-scrollview ,添加您精心制作的LoadingFooter, 提交Pull Request 合并到master,给其他人使用。 117 | -------------------------------------------------------------------------------- /docs/zh-cn/V2/CustomRefresh.md: -------------------------------------------------------------------------------- 1 | # 自定义下拉刷新 2 | 3 | 在我们自定义下拉刷新之前, 我们需要先了解一个下拉刷新各个状态: 4 | 5 | * "waiting": 准备状态:视图还没有碰边 6 | * "pulling": 下拉状态:视图已经碰到边缘,但是还没有达到组件的高度,此时松手不具备刷新的条件 7 | * "pullingEnough": 下拉足够态:视图已经达到组件的高度,但是用户还没有松手,松手即可进入刷新态 8 | * "pullingCancel": 下拉取消态: 当用户下拉经历过下拉足够态,但是又往上拉,达不到刷新的高度,则进入此状态,如果用户不松手,重新下拉可再次进入下拉足够态 9 | * "refreshing": 刷新态:已经触发onRefresh,此时正在刷新中 10 | * "cancelRefresh": 取消刷新态: 在数据刷新过程中,如果用户上拉,则会进入此状态 11 | * "rebound": 回弹态: 已经刷新完成,正在往回弹的状态 12 | 13 | ### 流程 14 | 15 | ![RefreshProcess](./res/RefreshProcess.png) 16 | 17 | ### 自定义 18 | 19 | #### 导入 20 | ```$js 21 | import { RefreshHeader } from "react-native-spring-scrollview/RefreshHeader"; 22 | ``` 23 | 24 | #### 继承RefreshHeader 25 | ```$js 26 | class MyHeader extends RefreshHeader{} 27 | ``` 28 | 29 | #### 重写render 30 | ```$js 31 | render() { 32 | return {this.state.status} 33 | } 34 | ``` 35 | 36 | RefreshHeader自带有两个Props, 和一个状态status,在子类里面可以直接使用 37 | ```$js 38 | interface HeaderPropType { 39 | offset?: Animated.Value, 40 | maxHeight?:number 41 | } 42 | 43 | export type HeaderStatus = 44 | | "waiting" 45 | | "pulling" 46 | | "pullingEnough" 47 | | "pullingCancel" 48 | | "refreshing" 49 | | "cancelRefresh" 50 | | "rebound"; 51 | 52 | interface HeaderStateType { 53 | status?: HeaderStatus 54 | } 55 | ``` 56 | 57 | * this.props.maxHeight: 刷新组件的高度 58 | * this.props.offset: 表示当前的Header偏移量动画值,取值范围是[0, this.props.maxHeight] 59 | * this.state.status: 表示当前刷新组件正处在的状态 60 | 61 | 62 | #### 将自定义的刷新组件应用到LargeList 63 | ```$js 64 | 65 | ``` 66 | 67 | 完整的示例可以查看[NormalHeader](https://github.com/bolan9999/react-native-spring-scrollview/blob/master/src/NormalHeader.js) 68 | 69 | ### 性能优化 70 | 71 | #### 避免无用的状态改变带来的无用更新 72 | 你可以通过重写onStateChange(oldStatus: HeaderStatus, newStatus: HeaderStatus)来阻止不需要的状态更新带来的re-render 73 | 74 | 举个例子,如果你只需要区分正在刷新和没有刷新两种状态,那么你可以像下面这样优化它 75 | ```$js 76 | onStateChange(oldStatus: HeaderStatus, newStatus: HeaderStatus) { 77 | if (oldStatus === "refreshing" || newStatus==="refreshing") { 78 | this.setState({status:newStatus}); 79 | } 80 | } 81 | ``` 82 | 83 | 除此之外,刷新控件应当设计得足够简单(DOM节点数量不能太多,太多会造成卡顿) 84 | 85 | #### 渐变动画 86 | 87 | this.props.offset: 表示当前的Header偏移量动画值,取值范围是[0, this.props.maxHeight], 你可以使用这个值来自定义你的动画: 88 | 89 | 举个例子,如果你有个箭头图标,希望在下拉过程中旋转角度,当到达刷新状态的时候,完全反转角度,那么你可以这样写 90 | 91 | ```$js 92 | return ( 93 | 106 | ); 107 | ``` 108 | 109 | 完整的示例可以查看[NormalHeader](https://github.com/bolan9999/react-native-spring-scrollview/blob/master/src/NormalHeader.js) 110 | 111 | ### 贡献您的自定义下拉刷新组件 112 | 113 | 欢迎Fork react-native-spring-scrollview ,添加您精心制作的RefreshHeader, 提交Pull Request 合并到master,给其他人使用。 114 | 115 | -------------------------------------------------------------------------------- /docs/zh-cn/V2/GettingStart.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | This library offers two components: NativeLargeList depends on [ScrollView](http://facebook.github.io/react-native/docs/scrollview) and it does not need to install any other library. And LargeList depends on [react-native-gesture-handler](https://github.com/kmagiera/react-native-gesture-handler), and you should install it first if you want to use LargeList. 4 | 5 | ### 1. Install[react-native-gesture-handler](https://github.com/kmagiera/react-native-gesture-handler) and [react-native-spring-scrollview](https://github.com/bolan9999/react-native-spring-scrollview) (optional) 6 | If you use NativeLargeList only(no LargeList), you can skip this step. 7 | 8 | Install code: 9 | ```$node 10 | yarn add react-native-gesture-handler react-native-spring-scrollview 11 | react-native link react-native-gesture-handler 12 | ``` 13 | Wrapper your Screen Component like this: 14 | ```$js 15 | import { gestureHandlerRootHOC } from 'react-native-gesture-handler' 16 | 17 | class YourScreen extends React.Component{ 18 | //... 19 | }; 20 | 21 | export const YourScreenWrapper = gestureHandlerRootHOC(YourScreen); 22 | ``` 23 | Use `YourScreenWrapper` instead of `YourScreen` in any places. 24 | 25 | [react-native-gesture-handler](https://github.com/kmagiera/react-native-gesture-handler)has been successfully installed. 26 | 27 | ### 2. Install [react-native-largelist](https://github.com/bolan9999/react-native-largelist) 28 | 29 | Use this npm command to install react-native-largelist v2. 30 | 31 | ```$node 32 | yarn add react-native-largelist-v2 33 | ``` 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /docs/zh-cn/V2/Loading.md: -------------------------------------------------------------------------------- 1 | # 上拉加载 2 | 3 | ### 预览 4 | ![Preview](./res/LoadingAndroid.gif) 5 | ![Preview](./res/LoadingIOS.gif) 6 | 7 | ### 代码 8 | 9 | 导入 10 | 11 | ```$js 12 | import { LargeList } from "react-native-largelist-v2"; 13 | import { NormalFooter } from "react-native-spring-scrollview/NormalFooter"; 14 | ``` 15 | 16 | 使用LargeList可以非常简单地实现上拉加载的功能, 本库默认提供了一个NormalFooter类供用户使用 17 | 18 | ```$js 19 | (this._scrollView = ref)} 21 | style={styles.container} 22 | loadingFooterHeight={60} 23 | loadingFooter={NormalFooter} 24 | allLoaded={false} 25 | onLoading={()=>{ 26 | this._scrollView.beginLoading(); 27 | setTimeOut(()=>{ 28 | this._scrollView.endLoading(); 29 | setTimeOut(()=>this.setState({prop:"your changed props"})); 30 | },2000); 31 | } 32 | onCancelLoading={()=>{ 33 | console.log("当上拉加载,但是用户主动回拉取消时回调"); 34 | } 35 | /> 36 | ``` 37 | 38 | 39 | ### 属性 40 | 41 | #### loadingFooterHeight 42 | 43 | 类型:number 44 | 45 | 默认值: 80 46 | 47 | 描述:上拉加载组件的高度 48 | 49 | #### loadingFooter 50 | 51 | 类型:LoadingFooter 52 | 53 | 默认值: undefined 54 | 55 | 描述:上拉加载组件,用户如果不希望自定义,则可以使用NormalFooter,如果需要高度自定义,请参看[自定义上拉加载](CustomLoading) 56 | 57 | #### onLoading 58 | 59 | 类型:()=>any 60 | 61 | 默认值:()=>null 62 | 63 | 描述:上拉加载的回调函数 64 | 65 | #### onCancelLoading 66 | 67 | 类型:()=>any 68 | 69 | 默认值:()=>null 70 | 71 | 描述:触发上拉加载回调以后,在加载的过程中,用户可以回拉取消加载,如果你希望在此回调,则可以在此做您的操作。 72 | 73 | ### allLoaded 74 | 75 | 类型:boolean 76 | 77 | 默认值: false 78 | 79 | 描述:数据是否加载完成。 80 | 81 | ### 方法 82 | 83 | #### beginLoading() 84 | 85 | 开始加载,弹出(或回弹)加载组件 86 | 87 | ### endLoading(rebound: boolean = false) 88 | 89 | 结束加载,rebound表示是否需要回弹关闭加载组件,如果你的数据是增加了,那么这个属性就可以使用默认的。 在onLoading完成数据请求以后,我们建议您先使用此方法开启结束动画,再setTimeout更新内容,这样在加载过程中,动画更流畅 90 | 91 | -------------------------------------------------------------------------------- /docs/zh-cn/V2/NativeBasicControl.md: -------------------------------------------------------------------------------- 1 | # Basic 2 | 3 | NativeLargeList has a very high performance. Theoretically speaking,it will never disappear blanks. But it does not support cross-platform bounces and customizing refreshing and loading more data. 4 | 5 | ### Basic Props 6 | 7 | Props | Type | Default |  Effect   8 | ---- | ------ | --------- | -------- 9 | ...[ScrollViewProps](http://facebook.github.io/react-native/docs/scrollview) | - | - | All props of ScrollView 10 | data | { items: any[] }[] | required | The data source of largelist 11 | heightForSection | (section: number) => number | ()=>0 | The height function for every Section 12 | renderSection | (section: number) => React.ReactElement <any> | ()=>null | The render function for every Section 13 | heightForIndexPath | (indexPath: IndexPath) => number | required | The height function for every IndexPath 14 | renderIndexPath | (indexPath: IndexPath) => React.ReactElement <any> | required | The render function for every IndexPath 15 | renderHeader | ()=> React.ReactElement <any> | undefined | The render function of largelist header 16 | renderFooter | ()=> React.ReactElement <any> | undefined | The render function of largelist footer 17 | 18 | ### Usage 19 | 20 | ```$js 21 | 50} 25 | renderSection={this._renderSection} 26 | heightForIndexPath={() => 50} 27 | renderIndexPath={this._renderIndexPath} 28 | /> 29 | ``` 30 | 31 | 32 | ### Precautions 33 | 1. NativeLargeList's height can not be propped up from its children, you should figure it out or use `flex` from a bounded height parent. 34 | 35 | 2. The parent node's width and height of `renderSection` and `renderIndexPath` is bounded. You can use `Flex`. 36 | Conversely, The parent node's width and height of `renderHeader` and `renderFooter` is not bounded. Children must prop up parent node. 37 | -------------------------------------------------------------------------------- /docs/zh-cn/V2/README.md: -------------------------------------------------------------------------------- 1 | # react-native-largelist 2 | 3 | **React-native-largelist** is a high performance large list component for React-Native. (iOS & Android) Now V2 is available. V1 is [here](https://github.com/bolan9999/react-native-largelist/tree/V1) 4 | 5 | ## Features 6 | 7 | * Large data source list component, items reused by group, Less CPU/Memory usage. 8 | * Fully Cross-platform bounces (iOS & Android). 9 | * Customize Refreshing and Loading. 10 | * Header and Footer support. 11 | * ScrollToIndex support. 12 | * Sticky Section support. 13 | * No blanks(theoretically speaking). 14 | 15 | ## Preview 16 | ![Preview](./res/Update.gif) 17 | ![Preview](./res/RefreshAndLoading.gif) 18 | 19 | ## License 20 | 21 | react-native-largelist is released under the MIT license. See LICENSE for details. 22 | 23 | -------------------------------------------------------------------------------- /docs/zh-cn/V2/Refresh.md: -------------------------------------------------------------------------------- 1 | # Pull To Refresh 2 | 3 | ### Preview 4 | ![Preview](./res/RefreshAndroid.gif) 5 | ![Preview](./res/RefreshIOS.gif) 6 | 7 | ### Code 8 | 9 | Import 10 | 11 | ```$js 12 | import { LargeList } from "react-native-largelist-v2"; 13 | import { NormalHeader } from "react-native-spring-scrollview/NormalHeader"; 14 | ``` 15 | 16 | It is easy to pull to refresh, (https://bolan9999.github.io/react-native-spring-scrollview) is a dependence of this component. It provide `NormalHeader` to you to implement pull-down to refresh easily. 17 | 18 | ```$js 19 | (this._largeList = ref)} 21 | style={styles.container} 22 | data={this.state.data} 23 | heightForSection={() => 40} 24 | renderSection={this._renderSection} 25 | heightForIndexPath={() => 60} 26 | renderIndexPath={this._renderItem} 27 | refreshHeaderHeight={60} 28 | refreshHeader={NormalHeader} 29 | onRefresh={this._onRefresh} 30 | loadingFooterHeight={60} 31 | loadingFooter={NormalFooter} 32 | onLoading={this._onLoading} 33 | allLoaded={this.state.allLoaded} 34 | renderHeader={this._renderHeader} 35 | renderFooter={this._renderFooter} 36 | /> 37 | 38 | //... 39 | _onRefresh = () => { 40 | this._largeList.beginRefresh(); 41 | setTimeout(() => { 42 | this._largeList.endRefresh(); 43 | this._index = 0; 44 | this.setState({ 45 | data: [contacts[this._index]], 46 | allLoaded: this._index > 2 47 | }); 48 | }, 2000); 49 | }; 50 | 51 | //... 52 | _onLoading = () => { 53 | this._largeList.beginLoading(); 54 | setTimeout(() => { 55 | this._largeList.endLoading(); 56 | this.setState(p => ({ 57 | data: p.data.concat(contacts[++this._index]), 58 | allLoaded: this._index > 2 59 | })); 60 | }, 2000); 61 | }; 62 | ``` 63 | 64 | 65 | ### Props 66 | 67 | #### refreshHeaderHeight 68 | 69 | Type:number 70 | 71 | Default: 80 72 | 73 | Effect:The height of refresh component. 74 | 75 | #### refreshHeader 76 | 77 | Type:RefreshHeader 78 | 79 | Default: undefined 80 | 81 | Effect:You can use NormalHeader directly to implement pull-down to refresh quickly. 82 | [Customize Refreshing](CustomRefresh) is here 83 | 84 | #### onRefresh 85 | 86 | Type:()=>any 87 | 88 | Default:()=>null 89 | 90 | Effect:The call back of Refresh 91 | 92 | #### onCancelRefresh 93 | 94 | Type:()=>any 95 | 96 | Default:()=>null 97 | 98 | Effect:The call back of canceling refreshing 99 | 100 | ### Method 101 | 102 | #### beginRefresh() 103 | 104 | Begin to refresh, it will pop refresh component. 105 | 106 | ### endRefresh() 107 | 108 | End refreshing. Call endRefresh first, and then update your component is a better way. 109 | 110 | -------------------------------------------------------------------------------- /docs/zh-cn/V2/Scroll.md: -------------------------------------------------------------------------------- 1 | # 滑动 2 | 3 | 要使用代码滑动到指定位置,非常简单: 4 | 5 | ### 第一步,获取VerticalScrollView的引用 6 | ```$js 7 | (this._scrollView = ref)} /> 8 | ``` 9 | 10 | ### 第二步,使用scrollTo方法 11 | ```$js 12 | this._scrollView && this._scrollView.scrollTo({x:0,y:100}); 13 | ``` 14 | 15 | scrollTo({x:number, y:number}, animated=true):Promise<void> 16 | 17 | 滑动到指定的偏移,注意: 18 | 19 | * x坐标目前没有任何效果 20 | 21 | * 如果超出 VerticalScrollView的内容范围,将自动矫正到极端位置 22 | 23 | 24 | # 监听滑动 25 | 26 | ### onScroll : ({x:number, y:number})=>any 27 | 28 | ```$js 29 | { 30 | console.log("offset : x=", x, "y=", y); 31 | } /> 32 | ``` 33 | 34 | 注意: 35 | 36 | * y值是有可能超出内容范围之外的 37 | * 遮挡键盘的偏移处理当中,该函数不会回调 38 | * 如果需要提高性能,使用原生动画驱动,则可以考虑使用下面的方法 39 | 40 | ### onTouchBegin : ()=>any 41 | 手指按下时回调 42 | ```$js 43 | { 44 | console.log("onTouchBegin"); 45 | } /> 46 | ``` 47 | 48 | ### onTouchEnd : ()=>any 49 | 手指按下时回调 50 | ```$js 51 | { 52 | console.log("onTouchEnd"); 53 | } /> 54 | ``` 55 | 56 | ### onMomentumScrollStart : ()=>any 57 | 手指按下时回调 58 | ```$js 59 | { 60 | console.log("onMomentumScrollStart"); 61 | } /> 62 | ``` 63 | 64 | ### onMomentumScrollEnd : ()=>any 65 | 手指按下时回调 66 | ```$js 67 | { 68 | console.log("onMomentumScrollEnd"); 69 | } /> 70 | ``` 71 | 72 | # 监听原生偏移值 73 | 74 | ### getNativeOffset : (offset: Animated.Value) => any 75 | 76 | 获得监听滑动偏移并支持原生动画的动画值(该值是合成值,不可监听,不可修改,只能用于原生动画,键盘遮挡的偏移动画不会触发此值更改) 77 | 78 | ```$js 79 | { 80 | //可以将此offset做任何插值运算并应用到你的组件里面,这样将在原生动画中驱动动画 81 | } /> 82 | ``` 83 | 84 | 85 | -------------------------------------------------------------------------------- /docs/zh-cn/V2/Update.md: -------------------------------------------------------------------------------- 1 | # Update Data Source 2 | 3 | Instead of calling `reloadData` in [V1](https://github.com/bolan9999/react-native-largelist/tree/V1), you can update large list directly via `setState` 4 | -------------------------------------------------------------------------------- /docs/zh-cn/V2/Usage.md: -------------------------------------------------------------------------------- 1 | # Sample Usage 2 | 3 | Import: 4 | ```$js 5 | import { LargeList } from "react-native-largelist-v2"; 6 | ``` 7 | 8 | Check your installation 9 | 10 | ```$js 11 | import React from "react"; 12 | import { StyleSheet, Text, View } from "react-native"; 13 | import { LargeList } from "react-native-largelist-v2"; 14 | 15 | export class HeightEqualExample extends React.Component { 16 | _sectionCount = 10; 17 | _rowCount = 10; 18 | 19 | render() { 20 | const data = []; 21 | for (let section = 0; section < this._sectionCount; ++section) { 22 | const sContent = { items: [] }; 23 | for (let row = 0; row < this._rowCount; ++row) { 24 | sContent.items.push(row); 25 | } 26 | data.push(sContent); 27 | } 28 | return ( 29 | 50} 33 | renderSection={this._renderSection} 34 | heightForIndexPath={() => 50} 35 | renderIndexPath={this._renderIndexPath} 36 | /> 37 | ); 38 | } 39 | 40 | _renderSection = (section: number) => { 41 | return ( 42 | 43 | 44 | Section {section} 45 | 46 | 47 | ); 48 | }; 49 | 50 | _renderIndexPath = ({ section: section, row: row }) => { 51 | return ( 52 | 53 | 54 | Section {section} Row {row} 55 | 56 | 57 | 58 | ); 59 | }; 60 | } 61 | 62 | const styles = StyleSheet.create({ 63 | container: { 64 | flex: 1 65 | }, 66 | section: { 67 | flex: 1, 68 | backgroundColor: "gray", 69 | justifyContent: "center", 70 | alignItems: "center" 71 | }, 72 | row: { 73 | flex: 1, 74 | justifyContent: "center", 75 | alignItems: "center" 76 | }, 77 | line: { 78 | position: "absolute", 79 | left: 0, 80 | right: 0, 81 | bottom: 0, 82 | height: 1, 83 | backgroundColor: "#EEE" 84 | } 85 | }); 86 | ``` 87 | 88 | 89 | [More Examples](https://github.com/bolan9999/react-native-largelist/tree/master/Examples) 90 | -------------------------------------------------------------------------------- /docs/zh-cn/V2/res/LoadingAndroid.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/zh-cn/V2/res/LoadingAndroid.gif -------------------------------------------------------------------------------- /docs/zh-cn/V2/res/LoadingIOS.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/zh-cn/V2/res/LoadingIOS.gif -------------------------------------------------------------------------------- /docs/zh-cn/V2/res/LoadingProcess.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/zh-cn/V2/res/LoadingProcess.png -------------------------------------------------------------------------------- /docs/zh-cn/V2/res/RefreshAndLoading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/zh-cn/V2/res/RefreshAndLoading.gif -------------------------------------------------------------------------------- /docs/zh-cn/V2/res/RefreshAndroid.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/zh-cn/V2/res/RefreshAndroid.gif -------------------------------------------------------------------------------- /docs/zh-cn/V2/res/RefreshIOS.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/zh-cn/V2/res/RefreshIOS.gif -------------------------------------------------------------------------------- /docs/zh-cn/V2/res/RefreshProcess.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/zh-cn/V2/res/RefreshProcess.png -------------------------------------------------------------------------------- /docs/zh-cn/V2/res/Update.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/zh-cn/V2/res/Update.gif -------------------------------------------------------------------------------- /docs/zh-cn/V2/res/list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/docs/zh-cn/V2/res/list.png -------------------------------------------------------------------------------- /docs/zh-cn/V3/BasicUsage.md: -------------------------------------------------------------------------------- 1 | 9 | # 简单使用 10 | 11 | 导入: 12 | ```$js 13 | import { LargeList } from "react-native-largelist"; 14 | ``` 15 | 16 | 使用下面的代码检查您的安装是否正确: 17 | 18 | ``` 19 | import React from "react"; 20 | import { StyleSheet, Text, View } from "react-native"; 21 | import { LargeList } from "react-native-largelist"; 22 | 23 | export class HeightEqualExample extends React.Component { 24 | _sectionCount = 10; 25 | _rowCount = 10; 26 | 27 | render() { 28 | const data = []; 29 | for (let section = 0; section < this._sectionCount; ++section) { 30 | const sContent = { items: [] }; 31 | for (let row = 0; row < this._rowCount; ++row) { 32 | sContent.items.push(row); 33 | } 34 | data.push(sContent); 35 | } 36 | return ( 37 | 50} 41 | renderSection={this._renderSection} 42 | heightForIndexPath={() => 50} 43 | renderIndexPath={this._renderIndexPath} 44 | /> 45 | ); 46 | } 47 | 48 | _renderSection = (section: number) => { 49 | return ( 50 | 51 | 52 | Section {section} 53 | 54 | 55 | ); 56 | }; 57 | 58 | _renderIndexPath = ({ section: section, row: row }) => { 59 | return ( 60 | 61 | 62 | Section {section} Row {row} 63 | 64 | 65 | 66 | ); 67 | }; 68 | } 69 | 70 | const styles = StyleSheet.create({ 71 | container: { 72 | flex: 1 73 | }, 74 | section: { 75 | flex: 1, 76 | backgroundColor: "gray", 77 | justifyContent: "center", 78 | alignItems: "center" 79 | }, 80 | row: { 81 | flex: 1, 82 | justifyContent: "center", 83 | alignItems: "center" 84 | }, 85 | line: { 86 | position: "absolute", 87 | left: 0, 88 | right: 0, 89 | bottom: 0, 90 | height: 1, 91 | backgroundColor: "#EEE" 92 | } 93 | }); 94 | ``` 95 | 96 | [更多示例](https://github.com/bolan9999/react-native-largelist/tree/master/Examples) 97 | -------------------------------------------------------------------------------- /docs/zh-cn/V3/BigMedia.md: -------------------------------------------------------------------------------- 1 | 9 | 10 | # 大图片视频列表优化 11 | 12 | 当使用LargeList时,由于大图片或者视频更新较慢,就会出现旧的图片变成新的图片的过程,本节讲解如何添加一个Loading图片覆盖在上面,让用户无法看到还没更新的旧图片. 13 | 14 | 请注意:这种优化只能在等高或者大致一致时才完美,如果图片大小不一,这种优化也会看到Loading图标有些错乱的情况。具体取决于您的图片大小差异到底有多大。 15 | 16 | 只需要在`renderIndexPath`上让你的大图片包含在`MediaWrapper`即可: 17 | ``` 18 | renderIndexPath = (indexPath, mediaWrapperParam)=>{ 19 | return 20 | ()} 23 | loadEndFunc="onLoadEnd"> 24 | 25 | 26 | 27 | } 28 | ``` 29 | 属性说明: 30 | 31 | 属性 | 类型 | 默认值 |  描述   32 | ---- | ------ | --------- | -------- 33 | mediaWrapperParam | Object | 必须 | 将renderIndexPath的第二个参数传给MediaWrapper即可。 34 | renderLoading | ()=> React.ReactElement <any> | 必须 | 函数,用以挡住图片或视频的Loading图标 35 | loadEndFunc | string | 必须 | MediaWrapper的子元素可以是`Image`,也可以是`Video`, 但是你需要指定其加载完成的函数名称,这样才能在加载完成时关闭Loading遮挡。常用的有:`Image from react-native` => `onLoadEnd`, `Video from react-native-video` => `onLoad` 36 | 37 | 38 | 完整的示例: [BigMediaExample](https://github.com/bolan9999/react-native-largelist/tree/master/Examples/LargeListExamples/BigMediaExample.js) -------------------------------------------------------------------------------- /docs/zh-cn/V3/GettingStart.md: -------------------------------------------------------------------------------- 1 | 9 | # 快速接入 10 | 11 | ### 全新安装命令 12 | ``` 13 | yarn add react-native-spring-scrollview react-native-largelist 14 | ``` 15 | RN 0.50-0.59 without pod 16 | ``` 17 | react-native link react-native-spring-scrollview 18 | ``` 19 | RN 0.60+ with pod 20 | ``` 21 | npx pod-install 22 | ``` 23 | 24 | 如果没有异常情况,原生端就已经安装好了。为了稳妥起见,您还是应该手动检查原生端的配置是否正确 25 | 26 | ### 检查原生端是否链接正确(0.50-0.59) 27 | 28 | ##### iOS 29 | * 检查 `您的项目 ==> Libraries ==> RNSpringScrollView.xcodeproj` 是否已添加到您的项目中 30 | * 检查 `您的项目设置 ==> TARGETS ==> BuildPhases ==> Link Binary With Libraries ==> libRNSpringScrollView.a` 31 | 是否链接到您的项目中 32 | 33 | ##### Android 34 | * 检查`YourProject/android/settings.gradle`是否包含了如下信息 35 | ``` 36 | include ':react-native-spring-scrollview' 37 | project(':react-native-spring-scrollview').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-spring-scrollview/android') 38 | ``` 39 | 40 | * 检查`YourProject/android/app/build.gradle`是否包含了以下信息 41 | ``` 42 | dependencies { 43 | compile project(':react-native-spring-scrollview') 44 | compile fileTree(include: ['*.jar'], dir: 'libs') 45 | compile 'com.android.support:appcompat-v7:26.0.0' 46 | compile 'com.facebook.react:react-native:+' 47 | // From node_modules 48 | } 49 | ``` 50 | 51 | * 检查'MainApplication.java'是否加入了`new SpringScrollViewPackage()` 52 | ``` 53 | @Override 54 | protected List getPackages() { 55 | return Arrays.asList( 56 | new MainReactPackage(), 57 | new SpringScrollViewPackage() 58 | ); 59 | } 60 | ``` 61 | 62 | ### 在V2的项目上升级到V3 63 | 64 | V3已经独立成为一个单独的库,您可以直接删除react-native-largelist-v2和react-native-spring-scrollview重新安装。当然您的项目其他地方如果没有使用react-native-gesture-handler,也可以删除(记得删除原生端配置)。 65 | 66 | ### iOS常见接入问题 67 | 1. 编译找不到`RCTXXXX.h`文件: 68 | 69 | 可以参看[这里](https://github.com/facebook/react-native/issues/22000#issuecomment-438201084) 70 | 71 | 2. Pod安装 72 | 73 | 在您的项目pod文件里加入如下内容后pod install 74 | ``` 75 | pod 'RNSpringScrollView', :path => '../node_modules/react-native-spring-scrollview/ios' 76 | ``` 77 | 78 | ### Android常见接入问题 79 | 80 | 1. 找不到`android/drawable/XXXXXX`, '`android/res/XXXXXX`'等文件。 81 | 82 | 检查android编译版本问题,本库编译版本是26,可以尝试修改您的版本号,或者修改本库版本号; 83 | 84 | 检查`YourProject/android/app/build.gradle`是否包含了谷歌的代码仓库 85 | ``` 86 | allprojects { 87 | repositories { 88 | mavenLocal() 89 | jcenter() 90 | maven { 91 | url 'https://maven.google.com' 92 | } 93 | maven { 94 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 95 | url "$rootDir/../node_modules/react-native/android" 96 | } 97 | } 98 | } 99 | ``` 100 | -------------------------------------------------------------------------------- /docs/zh-cn/V3/KnownIssues.md: -------------------------------------------------------------------------------- 1 | 9 | # 已知问题 10 | 1. 由于React Native本身问题,安卓拥有`overflow:"scroll"`样式的View就不能直接支持borderRadius。你可以选择在外面套一层View即可实现borderRadius,就像下面这样: 11 | 12 | ``` 13 | 14 | 15 | 16 | ``` 17 | -------------------------------------------------------------------------------- /docs/zh-cn/V3/Overview.md: -------------------------------------------------------------------------------- 1 | 9 | # 概述 10 | 11 | LargeList V3 依赖 `react-native-spring-scrollview@^3.0.2`, 支持SpringScrollView几乎所有的属性。 12 | 13 | 与SpringScrollView一样,LargeList必须有一个确定的高度才能正常工作,因为它实际上所做的就是将一系列Cell装进一个确定高度的容器(通过滚动操作)。LargeList默认具有{flex:1}的样式,因此要使LargeList正常工作,它的父容器必须是确定高度的,你也可以通过手动指定样式,使之正常工作。 14 | 15 | ### 基础属性列表 16 | 17 | 属性 | 类型 | 默认值 |  描述   18 | ---- | ------ | --------- | -------- 19 | [...SpringScrollView](https://bolan9999.github.io/react-native-spring-scrollview/#/) | - | - | 支持SpringScrollView几乎所有属性 20 | data | { items: any[] }[] | 必需 | 列表的数据源,外层数组表示吸顶Section的数量,内层的items数组表示每个Section下有多少个Items。 21 | contentStyle | ViewStyle | { height } | LargeList的content view样式 22 | heightForSection | (section: number) => number | ()=>0 | 返回列表每一组组头高度的函数 23 | renderSection | (section: number) => React.ReactElement <any> | ()=>null | 每一组组头的render函数 24 | heightForIndexPath | (indexPath: IndexPath) => number | 必需 | 返回列表每一行高度的函数 25 | renderIndexPath | (indexPath: IndexPath, mediaWrapperParam:Object) => React.ReactElement <any> | 必需 | 每一行的render函数,mediaWrapperParam是用于大图片或视频优化选项。 26 | renderHeader | ()=> React.ReactElement <any> | undefined | 列表的头部组件函数 27 | renderFooter | ()=> React.ReactElement <any> | undefined | 列表的尾部组件函数 28 | inverted | boolean | false | 翻转滚动方向,适配聊天App,查看示例 [ChatExample](https://github.com/bolan9999/react-native-largelist/tree/master/Examples/ChatExample.js) . 29 | 30 | ### 简单示例 31 | 32 | ``` 33 | 50} 37 | renderSection={this._renderSection} 38 | heightForIndexPath={() => 50} 39 | renderIndexPath={this._renderIndexPath} 40 | /> 41 | ``` 42 | 43 | ### 注意事项 44 | * LargeList默认具有{flex:1}的样式,因此要使LargeList正常工作,它的父容器必须是确定高度的,你也可以通过手动指定样式,使之正常工作。 45 | * 再3.1版本之后,`renderHeader`,`renderFooter`,`renderIndexPath`不再执行切片操作. `renderIndexPath`需要`{flex:1}`才能占满整个行 46 | -------------------------------------------------------------------------------- /docs/zh-cn/V3/Scroll.md: -------------------------------------------------------------------------------- 1 | 9 | # 滑动 10 | 11 | 要使用代码滑动到指定位置,非常简单: 12 | 13 | ### 第一步,获取LargeList的引用 14 | ```$js 15 | (this._list = ref)} /> 16 | ``` 17 | 18 | ### 第二步,使用scrollTo方法 19 | ```$js 20 | this._list && this._list.scrollTo({x:0,y:100}).then().catch(); 21 | ``` 22 | ### 可用滑动方法 23 | scrollTo({x:number, y:number}, animated:boolean=true):Promise<void> 24 | 25 | 滑动到指定的偏移 26 | 27 | scrollToIndexPath({section:number, row:number}, animated: boolean = true):Promise<void> 28 | 29 | 滑动到指定的IndexPath,如果row===-1,则表示滑动到相应的组头 30 | # Javascript端监听滑动 31 | 32 | ### onScroll : ({nativeEvent:{contentOffset:{x:number, y:number}}})=>any 33 | 34 | ```$js 35 | { 36 | console.log("offset : x=", x, "y=", y); 37 | }/> 38 | ``` 39 | 40 | 注意: 41 | 42 | * y值是有可能超出内容范围之外的 43 | * 不要使用Animated.createAnimatedComponent,LargeList本身支持所有的Animated.View的属性,如果需要高性能的监听偏移,请使用下面的原生动画驱动 44 | 45 | # 监听原生偏移值 46 | 47 | ### onNativeContentOffsetExtract : {x?:Animated.Value, y?:Animated.Value} 48 | 49 | 使用原生动画值监听滑动偏移,可以用作插值动画 50 | 51 | ```$js 52 | _nativeOffset = { 53 | y: new Animated.Value(0) 54 | }; 55 | 56 | render(){ 57 | return 58 | } 59 | 60 | ``` 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /docs/zh-cn/V3/StickyForm/Overview.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | `StickyForm`是一个支持水平垂直双吸边的组件。它会把`renderHeader`,`renderSection`,`renderIndexPath`,`renderFooter`返回的element的子节点切片,并且让他们的第一个节点自动吸住左边。 配合LargeList的headerStickyEnabled,可以把头部吸在列表的顶部,然后把Section吸在头部的下面。具体示例见下面动图: 3 | 4 | ### 预览 5 | 6 | ![StickyFormExample](../../../res/StickyFormExample.gif) 7 | -------------------------------------------------------------------------------- /docs/zh-cn/V3/StickyForm/Usage.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | 属性 | 类型 | 默认值 | 描述   4 | ---- | ------ | --------- | -------- 5 | ...LargeList | - | - | 支持所有的LargeList属性(含刷新及加载)。 6 | directionalLockEnabled | boolean | true | 当此属性为true时,它会试着锁定只在水平或垂直一个方向上滚动。 7 | headerStickyEnabled | boolean | true | 将头部吸在StickForm的顶部,Section跟着吸在头部的下边。 8 | 9 | 10 | ### Precautions 11 | 它会把`renderHeader`,`renderSection`,`renderIndexPath`,`renderFooter`返回节点的子节点切片,并且让他们的第一个节点自动吸住左边。 配合LargeList的headerStickyEnabled,可以把头部吸在列表的顶部,然后把Section吸在头部的下面。. 具体可以查看示例 [StickyFormExample](https://github.com/bolan9999/react-native-largelist/blob/master/Examples/StickyFormExamples/StickyFormExample.js) . 12 | 13 | -------------------------------------------------------------------------------- /docs/zh-cn/V3/SupportedProps.md: -------------------------------------------------------------------------------- 1 | 9 | # 所有支持属性列表 10 | 11 | 属性 | 类型 | 默认值 |  描述   12 | ---- | ------ | --------- | -------- 13 | [...Animated.View](http://facebook.github.io/react-native/docs/view) | - | - | 支持有View的属性 14 | bounces | boolean | true | 滑动超出内容视图后是否可以弹性地继续滑动(iOS & Android,如果为true,水平方向内容视图如果没有超过SpringScrollView则不会有弹性,垂直方向始终具有弹性) 15 | scrollEnabled | boolean | true | 是否可以滚动 16 | initialContentOffset | {x:number, y:number} | {x:0,y:0} | 初始化偏移,仅第一次初始化有效,后期更改无效(已支持x方向) 17 | showsVerticalScrollIndicator | boolean | true | 显示垂直滚动指示器 18 | showsHorizontalScrollIndicator | boolean | true | 显示水平滚动指示器(内容视图超出LargeList视口才有用) 19 | tapToHideKeyboard | boolean | true | 点击LargeList是否收起键盘 20 | data | { items: any[] }[] | 必需 | 列表的数据源 21 | heightForSection | (section: number) => number | ()=>0 | 返回列表每一组组头高度的函数 22 | renderSection | (section: number) => React.ReactElement <any> | ()=>null | 每一组组头的render函数 23 | heightForIndexPath | (indexPath: IndexPath) => number | 必需 | 返回列表每一行高度的函数 24 | renderIndexPath | (indexPath: IndexPath, mediaWrapperParam:Object) => React.ReactElement <any> | 必需 | 每一行的render函数, mediaWrapperParam是用于大图片或视频优化选项。 25 | renderHeader | ()=> React.ReactElement <any> | undefined | 列表的头部组件函数 26 | renderFooter | ()=> React.ReactElement <any> | undefined | 列表的尾部组件函数 27 | inverted | boolean | false | 翻转滚动方向,适配聊天App,查看示例 [ChatExample](https://github.com/bolan9999/react-native-largelist/tree/master/Examples/ChatExample.js) . 28 | pagingEnabled | boolean | false | 当值为 true 时,滚动条会停在设置的pageSize整数倍位置。这个属性在iOS和安卓上都支持双向分页。 29 | pageSize | {width:number,height:number} | {width:0, height:0} | 配合pagingEnabled使用分页,使滑动停止在设置的整数倍位置。同时支持水平和垂直双向分页。0代表使用LargeList的视口大小。 30 | onRefresh | ()=>any | undefined | 下拉刷新的回调函数,如果设置了此属性,则会在顶部加一个刷新Header 31 | refreshHeader | [RefreshHeader](https://github.com/bolan9999/react-native-spring-scrollview/blob/master/src/RefreshHeader.js) | NormalHeader | 选择下拉刷新的组件,用户如果不希望高度自定义,则可以不设定直接使用NormalHeader,如果需要高度自定义,请参看[下拉刷新](zh-cn/V3/Refresh) 32 | onLoading | ()=>any | undefined | 上拉加载的回调函数,如果设置了此属性,则会在底部加一个加载组件 33 | allLoaded | boolean | false | 数据是否加载完成。 34 | loadingFooter | [LoadingFooter](https://github.com/bolan9999/react-native-spring-scrollview/blob/master/src/LoadingFooter.js) | NormalFooter | 上拉加载组件,用户如果不希望自定义,则可以使用NormalFooter,如果需要高度自定义,请参看[上拉加载](Loading) 35 | onScroll | ({nativeEvent:{contentOffset:{x, y}}})=>any | undefined | 监听列表滑动(JavaScript端) 36 | onNativeContentOffsetExtract | {x?:Animated.Value, y?:Animated.Value} | undefined | 使用原生动画值监听滑动偏移,可以用作插值动画 37 | onTouchBegin | ()=>any | undefined | 手指按下时回调 38 | onTouchEnd | ()=>any | undefined | 手指抬起时回调 39 | onMomentumScrollBegin | ()=>any | undefined | 松手后减速开始的回调 40 | onMomentumScrollEnd | ()=>any | undefined | 减速结束回调 41 | textInputRefs | TextInput[] | [] | 将TextInput的引用传入,让SpringScrollView自动管理键盘遮挡问题。 42 | dragToHideKeyboard | boolean | true | 滑动屏幕时是否隐藏键盘 43 | inputToolBarHeight | number | 44 | 不同的系统,不同的三方输入法,键盘的工具栏高度是不确定的,并且官方没有给出获取工具栏高度的办法,这个属性用以给用户小幅调整键盘弹起时,组件偏移的位置 44 | groupCount | number | 4 | 优化参数,LargeList将各行进行分组(不是Section,这个视独立的组),groupCount表示总共渲染4组,每组至少渲染groupMinHeight高度,值越大预渲染的行数越多,对应的初始化越慢。请注意groupCount * groupMinHeight必须大于LargeList的视口高度。 45 | groupMinHeight | number | screenHeight / 3 | 优化参数,每组的高度 46 | updateTimeInterval | number | 150 | 更新延时,值越小请求更新的频率越高,但是React Native是异步的,请求更新过多会导致更新不过来;值越大越容易让用户看到新的Item替换旧的Item的现象。 47 | -------------------------------------------------------------------------------- /docs/zh-cn/V3/WaterfallList/Overview.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | `WaterfallList`是一个高性能的瀑布流列表,它继承了SpringScrollView的跨平台弹性功能,刷新与加载功能。同时继承了LargeList的高性能性(无白板)。请注意,为了优化性能,每个Item的高度是需要给出的。 3 | 4 | ### 预览 5 | ![WaterfallExample](../../../res/WaterfallExample.png) 6 | ![WaterfallExample](../../../res/WaterfallExample.gif) 7 | ![PictureExample](../../../res/PictureExample.gif) 8 | -------------------------------------------------------------------------------- /docs/zh-cn/V3/WaterfallList/Usage.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | Props | Type | Default |  Description   4 | ---- | ------ | --------- | -------- 5 | [...SpringScrollView](https://bolan9999.github.io/react-native-spring-scrollview/#/) | - | - | 支持几乎所有SpringScrollView的属性(包含自定义刷新及自定义加载)。 6 | data | any[] | required | 数据源,数组的个数决定了Item的数量 7 | heightForItem | (item:any,index:number)=> number | 必需 | 一个高度函数,用以返回每个Item的高度 8 | renderItem | (item:any,index:number)=> React.ReactElement<any> | 必需 | 每个Item的render函数 9 | preferColumnWidth | number | undefined | 每个Item的理想宽度, 它会影响实际列数,实际列数等于WaterfallList除以理想宽度向下取整,实际宽度是组件宽度除以实际列数(目前只支持等宽的Item).(`preferColumnWidth` 和 `numColumns` 至少需要指定一个. ) 10 | numColumns | number | undefined | 固定列数. (`preferColumnWidth` 和 `numColumns` 至少需要指定一个. ) 11 | renderHeader | ()=> React.ReactElement <any> | undefined | 头部组件函数 12 | renderFooter | ()=> React.ReactElement <any> | undefined | 尾部组件函数 13 | 14 | -------------------------------------------------------------------------------- /docs/zh-cn/_sidebar.md: -------------------------------------------------------------------------------- 1 | 9 | * [Version 3 (Latest)](zh-cn/README) 10 | * [欢迎](zh-cn/README) 11 | * [快速接入](zh-cn/V3/GettingStart) 12 | * [简单使用](zh-cn/V3/BasicUsage) 13 | * LargeList 14 | * [基本用法](zh-cn/V3/Overview) 15 | * [下拉刷新](zh-cn/V3/Refresh) 16 | * [上拉加载](zh-cn/V3/Loading) 17 | * [滑动 & 监听滑动](zh-cn/V3/Scroll) 18 | * [大图片视频列表优化](zh-cn/V3/BigMedia) 19 | * [所有支持属性列表](zh-cn/V3/SupportedProps) 20 | * [已知问题](zh-cn/V3/KnownIssues) 21 | * WaterfallList 22 | * [概述](zh-cn/V3/WaterfallList/Overview) 23 | * [基本用法](zh-cn/V3/WaterfallList/Usage) 24 | * StickyForm 25 | * [概述](zh-cn/V3/StickyForm/Overview) 26 | * [基本用法](zh-cn/V3/StickyForm/Usage) 27 | * 注意事项 28 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 石破天惊 3 | * @email: shanshang130@gmail.com 4 | * @Date: 2021-07-21 13:45:04 5 | * @LastEditTime: 2021-07-21 14:40:23 6 | * @LastEditors: 石破天惊 7 | * @Description: 8 | */ 9 | import 'react-native-gesture-handler'; 10 | import { AppRegistry, UIManager } from "react-native"; 11 | UIManager.setLayoutAnimationEnabledExperimental && 12 | UIManager.setLayoutAnimationEnabledExperimental(true); 13 | import App from "./App"; 14 | 15 | 16 | AppRegistry.registerComponent("LargeListExample", () => App); 17 | -------------------------------------------------------------------------------- /ios/LargeListDemoTests/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 | -------------------------------------------------------------------------------- /ios/LargeListDemoTests/LargeListDemoTests.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 Native!" 16 | 17 | @interface LargeListDemoTests : XCTestCase 18 | 19 | @end 20 | 21 | @implementation LargeListDemoTests 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 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 44 | if (level >= RCTLogLevelError) { 45 | redboxError = message; 46 | } 47 | }); 48 | 49 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 50 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 51 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 52 | 53 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 54 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 55 | return YES; 56 | } 57 | return NO; 58 | }]; 59 | } 60 | 61 | RCTSetLogFunction(RCTDefaultLogFunction); 62 | 63 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 64 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 65 | } 66 | 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /ios/LargeListExample-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | -------------------------------------------------------------------------------- /ios/LargeListExample.xcodeproj/xcshareddata/xcschemes/LargeListExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 55 | 61 | 62 | 63 | 64 | 70 | 72 | 78 | 79 | 80 | 81 | 83 | 84 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /ios/LargeListExample.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/LargeListExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/LargeListExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : UIResponder 5 | 6 | @property (nonatomic, strong) UIWindow *window; 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /ios/LargeListExample/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | 3 | #import 4 | #import 5 | #import 6 | 7 | #ifdef FB_SONARKIT_ENABLED 8 | #import 9 | #import 10 | #import 11 | #import 12 | #import 13 | #import 14 | 15 | static void InitializeFlipper(UIApplication *application) { 16 | FlipperClient *client = [FlipperClient sharedClient]; 17 | SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults]; 18 | [client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]]; 19 | [client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]]; 20 | [client addPlugin:[FlipperKitReactPlugin new]]; 21 | [client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]]; 22 | [client start]; 23 | } 24 | #endif 25 | 26 | @implementation AppDelegate 27 | 28 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 29 | { 30 | #ifdef FB_SONARKIT_ENABLED 31 | InitializeFlipper(application); 32 | #endif 33 | 34 | RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; 35 | RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge 36 | moduleName:@"LargeListExample" 37 | initialProperties:nil]; 38 | 39 | if (@available(iOS 13.0, *)) { 40 | rootView.backgroundColor = [UIColor systemBackgroundColor]; 41 | } else { 42 | rootView.backgroundColor = [UIColor whiteColor]; 43 | } 44 | 45 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 46 | UIViewController *rootViewController = [UIViewController new]; 47 | rootViewController.view = rootView; 48 | self.window.rootViewController = rootViewController; 49 | [self.window makeKeyAndVisible]; 50 | return YES; 51 | } 52 | 53 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge 54 | { 55 | #if DEBUG 56 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; 57 | #else 58 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 59 | #endif 60 | } 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /ios/LargeListExample/Empty.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Empty.swift 3 | // LargeListExample 4 | // 5 | // Created by MAC on 2021/7/26. 6 | // 7 | 8 | import Foundation 9 | -------------------------------------------------------------------------------- /ios/LargeListExample/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 | } -------------------------------------------------------------------------------- /ios/LargeListExample/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ios/LargeListExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | LargeListExample 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 | NSExceptionDomains 30 | 31 | localhost 32 | 33 | NSExceptionAllowsInsecureHTTPLoads 34 | 35 | 36 | 37 | 38 | NSLocationWhenInUseUsageDescription 39 | 40 | UILaunchStoryboardName 41 | LaunchScreen 42 | UIRequiredDeviceCapabilities 43 | 44 | armv7 45 | 46 | UISupportedInterfaceOrientations 47 | 48 | UIInterfaceOrientationPortrait 49 | UIInterfaceOrientationLandscapeLeft 50 | UIInterfaceOrientationLandscapeRight 51 | 52 | UIViewControllerBasedStatusBarAppearance 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /ios/LargeListExample/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ios/LargeListExample/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char * argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ios/LargeListExampleTests-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | -------------------------------------------------------------------------------- /ios/LargeListExampleTests/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 | -------------------------------------------------------------------------------- /ios/LargeListExampleTests/LargeListExampleTests.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | #import 5 | #import 6 | 7 | #define TIMEOUT_SECONDS 600 8 | #define TEXT_TO_LOOK_FOR @"Welcome to React" 9 | 10 | @interface LargeListExampleTests : XCTestCase 11 | 12 | @end 13 | 14 | @implementation LargeListExampleTests 15 | 16 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 17 | { 18 | if (test(view)) { 19 | return YES; 20 | } 21 | for (UIView *subview in [view subviews]) { 22 | if ([self findSubviewInView:subview matching:test]) { 23 | return YES; 24 | } 25 | } 26 | return NO; 27 | } 28 | 29 | - (void)testRendersWelcomeScreen 30 | { 31 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 32 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 33 | BOOL foundElement = NO; 34 | 35 | __block NSString *redboxError = nil; 36 | #ifdef DEBUG 37 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 38 | if (level >= RCTLogLevelError) { 39 | redboxError = message; 40 | } 41 | }); 42 | #endif 43 | 44 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 45 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 46 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 47 | 48 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 49 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 50 | return YES; 51 | } 52 | return NO; 53 | }]; 54 | } 55 | 56 | #ifdef DEBUG 57 | RCTSetLogFunction(RCTDefaultLogFunction); 58 | #endif 59 | 60 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 61 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 62 | } 63 | 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | require_relative '../node_modules/react-native/scripts/react_native_pods' 2 | require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' 3 | 4 | platform :ios, '10.0' 5 | 6 | target 'LargeListExample' do 7 | config = use_native_modules! 8 | 9 | use_react_native!( 10 | :path => config[:reactNativePath], 11 | # to enable hermes on iOS, change `false` to `true` and then install pods 12 | :hermes_enabled => true 13 | ) 14 | 15 | target 'LargeListExampleTests' do 16 | inherit! :complete 17 | # Pods for testing 18 | end 19 | 20 | # Enables Flipper. 21 | # 22 | # Note that if you have use_frameworks! enabled, Flipper will not work and 23 | # you should disable the next line. 24 | use_flipper!({'Flipper' => '0.75.1', 'Flipper-Folly' => '2.5.3', 'Flipper-RSocket' => '1.3.1'}) 25 | 26 | post_install do |installer| 27 | react_native_post_install(installer) 28 | end 29 | end -------------------------------------------------------------------------------- /issue_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 21 | -------------------------------------------------------------------------------- /metro.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Metro configuration for React Native 3 | * https://github.com/facebook/react-native 4 | * 5 | * @format 6 | */ 7 | 8 | module.exports = { 9 | transformer: { 10 | getTransformOptions: async () => ({ 11 | transform: { 12 | experimentalImportSupport: false, 13 | inlineRequires: true, 14 | }, 15 | }), 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "largelistexample", 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 | "lint": "eslint ." 11 | }, 12 | "dependencies": { 13 | "@react-native-community/masked-view": "^0.1.11", 14 | "@react-navigation/native": "^5.9.4", 15 | "@react-navigation/stack": "^5.14.5", 16 | "react": "17.0.1", 17 | "react-native": "0.64.2", 18 | "react-native-gesture-handler": "^1.10.3", 19 | "react-native-reanimated": "^2.2.0", 20 | "react-native-safe-area-context": "^3.2.0", 21 | "react-native-screens": "^3.4.0", 22 | "react-native-spring-scrollview": "3.0.1-rc.5", 23 | "lottie-ios": "3.1.8", 24 | "lottie-react-native": "4.0.2", 25 | "@react-native-community/async-storage": "^1.12.1" 26 | }, 27 | "devDependencies": { 28 | "@babel/core": "^7.12.9", 29 | "@babel/runtime": "^7.12.5", 30 | "@react-native-community/eslint-config": "^2.0.0", 31 | "babel-jest": "^26.6.3", 32 | "eslint": "7.14.0", 33 | "jest": "^26.6.3", 34 | "metro-react-native-babel-preset": "^0.64.0", 35 | "react-test-renderer": "17.0.1" 36 | }, 37 | "jest": { 38 | "preset": "react-native" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /readme_resources/example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/readme_resources/example.gif -------------------------------------------------------------------------------- /readme_resources/largelist_advanced_usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/readme_resources/largelist_advanced_usage.png -------------------------------------------------------------------------------- /readme_resources/sample1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/readme_resources/sample1.gif -------------------------------------------------------------------------------- /readme_resources/sample2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/readme_resources/sample2.gif -------------------------------------------------------------------------------- /readme_resources/sample3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/readme_resources/sample3.gif -------------------------------------------------------------------------------- /readme_resources/sample4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/readme_resources/sample4.gif -------------------------------------------------------------------------------- /readme_resources/sample5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/readme_resources/sample5.gif -------------------------------------------------------------------------------- /readme_resources/sample6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/readme_resources/sample6.gif -------------------------------------------------------------------------------- /readme_resources/sample7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/readme_resources/sample7.gif -------------------------------------------------------------------------------- /readme_resources/sample8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolan9999/react-native-largelist/d571c13f6f852ce96860ea32755cb1477ff80ad0/readme_resources/sample8.gif -------------------------------------------------------------------------------- /src/.npmignore: -------------------------------------------------------------------------------- 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 | # node.js 34 | # 35 | node_modules/ 36 | npm-debug.log 37 | yarn-error.log 38 | 39 | # BUCK 40 | buck-out/ 41 | \.buckd/ 42 | *.keystore 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | */fastlane/report.xml 52 | */fastlane/Preview.html 53 | */fastlane/screenshots 54 | -------------------------------------------------------------------------------- /src/Group.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 石破天惊 3 | * @email: shanshang130@gmail.com 4 | * @Date: 2021-07-21 13:11:34 5 | * @LastEditTime: 2021-07-29 17:33:54 6 | * @LastEditors: 石破天惊 7 | * @Description: 8 | */ 9 | 10 | import React from "react"; 11 | import { StyleSheet, View,Animated } from "react-native"; 12 | import type { GroupPropType } from "./Types"; 13 | import {styles } from "./styles"; 14 | 15 | export class Group extends React.Component { 16 | _currentIndex = 0; 17 | _offset = 0; 18 | _margin = 0; 19 | 20 | constructor(props) { 21 | super(props); 22 | this.contentConversion(props.offset, true); 23 | } 24 | 25 | contentConversion = (offset: number, init: boolean = false) => { 26 | this._offset = offset; 27 | const { input, output } = this.props; 28 | const cc = []; 29 | output.forEach((v) => cc.indexOf(v) < 0 && cc.push(v)); 30 | for (let i = 0; i < input.length; ++i) { 31 | if (offset >= input[i] && offset <= input[i + 1]) { 32 | this.update(cc.indexOf(output[i]), init); 33 | break; 34 | } 35 | } 36 | }; 37 | 38 | update(index: number, init: boolean) { 39 | if ( 40 | index < 0 || 41 | index >= this.props.indexes.length || 42 | this._currentIndex === index 43 | ) 44 | return; 45 | this._currentIndex = index; 46 | !init && this.forceUpdate(); 47 | } 48 | 49 | shouldComponentUpdate(nextProps, nextState) { 50 | this._offset = nextProps.offset; 51 | return true; 52 | } 53 | 54 | render() { 55 | const { 56 | indexes, 57 | heightForSection, 58 | heightForIndexPath, 59 | renderIndexPath, 60 | inverted, 61 | offset, 62 | input, 63 | output, 64 | nativeOffset, 65 | } = this.props; 66 | this.contentConversion(this._offset, true); 67 | if (this._currentIndex >= indexes.length) return null; 68 | this._margin = 0; 69 | let transform; 70 | if (input.length > 1) { 71 | transform = [ 72 | { 73 | translateY: nativeOffset.value.interpolate({ 74 | inputRange: input, 75 | outputRange: output, 76 | }), 77 | }, 78 | ]; 79 | } 80 | const cs = StyleSheet.flatten([styles.abs, { transform }]); 81 | return ( 82 | 83 | {indexes[this._currentIndex].map((indexPath, rowIndex) => { 84 | if (indexPath.row === -1) { 85 | this._margin = heightForSection(indexPath.section); 86 | return null; 87 | } 88 | const height = heightForIndexPath(indexPath); 89 | if (height === 0) return null; 90 | const marginTop = this._margin; 91 | this._margin = 0; 92 | const style = StyleSheet.flatten({ 93 | height, 94 | marginTop, 95 | alignSelf: "stretch", 96 | transform: [{ scaleY: inverted ? -1 : 1 }], 97 | }); 98 | let rIdx = this._currentIndex; 99 | if (output.length > 4 && output[0] === output[2]) rIdx += 1; 100 | const from = input[rIdx * 2]; 101 | const to = input[rIdx * 2 + 1]; 102 | const mediaWrapperParam = nativeOffset.value.interpolate({ 103 | inputRange: [from, from + 0.1, to, to + 0.1], 104 | outputRange: [1, 0, 0, 1], 105 | }); 106 | return ( 107 | 108 | {renderIndexPath(indexPath, { value: mediaWrapperParam })} 109 | 110 | ); 111 | })} 112 | 113 | ); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/MediaWrapper.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 石破天惊 3 | * @email: shanshang130@gmail.com 4 | * @Date: 2021-07-28 10:53:28 5 | * @LastEditTime: 2021-07-29 15:56:29 6 | * @LastEditors: 石破天惊 7 | * @Description: The big Media wrapper. 8 | */ 9 | 10 | import React from "react"; 11 | import { MediaWrapperType } from "./Types"; 12 | import { Animated, View, StyleSheet, Image } from "react-native"; 13 | 14 | export class MediaWrapper extends React.Component { 15 | _visible = new Animated.Value(1); 16 | render() { 17 | const child = React.Children.only(this.props.children); 18 | this._visible.setValue(1); 19 | return ( 20 | 21 | {React.cloneElement(child, { 22 | [this.props.loadEndFunc]: () => this._visible.setValue(0), 23 | })} 24 | 31 | {this.props.renderLoading()} 32 | 33 | 34 | ); 35 | } 36 | } 37 | 38 | const styles = StyleSheet.create({ 39 | cover: { 40 | position: "absolute", 41 | left: 0, 42 | top: 0, 43 | bottom: 0, 44 | right: 0, 45 | justifyContent: "center", 46 | alignItems: "center", 47 | backgroundColor: "white", 48 | }, 49 | }); 50 | -------------------------------------------------------------------------------- /src/Section.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Created by Stone 4 | * https://github.com/bolan9999 5 | * Email: shanshang130@gmail.com 6 | * Date: 2018/7/24 7 | * 8 | */ 9 | 10 | import React from "react"; 11 | import { StyleSheet, View, Animated } from "react-native"; 12 | import type { SectionPropType } from "./Types"; 13 | 14 | export class Section extends React.Component { 15 | _section = 0; 16 | _offset = 0; 17 | 18 | constructor(props) { 19 | super(props); 20 | this._offset = props.offset; 21 | } 22 | 23 | updateOffset=(offset: number, preventUpdate: boolean = false) =>{ 24 | let index = 0; 25 | this._offset = offset; 26 | for (let i = 0; i < this.props.input.length; ++i) { 27 | if (offset > this.props.input[i]) { 28 | index = i; 29 | } 30 | } 31 | const section = this.props.sectionIndexes[index]; 32 | if (section !== this._section) { 33 | this._section = section; 34 | if (!preventUpdate) this.forceUpdate(); 35 | } 36 | } 37 | 38 | shouldComponentUpdate(nextProps, nextState) { 39 | this._offset = nextProps.offset; 40 | return true; 41 | } 42 | 43 | render() { 44 | const { data, style, heightForSection, renderSection, inverted, offset } = 45 | this.props; 46 | this.updateOffset(this._offset, true); 47 | if ( 48 | this._section === undefined || 49 | this._section < 0 || 50 | this._section >= data.length 51 | ) 52 | return null; 53 | const wStyle = StyleSheet.flatten([ 54 | style, 55 | { 56 | height: heightForSection(this._section), 57 | transform: [...style.transform, { scaleY: inverted ? -1 : 1 }], 58 | }, 59 | ]); 60 | return ( 61 | 62 | {renderSection(this._section)} 63 | 64 | ); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/StickyForm.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Created by Stone 4 | * https://github.com/bolan9999 5 | * Email: shanshang130@gmail.com 6 | * Date: 2019/2/23 7 | * 8 | */ 9 | 10 | import React from "react"; 11 | import { StickyFormPropType } from "./Types"; 12 | import type {IndexPath, LargeListPropType, Offset, Size} from "./Types"; 13 | import { Animated, StyleSheet } from "react-native"; 14 | import { LargeList } from "./LargeList"; 15 | import {idx} from "./idx"; 16 | 17 | export class StickyForm extends React.PureComponent { 18 | _size: Size; 19 | _contentOffsetY = 0; 20 | _nativeOffset; 21 | _offset: Animated.Value; 22 | _largeList=React.createRef(); 23 | 24 | constructor(props) { 25 | super(props); 26 | this._nativeOffset = { 27 | x: new Animated.Value(0), 28 | ...this.props.onNativeContentOffsetExtract 29 | }; 30 | this._offset = this._nativeOffset.x; 31 | } 32 | 33 | render() { 34 | return ( 35 | 44 | ); 45 | } 46 | 47 | _renderHeader = () => { 48 | const { renderHeader } = this.props; 49 | if (!renderHeader || !renderHeader()) return null; 50 | return this._stickyFirstView(this.props.renderHeader()); 51 | }; 52 | 53 | _renderFooter = () => { 54 | const { renderFooter } = this.props; 55 | if (!renderFooter || !renderFooter()) return null; 56 | return this._stickyFirstView(renderFooter()); 57 | }; 58 | 59 | _renderSection = (section: number) => { 60 | return this._stickyFirstView(this.props.renderSection(section)); 61 | }; 62 | 63 | _renderIndexPath = (path: IndexPath) => { 64 | return this._stickyFirstView(this.props.renderIndexPath(path)); 65 | }; 66 | 67 | _stickyFirstView(view: React.ReactElement) { 68 | const childArray = React.Children.toArray(view.props.children); 69 | if (!childArray || childArray.length < 1) return null; 70 | const sticky: any = childArray[0]; 71 | const style = StyleSheet.flatten([ 72 | sticky.props.style, 73 | { 74 | zIndex: 9999, 75 | transform: [{ translateX: this._offset.interpolate({ inputRange: [-1, 0, 1], outputRange: [0, 0, 1] }) }] 76 | } 77 | ]); 78 | return React.cloneElement( 79 | view, 80 | null, 81 | childArray.map((v, index) => { 82 | if (index > 0) return React.cloneElement(v, { key: index }); 83 | return ; 84 | }) 85 | ); 86 | } 87 | 88 | scrollTo(offset: Offset, animated: boolean = true): Promise { 89 | if (!this._largeList.current) return Promise.reject("StickyForm has not been initialized yet!"); 90 | return this._largeList.current.scrollTo(offset, animated).then(() => { 91 | return Promise.resolve(); 92 | }); 93 | } 94 | 95 | endRefresh() { 96 | idx(() => this._largeList.current.endRefresh()); 97 | } 98 | 99 | endLoading() { 100 | idx(() => this._largeList.current.endLoading()); 101 | } 102 | 103 | static defaultProps = { 104 | directionalLockEnabled: true, 105 | headerStickyEnabled: true 106 | }; 107 | } 108 | -------------------------------------------------------------------------------- /src/Types.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Created by Stone 4 | * https://github.com/bolan9999 5 | * Email: shanshang130@gmail.com 6 | * Date: 2018/7/17 7 | * 8 | */ 9 | 10 | import { Animated, ViewStyle } from "react-native"; 11 | import { SpringScrollViewPropType } from "react-native-spring-scrollview"; 12 | 13 | export type LargeListDataType = { items: any[] }[]; 14 | 15 | export interface IndexPath { 16 | section: number; 17 | row: number; 18 | } 19 | 20 | export interface Offset { 21 | x: number; 22 | y: number; 23 | } 24 | 25 | export interface Size { 26 | height: number; 27 | width: number; 28 | } 29 | 30 | export interface LargeListPropType extends SpringScrollViewPropType { 31 | data: LargeListDataType; 32 | headerStickyEnabled?: boolean; 33 | contentStyle?: ViewStyle; 34 | directionalLockEnabled?: boolean; 35 | renderScaleHeaderBackground?: () => React.ReactElement; 36 | heightForSection?: (section: number) => number; 37 | renderSection?: (section: number) => React.Node; 38 | heightForIndexPath: (indexPath: IndexPath) => number; 39 | renderIndexPath: (indexPath: IndexPath) => React.Node; 40 | renderHeader?: () => React.ReactElement; 41 | renderFooter?: () => React.ReactElement; 42 | renderEmpty?: () => React.ReactElement; 43 | onNativeContentOffsetExtract?: { 44 | x: Animated.Value, 45 | y: Animated.Value, 46 | }; 47 | inverted?: boolean; 48 | 49 | groupCount?: number; 50 | groupMinHeight?: number; 51 | updateTimeInterval?: number; 52 | } 53 | 54 | export interface GroupPropType { 55 | indexes: IndexPath[]; 56 | criticalPoint: number[]; 57 | input: number[]; 58 | output: number[]; 59 | data: LargeListDataType; 60 | heightForSection?: (section: number) => number; 61 | heightForIndexPath: (indexPath: IndexPath) => number; 62 | renderSection?: (section: number) => React.Node; 63 | renderIndexPath: (indexPath: IndexPath) => React.Node; 64 | offset?: number; 65 | inverted?: boolean; 66 | updateTimeInterval: number; 67 | } 68 | 69 | export interface SectionPropType { 70 | tops: number[]; 71 | section: number; 72 | nativeOffset: Animated.Value; 73 | heightForSection: (section: number) => number; 74 | renderSection?: (section: number) => React.Node; 75 | input: number[]; 76 | output: number[]; 77 | sectionIndexes: number[]; 78 | offset: number; 79 | inverted?: boolean; 80 | data: LargeListDataType; 81 | } 82 | 83 | export interface WaterfallListType extends SpringScrollViewPropType { 84 | data: any[]; 85 | heightForItem: (item: any, index: number) => number; 86 | renderItem: (item: any, index: number) => React.ReactElement; 87 | preferColumnWidth?: number; 88 | numColumns?: number; 89 | renderHeader?: () => React.ReactElement; 90 | renderFooter?: () => React.ReactElement; 91 | onNativeContentOffsetExtract?: { 92 | x: Animated.Value, 93 | y: Animated.Value, 94 | }; 95 | } 96 | 97 | export interface WaterfallItemType extends WaterfallListType { 98 | input: number[]; 99 | output: number[]; 100 | itemIndexes: number[]; 101 | offset: number; 102 | } 103 | 104 | export interface StickyFormPropType extends LargeListPropType {} 105 | 106 | export interface MediaWrapperType { 107 | loadEndFunc: string; 108 | renderLoading: () => React.ReactElement; 109 | mediaWrapperParam: Animated.Value; 110 | } 111 | -------------------------------------------------------------------------------- /src/WaterfallItem.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 石破天惊 3 | * @email: shanshang130@gmail.com 4 | * @Date: 2021-07-21 13:11:34 5 | * @LastEditTime: 2021-07-27 19:59:36 6 | * @LastEditors: 石破天惊 7 | * @Description: 8 | */ 9 | 10 | import React from "react"; 11 | import { StyleSheet,Animated } from "react-native"; 12 | import type { WaterfallItemType } from "./Types"; 13 | 14 | export class WaterfallItem extends React.Component { 15 | _itemIndex=0; 16 | 17 | constructor(props) { 18 | super(props); 19 | this._offset = props.offset; 20 | } 21 | 22 | shouldComponentUpdate(nextProps) { 23 | this._offset = nextProps.offset; 24 | return true; 25 | } 26 | 27 | updateOffset(offset: number, init: boolean = false, next?: WaterfallItemType) { 28 | let index = 0; 29 | this._offset = offset; 30 | if (!next) next = this.props; 31 | for (let i = 0; i < next.input.length; ++i) { 32 | if (offset > next.input[i]) { 33 | index = i; 34 | } 35 | } 36 | const itemIndex = next.itemIndexes[index]; 37 | if (itemIndex !== this._itemIndex) { 38 | this._itemIndex = itemIndex; 39 | if(!init) this.forceUpdate(); 40 | } 41 | } 42 | 43 | render() { 44 | const { data, style, heightForItem, renderItem,columnIdx } = this.props; 45 | this.updateOffset(this._offset,true); 46 | if (this._itemIndex === undefined || this._itemIndex < 0 || this._itemIndex >= data.length) return null; 47 | const wStyle = StyleSheet.flatten([style, { height: heightForItem(data[this._itemIndex], this._itemIndex) }]); 48 | return ( 49 | 50 | {renderItem(data[this._itemIndex], this._itemIndex, columnIdx)} 51 | 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/idx.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Created by Stone 4 | * https://github.com/bolan9999 5 | * Email: shanshang130@gmail.com 6 | * Date: 2018/9/23 7 | * 8 | */ 9 | 10 | export function idx(f: () => T, defaultValue?: T | string) { 11 | try { 12 | const res = f(); 13 | return res === null || res === undefined || isNaN(res) ? defaultValue : res; 14 | } catch (e) { 15 | return defaultValue; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/index.d.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 石破天惊 3 | * @email: shanshang130@gmail.com 4 | * @Date: 2021-07-21 13:11:34 5 | * @LastEditTime: 2021-08-05 18:42:43 6 | * @LastEditors: 石破天惊 7 | * @Description: 8 | */ 9 | 10 | declare module "react-native-largelist" { 11 | import { SpringScrollViewPropType, Offset } from "react-native-spring-scrollview"; 12 | import * as React from "react"; 13 | import { Animated } from "react-native"; 14 | 15 | export interface IndexPath { 16 | section: number; 17 | row: number; 18 | } 19 | 20 | export type LargeListDataType = { items: any[] }[]; 21 | 22 | export interface LargeListPropType extends SpringScrollViewPropType { 23 | data: LargeListDataType; 24 | heightForSection?: (section: number) => number; 25 | renderSection?: (section: number) => React.ReactElement; 26 | heightForIndexPath: (indexPath: IndexPath) => number; 27 | renderIndexPath: (indexPath: IndexPath) => React.ReactElement; 28 | renderHeader?: () => React.ReactElement; 29 | renderFooter?: () => React.ReactElement; 30 | renderEmpty?: () => React.ReactElement, 31 | 32 | groupCount?: number; 33 | groupMinHeight?: number; 34 | updateTimeInterval?: number; 35 | headerStickyEnabled?: boolean; 36 | } 37 | 38 | export class LargeList extends React.PureComponent { 39 | scrollTo(offset: Offset, animated?: boolean): Promise; 40 | scrollToIndexPath(indexPath: IndexPath, animated?: boolean): Promise; 41 | endRefresh(): void; 42 | endLoading(): void; 43 | } 44 | 45 | export interface WaterfallListType extends SpringScrollViewPropType { 46 | data: T[]; 47 | heightForItem: (item: T, index: number) => number; 48 | renderItem: (item: T, index: number, columnIdx: number) => React.ReactElement; 49 | preferColumnWidth?: number; 50 | numColumns?: number; 51 | renderHeader?: () => React.ReactElement; 52 | renderFooter?: () => React.ReactElement; 53 | onNativeContentOffsetExtract?: { 54 | x?: Animated.Value; 55 | y?: Animated.Value; 56 | }; 57 | } 58 | 59 | export class WaterfallList extends React.PureComponent> { 60 | scrollTo(offset: Offset, animated?: boolean): Promise; 61 | endRefresh(): void; 62 | endLoading(): void; 63 | } 64 | 65 | export interface StickyFormPropType extends LargeListPropType {} 66 | 67 | export class StickyForm extends React.PureComponent { 68 | scrollTo(offset: Offset, animated?: boolean): Promise; 69 | beginRefresh():Promise; 70 | endRefresh(): void; 71 | endLoading(rebound?: boolean): void; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 石破天惊 3 | * @email: shanshang130@gmail.com 4 | * @Date: 2021-07-21 13:11:34 5 | * @LastEditTime: 2021-07-28 15:55:37 6 | * @LastEditors: 石破天惊 7 | * @Description: 8 | */ 9 | export * from "./LargeList"; 10 | export * from "./WaterfallList"; 11 | export * from "./Types"; 12 | export * from "./StickyForm"; 13 | export * from "./MediaWrapper"; 14 | -------------------------------------------------------------------------------- /src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-largelist", 3 | "version": "3.1.0-rc.2", 4 | "private": false, 5 | "description": "The best performance large list component which is much better than SectionList for React Native.", 6 | "author": "bolan9999 ", 7 | "license": "MIT", 8 | "repository": { 9 | "type": "git", 10 | "url": "git@github.com:bolan9999/react-native-largelist.git" 11 | }, 12 | "keywords": [ 13 | "react-native", 14 | "react-component", 15 | "large list", 16 | "flatlist", 17 | "sectionlist", 18 | "tableview", 19 | "high performance", 20 | "swipeout", 21 | "swipable flatlist" 22 | ], 23 | "bugs": { 24 | "url": "https://github.com/bolan9999/react-native-largelist/issues" 25 | }, 26 | "homepage": "https://github.com/bolan9999/react-native-largelist", 27 | "peerDependencies": { 28 | "react": "^16.3.1", 29 | "react-native": "^0.50.0", 30 | "prop-types": "^15.6.0", 31 | "react-native-spring-scrollview": "^3.0.1-rc.5" 32 | }, 33 | "devDependencies": { 34 | "babel-jest": "21.2.0", 35 | "babel-preset-react-native": "^4.0.0", 36 | "jest": "21.2.1", 37 | "react-test-renderer": "16.0.0" 38 | }, 39 | "jest": { 40 | "preset": "react-native" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/styles.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Created by Stone 4 | * https://github.com/bolan9999 5 | * Email: shanshang130@gmail.com 6 | * Date: 2018/7/17 7 | * 8 | */ 9 | 10 | import {StyleSheet} from "react-native"; 11 | 12 | export const styles = StyleSheet.create({ 13 | footer:{ 14 | position:"absolute", 15 | bottom:0, 16 | left:0, 17 | right:0 18 | }, 19 | abs:{ 20 | position: "absolute", 21 | left: 0, 22 | right: 0, 23 | top: 0, 24 | }, 25 | leftTop:{ 26 | position: "absolute", 27 | left: 0, 28 | top: 0, 29 | } 30 | }); 31 | --------------------------------------------------------------------------------