Skip to content

Commit

Permalink
feat(components-rn): ScrollView, 支持 FlatList 来代替 ScrollView
Browse files Browse the repository at this point in the history
  • Loading branch information
Manjiz committed Jun 24, 2019
1 parent 96573c1 commit 6714e24
Show file tree
Hide file tree
Showing 3 changed files with 229 additions and 46 deletions.
157 changes: 157 additions & 0 deletions packages/taro-components-rn/TCRNExample/App.flatlist.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import React, { Component } from 'react'
import { StyleSheet } from 'react-native'
import {
Provider,
Block,
ScrollView,
View,
Text,
Button,
Image
} from '../dist'
// import EXAudio from './example/EXAudio'
import EXButton from './example/EXButton'
import EXCheckbox from './example/EXCheckbox'
import EXForm from './example/EXForm'
import EXIcon from './example/EXIcon'
import EXImage from './example/EXImage'
import EXInput from './example/EXInput'
// import EXMap from './example/EXMap'
import EXPicker from './example/EXPicker'
import EXProgress from './example/EXProgress'
import EXRadio from './example/EXRadio'
import EXRichText from './example/EXRichText'
import EXSlider from './example/EXSlider'
import EXSwiper from './example/EXSwiper'
import EXSwitch from './example/EXSwitch'
// import EXVideo from './example/EXVideo'
import EXWebView from './example/EXWebView'

export default class App extends Component {
state = {
// 更改 scrollTop 可滚动
scrollTop: 0
}

onViewTouchstart = () => {
console.log('view toucstart')
}

onViewTouchmove = () => {
console.log('view touchmove')
}

onViewTouchend = () => {
console.log('view touchend')
}

componentDidMount () {
// setTimeout(() => {
// this.setState({ scrollTop: 2200 })
// }, 0)
}

renderItem = ({ item }) => {
switch (item.name) {
case 'welcome':
return <Text>Welcome to React Native!</Text>
case 'Block':
return (
<View style={styles.section}>
<View style={styles.sectionTit}>
<Text style={styles.sectionTitTxt}>Block</Text>
</View>
<Block />
</View>
)
case 'Button':
return (
<View style={styles.section}>
<View style={styles.sectionTit}>
<Text style={styles.sectionTitTxt}>Button</Text>
</View>
<EXButton />
</View>
)
case 'Checkbox':
return (
<View style={styles.section}>
<View style={styles.sectionTit}>
<Text style={styles.sectionTitTxt}>Checkbox</Text>
</View>
<EXCheckbox />
</View>
)
case 'Form':
return (
<View style={styles.section}>
<View style={styles.sectionTit}>
<Text style={styles.sectionTitTxt}>Form</Text>
</View>
<EXForm />
</View>
)
}
}

render () {
return (
<Provider>
<ScrollView
style={{
flex: 1,
backgroundColor: '#f5fcff',
alignItems: 'center'
}}
scrollTop={this.state.scrollTop}
scrollWithAnimation={true}
enableBackToTop={false}
onScrollToUpper={() => {
console.log('to upper')
}}
onScrollToLower={() => {
console.log('to lower')
}}
onScroll={(e) => {
console.log('onScroll', e)
}}
bounces={false}
data={[
{ name: 'welcome' },
{ name: 'Block' },
{ name: 'Button' },
{ name: 'Checkbox' },
{ name: 'Form' },
]}
renderItem={this.renderItem}
/>
</Provider>
)
}
}

const styles = StyleSheet.create({
section: {
alignItems: 'center',
width: '100%',
paddingBottom: 10,
marginBottom: 10,
borderBottomWidth: 1,
borderBottomColor: 'gold'
},
sectionTit: {
marginBottom: 10,
paddingVertical: 4,
paddingHorizontal: 8,
backgroundColor: 'tomato',
borderRadius: 4,
borderLeftWidth: 3,
borderLeftColor: '#666',
borderRightWidth: 3,
borderRightColor: '#666'
},
sectionTitTxt: {
fontSize: 18,
color: 'white'
}
})
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react'
import { StyleProp, ViewStyle } from 'react-native'
import { StyleProp, ViewStyle, ListRenderItem } from 'react-native'

export type ScrollMetrics = {
contentLength: number;
Expand Down Expand Up @@ -37,7 +37,7 @@ export interface ScrollViewState {
snapScrollLeft: number;
}

export interface ScrollViewProps {
export interface ScrollViewProps<ItemT> {
children?: React.ReactNode;
style?: StyleProp<ViewStyle>;
scrollX?: boolean;
Expand All @@ -52,4 +52,6 @@ export interface ScrollViewProps {
onScroll?: (evt: EventOnScroll) => void;
// RN 属性
contentContainerStyle?: StyleProp<ViewStyle>;
data?: ReadonlyArray<ItemT> | null;
renderItem?: ListRenderItem<ItemT>;
}
112 changes: 68 additions & 44 deletions packages/taro-components-rn/src/components/ScrollView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import * as React from 'react'
import {
ScrollView,
FlatList,
NativeSyntheticEvent,
NativeScrollEvent,
LayoutChangeEvent,
Expand All @@ -38,7 +39,7 @@ import { ScrollViewProps, ScrollViewState, ScrollMetrics } from './PropsType'
// // Other
// ]

class _ScrollView extends React.Component<ScrollViewProps, ScrollViewState> {
class _ScrollView extends React.Component<ScrollViewProps<any>, ScrollViewState> {
static defaultProps = {
upperThreshold: 50,
lowerThreshold: 50,
Expand All @@ -47,7 +48,7 @@ class _ScrollView extends React.Component<ScrollViewProps, ScrollViewState> {
enableBackToTop: false,
}

static getDerivedStateFromProps (props: ScrollViewProps, state: ScrollViewState) {
static getDerivedStateFromProps (props: ScrollViewProps<any>, state: ScrollViewState) {
return state.snapScrollTop !== props.scrollTop || state.snapScrollLeft !== props.scrollLeft ? {
snapScrollTop: props.scrollTop,
snapScrollLeft: props.scrollLeft
Expand All @@ -70,7 +71,7 @@ class _ScrollView extends React.Component<ScrollViewProps, ScrollViewState> {
velocity: 0,
visibleLength: 0,
}
$scrollView = React.createRef<ScrollView>()
$scrollView = React.createRef<any>()
_hasDataChangedSinceEndReached: boolean
_sentEndForContentLength: number = 0
_scrollEventThrottle: number = 50
Expand Down Expand Up @@ -180,8 +181,15 @@ class _ScrollView extends React.Component<ScrollViewProps, ScrollViewState> {
}

scrollToOffset = (x: number = 0, y: number = 0): void => {
const { scrollX, data, renderItem } = this.props
const node = this.$scrollView.current
node && node.scrollTo({ x, y, animated: !!this.props.scrollWithAnimation })
if (node) {
if (data && renderItem) {
(node as FlatList<any>).scrollToOffset({ offset: scrollX ? x : y, animated: !!this.props.scrollWithAnimation })
} else {
(node as ScrollView).scrollTo({ x, y, animated: !!this.props.scrollWithAnimation })
}
}
}

componentDidMount () {
Expand All @@ -192,11 +200,11 @@ class _ScrollView extends React.Component<ScrollViewProps, ScrollViewState> {
}
}

getSnapshotBeforeUpdate (prevProps: ScrollViewProps, prevState: ScrollViewState) {
getSnapshotBeforeUpdate (prevProps: ScrollViewProps<any>, prevState: ScrollViewState) {
return prevState.snapScrollTop !== this.state.snapScrollTop || prevState.snapScrollLeft !== this.state.snapScrollLeft
}

componentDidUpdate (prevProps: ScrollViewProps, prevState: ScrollViewState, snapshot: boolean) {
componentDidUpdate (prevProps: ScrollViewProps<any>, prevState: ScrollViewState, snapshot: boolean) {
if (snapshot) {
this.scrollToOffset(this.state.snapScrollLeft, this.state.snapScrollTop)
}
Expand All @@ -213,6 +221,8 @@ class _ScrollView extends React.Component<ScrollViewProps, ScrollViewState> {
scrollX,
enableBackToTop,
contentContainerStyle,
data,
renderItem,
} = this.props

const flattenStyle: ViewStyle & { [key: string]: any } = StyleSheet.flatten(style)
Expand All @@ -226,45 +236,59 @@ class _ScrollView extends React.Component<ScrollViewProps, ScrollViewState> {
flattenStyle.justifyContent && (_contentContainerStyle.justifyContent = flattenStyle.justifyContent)
}

return (
const scrollElementProps = {
horizontal: scrollX,
onContentSizeChange: this._onContentSizeChange,
onLayout: this._onLayout,
onScroll: this._onScroll,
onScrollEndDrag: this._onScrollEndDrag,
onMomentumScrollEnd: this._onMomentumScrollEnd,
scrollEventThrottle: this._scrollEventThrottle,
scrollsToTop: !!enableBackToTop,
style: wrapperStyle,
contentContainerStyle: [_contentContainerStyle, contentContainerStyle],
...omit(this.props, [
// props
'style',
'scrollX',
'upperThreshold',
'lowerThreshold',
'scrollTop',
'scrollLeft',
'scrollWithAnimation',
'enableBackToTop',
'onScrollToUpper',
'onScrollToLower',
'onScroll',
'contentContainerStyle',
// SProps
'horizontal',
'onContentSizeChange',
'onLayout',
'onScroll',
'onScrollEndDrag',
'onMomentumScrollEnd',
'scrollEventThrottle',
'scrollsToTop',
'style',
'contentContainerStyle',
'data',
'renderItem',
'keyExtractor',
]),
ref: this.$scrollView
}

return data && renderItem ? (
<FlatList
{...scrollElementProps}
data={data}
renderItem={renderItem}
keyExtractor={(item, index) => index + ''}
/>
) : (
<ScrollView
horizontal={scrollX}
onContentSizeChange={this._onContentSizeChange}
onLayout={this._onLayout}
onScroll={this._onScroll}
onScrollEndDrag={this._onScrollEndDrag}
onMomentumScrollEnd={this._onMomentumScrollEnd}
scrollEventThrottle={this._scrollEventThrottle}
scrollsToTop={!!enableBackToTop}
style={wrapperStyle}
contentContainerStyle={[_contentContainerStyle, contentContainerStyle]}
{...omit(this.props, [
// props
'style',
'scrollX',
'upperThreshold',
'lowerThreshold',
'scrollTop',
'scrollLeft',
'scrollWithAnimation',
'enableBackToTop',
'onScrollToUpper',
'onScrollToLower',
'onScroll',
'contentContainerStyle',
// SProps
'horizontal',
'onContentSizeChange',
'onLayout',
'onScroll',
'onScrollEndDrag',
'onMomentumScrollEnd',
'scrollEventThrottle',
'scrollsToTop',
'style',
'contentContainerStyle'
])}
ref={this.$scrollView}
{...scrollElementProps}
>
{children}
</ScrollView>
Expand Down

0 comments on commit 6714e24

Please sign in to comment.