陣營本地陣圖插入我寫了一個動畫列表組件:在開始
import React, {Component} from 'react';
import PropType from 'prop-types';
import * as Animatable from 'react-native-animatable-promise';
import {FlatList, View} from 'react-native';
import {observable, action, runInAction} from "mobx"
import {observer} from 'mobx-react';
import TransitionGroup, {FadeInOutTransition} from 'react-native-transitiongroup';
import arrayDiff from 'arraydiff';
class AnimatedListItem extends Component {
static propTypes = {
animationOut: PropType.string.isRequired,
animationIn: PropType.string.isRequired,
duration: PropType.number.isRequired
};
tempHeight = 0;
locked = false;
componentDidAppear(callback) {
this.componentWillEnter(callback);
}
componentDidEnter(callback) {
this.refs.Item[this.props.animationIn](this.props.duration).then(() => callback());
}
componentWillLeave(callback) {
this.locked = true;
this.refs.Item.stopAnimation();
this.refs.Item.transition({height: this.tempHeight, opacity: 1, scale: 1}, {height: 0, opacity: 0, scale: 0}, this.props.duration, 'ease').then(callback).catch(console.error);
//this.refs.Item[this.props.animationOut](this.props.duration).then(() => callback());
}
_onLayout(event) {
const {height} = event.nativeEvent.layout;
if (!this.locked) this.tempHeight = height;
}
render() {
return (<Animatable.View ref='Item' onLayout={this._onLayout.bind(this)}>
{this.props.children}
</Animatable.View>);
}
}
@observer
class AnimatedList extends Component {
static propTypes = {
data: PropType.array.isRequired,
renderItem: PropType.func.isRequired,
keyExtractor: PropType.func.isRequired,
inAnimation: PropType.string.isRequired,
outAnimation: PropType.string.isRequired,
style: PropType.any,
duration: PropType.number,
delay: PropType.number
};
@observable keyExtractor = this.props.keyExtractor;
@observable data = [];
@observable duration = this.props.duration || 1000;
@observable outAnimation = this.props.outAnimation;
@observable inAnimation = this.props.inAnimation;
_renderItem = this.props.renderItem;
delay = this.props.delay || 100;
queue;
actionIsRunning = false;
componentDidMount() {
this.setProps(this.props);
}
componentWillReceiveProps(props) {
this.setProps(props);
}
setProps(props) {
requestAnimationFrame(() => {
if (this.actionIsRunning) {
this.queue = props;
return;
}
this.queue = null;
this.actionIsRunning = true;
runInAction(() => {
this.duration = props.duration || 1000;
this.outAnimation = props.outAnimation;
this.inAnimation = props.inAnimation;
this.delay = props.delay;
this.keyExtractor = props.keyExtractor;
});
const differences = arrayDiff(this.data.toJS(), props.data.toJS(), (a, b) => {
const aKey = this.keyExtractor(a);
const bKey = this.keyExtractor(b);
return aKey === bKey;
});
console.log("ADIFF: " + JSON.stringify(differences));
this.applyDifferences(differences).then(() => {
console.log("NEWLIST: " + JSON.stringify(this.data));
this.actionIsRunning = false;
if (this.queue) this.setProps.bind(this)(this.queue);
}).catch(e => console.error(e));
});
}
async applyDifferences(differences) {
for (let diff of differences) {
if (!diff.type) continue;
await new Promise((resolve) => requestAnimationFrame(resolve));
if (diff.type === 'remove' && diff.index !== undefined && diff.howMany !== undefined) {
runInAction(() => {
this.data.splice(diff.index, diff.howMany);
});
}
if (diff.type === 'move' && diff.from !== undefined && diff.to !== undefined) {
runInAction(() => {
moveInThisArray(this.data, diff.from, diff.to);
});
}
if (diff.type === 'insert' && diff.index !== undefined && Array.isArray(diff.values)) {
const argArray = [diff.index, 0];
for (let value of diff.values) {
argArray.push(value);
}
runInAction(() => {
this.data.splice.apply(this.data, argArray);
});
}
await new Promise((resolve) => setTimeout(resolve, this.delay));
}
await new Promise((resolve) => setTimeout(resolve, this.duration));
}
/**
* @typedef {Object} FlatListRenderInfo
* @property {Object} item
* @property {Number} index
* @property {Object} separators
*/
/**
*
* @param {FlatListRenderInfo} info
*/
renderItem(info) {
//console.log(this.keyExtractor(info.item));
return (
<AnimatedListItem animationOut={this.outAnimation} animationIn={this.inAnimation} duration={this.duration}
key={this.keyExtractor(info.item)}>
{this._renderItem(info)}
</AnimatedListItem>);
}
render() {
return (<TransitionGroup>
{this.data.toJS().map((item, index) => {
return this.renderItem({
item: item,
index: index,
separators: {}
});
})}
</TransitionGroup>)
}
}
function moveInThisArray(arr, old_index, new_Index) {
if (new_Index >= arr.length) {
let k = new_Index - arr.length;
while ((k--) + 1) {
arr.push(undefined);
}
}
arr.splice(new_Index, 0, arr.splice(old_index, 1)[0]);
return arr;
}
export default AnimatedList;
最我的代碼按預期工作。但是我有一個小問題,如果我在數組的開頭添加一個元素,它會在我的列表的末尾呈現。我想也許我的使用Array.map
是錯誤的。數組沒有問題,如果我將數組打印到控制檯,它有正確的順序。我在最後一個問題中已經注意到了這個問題,但是忽略了它,因爲在我的最後一個項目中,元素的順序並不重要,但是這次它很重要。是否有替代使用Array.map
來解決問題?或者我該怎麼做?
你有沒有嘗試使用unshift而不是push? –
因爲它不應該在每一次開始時都推動。開始只是一個例子。也可能在第二個位置等。 –