当状态/道具改变时,反应原生动画部分列表跳到顶部
Posted
技术标签:
【中文标题】当状态/道具改变时,反应原生动画部分列表跳到顶部【英文标题】:React native animated section list jumps to top when state/props change 【发布时间】:2019-10-13 11:59:00 【问题描述】:我正在一个带有部分列表组件的本机应用程序中构建一个视图,它上面还有一个标题,它将显示有关列表的聚合数据。滚动时,标题视图应该随着动画缩小。我的所有动画都可以正常工作,但是在使用 onEndreached
属性添加无限滚动时会出现问题。当添加新数据或状态/道具发生变化时,它会跳到列表的顶部。
为了使 SectionList 具有动画效果,我使用 Animated.createAnimatedComponent
对其进行了包装,以创建一个 <AnimatedSectionList />
组件。当它被 Animated 包裹时,问题就出现了。
在下面链接的 gif 中,您可以看到当我向下滚动时它会跳到列表的顶部。这是状态发生变化并且我们开始获取更多数据的时候。 https://monosnap.com/file/2aH5iPF2XcygEz381bpHW9QGPGHA2Z
我尝试使用getItemLayout
来计算列表大小,希望是因为我读到当 react 不知道列表的高度时,它可能会很跳跃。
我还尝试在使用scrollTo
加载新数据后滚动到某个部分,但这也不起作用。我使用 componentDidUpdate
生命周期方法执行此操作,但是当新数据进入时,componentDidUpdate
并没有被一致地调用。
这是我的代码。
const DataItem = [
name: "test name", value: "testvalue" ,
name: "test name", value: "testvalue" ,
name: "test name", value: "testvalue" ,
name: "test name", value: "testvalue" ,
name: "test name", value: "testvalue"
];
const initialSections = [
title: "MY DETAILS", data: DataItem ,
title: "MY COMMUNITY", data: DataItem ,
title: "MY FAMILY", data: DataItem
];
const styles =
item:
flex: 1,
height: 50,
marginTop: 1,
backgroundColor: "#dddddd"
,
sectionHeader:
flex: 1,
height: 20,
marginTop: 1,
backgroundColor: "#00ff00"
;
class Edit extends Component
constructor(props)
super(props);
this.state =
scrollEnabled: true,
scrollY: new Animated.Value(0),
sections: initialSections,
refreshing: false
;
_renderSectionHeader(section)
return (
<View style=styles.sectionHeader>
<Text> section.title </Text>
</View>
);
_renderItem(item)
return (
<View style=styles.item>
<Text>item.name</Text>
</View>
);
handleStateButton()
this.setState( refreshing: true );
fetchMoreData()
this.setState( refreshing: true );
const newData = [...this.state.sections, ...initialSections];
setTimeout(
function()
this.setState( sections: newData, refreshing: false ); .bind(this),
2000
);
render()
const backgroundScrollY = this.state.scrollY.interpolate(
inputRange: [0, 224],
outputRange: [0, -50],
extrapolate: "clamp"
);
const backgroundScrollHeight = this.state.scrollY.interpolate(
inputRange: [0, 224],
outputRange: [1, 0.75],
extrapolate: "clamp"
);
const listScrollY = this.state.scrollY.interpolate(
inputRange: [0, 224],
outputRange: [0, -10],
extrapolate: "clamp"
);
const infoOpacity = this.state.scrollY.interpolate(
inputRange: [0, 0.5, 150],
outputRange: [1, 1, 0],
extrapolate: "clamp"
);
const AnimatedSectionList = Animated.createAnimatedComponent(SectionList);
return (
<View
style=
flex: 1,
// alignItems: "flex-start",
flexDirection: "column"
>
<Animated.View
style=[
position: "relative",
// flex: 1,
// alignSelf: "flex-start",
top: 0,
minHeight: 200,
height: 300,
backgroundColor: "#ddee99",
border: "1px solid #0000FF",
justifyContent: "center",
alignItems: "center"
,
transform: [ scaleY: backgroundScrollHeight ]
]
>
<Animated.Image
source=
uri:
"https://images.unsplash.com/photo-1558901591-3a5f333830dd?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80"
style=[
position: "absolute", backgroundColor: "#cccccc" ,
transform: [ translateY: backgroundScrollY ]
]
blurRadius=1.5
/>
<Text>this.state.refreshing && `Fetching data`</Text>
<Button onPress=this.fetchMoreData title="Get More Data" />
<Button onPress=this.handleStateButton title="Changing State" />
</Animated.View>
<AnimatedSectionList
ref=ref => (this.sectionListRef = ref)
bounces=false
scrollEnabled=this.state.scrollEnabled
style=[
position: "relative" ,
transform: [ translateY: listScrollY ]
]
onScroll=Animated.event(
[ nativeEvent: contentOffset: y: this.state.scrollY ],
listener: this._onScroll.bind(this)
)
sections=this.state.sections
renderSectionHeader=( section ) =>
this._renderSectionHeader(section)
ListHeaderComponent=() => (
<View
style=
flex: 1,
flexDirection: "row",
alignItems: "center",
height: 40,
backgroundColor: "#ff00ff"
>
<Text>List Header</Text>
</View>
)
ListFooterComponent=() => (
<View
style=
flex: 1,
flexDirection: "row",
alignItems: "center",
height: 80,
backgroundColor: "#FF0"
>
<Text>List Footer</Text>
</View>
)
getItemLayout=this.getItemLayout
renderItem=( item ) => this._renderItem(item)
keyExtractor=(item, index) => index
stickySectionHeadersEnabled=true
onEndReachedThreshold=0.75
onEndReached=d =>
this.fetchMoreData();
/>
</View>
);
我希望当 state 或 props 发生变化时列表会保持在当前滚动的位置,但是它会跳到顶部,从而破坏了无限滚动的目的。
对于解决此问题的最佳方法的任何想法,我们将不胜感激。
【问题讨论】:
【参考方案1】:我把
const AnimatedSectionList = Animated.createAnimatedComponent(SectionList);
退出班级,不再跳到榜首
【讨论】:
以上是关于当状态/道具改变时,反应原生动画部分列表跳到顶部的主要内容,如果未能解决你的问题,请参考以下文章