الواجهة LayoutAnimation في React Native
تحرِّك الواجهات لمواضعها الجديدة تلقائيًا عند تطبيق التخطيط التالي.
تعدّ الطّريقة المألوفة لاستخدام هذه الواجهة البرمجية هي استدعاؤها قبل تحديث خطّاف الحالة (state hook) في المكوّنات الوظيفيّة (functional components)، واستدعاء setState ضمن مكونات الصنف.
ويجب وضع الرّايات (flags) التّالية بواسطة UIManager لتعمل هذه الواجهة البرمجيّة على منصّة Android:
if (Platform.OS === 'android') {
if (UIManager.setLayoutAnimationEnabledExperimental) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
}
مثال
إليك المثال التالي (تجربة حية):
import React, { useState } from "react";
import { LayoutAnimation, Platform, StyleSheet, Text, TouchableOpacity, UIManager, View } from "react-native";
if (
Platform.OS === "android" &&
UIManager.setLayoutAnimationEnabledExperimental
) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
const App = () => {
const [expanded, setExpanded] = useState(false);
return (
<View style={style.container}>
<TouchableOpacity
onPress={() => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
setExpanded(!expanded);
}}
>
<Text>Press me to {expanded ? "collapse" : "expand"}!</Text>
</TouchableOpacity>
{expanded && (
<View style={style.tile}>
<Text>I disappear sometimes!</Text>
</View>
)}
</View>
);
};
const style = StyleSheet.create({
tile: {
backgroundColor: "lightgrey",
borderWidth: 0.5,
borderColor: "#d6d7da"
},
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
overflow: "hidden"
}
});
export default App;
التوابع
configureNext()
static configureNext(config, onAnimationDidEnd?)
يجدوِل الحركة لتحدُث في التخطيط التّالي.
المعاملات:
| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
config
|
كائن (object) | نعم | انظر الوصف بالأسفل |
onAnimationDidEnd
|
دالة (function) | لا | تُستدعى عند انتهاء الحركة، مدعومة فقط على منصة IOS |
المعامل config هو كائن مع المفاتيح الموضّحة في الأسفل، يعيد التابع ()create كائنًا موافقًا للكائن config، ويمكن تمرير جميع كائنات الضّبط المسبق Presets، مثل: الكائن config.
duration: المدّة الزّمنيّة بالميلي ثانية.create: مكوّن ضبطconfigاختياريٌّ للتحريك في الواجهات الجديدة.update: مكوّن ضبط (config) اختياريٌّ للواجهات المتحرّكة المحدَّثة.delete: مكوّن ضبط (config) اختياريٌّ للواجهات المتحرّكة المحذوفة.
يتضمن مكوّن الضبط (config) الذي يمرّر إلى create، وupdate، وdelete المفاتيح التالية:
type: نوع الحركةanimation typeالتي ستستخدم.property: خاصيّة التّخطيطlayout property(اختياريٌّ، لكنّه مطلوبٌ فيcreate، وdelete).springDamping: (عددٌ، اختياريٌّ، ويستخدم فقط معtype: Type.spring).initialVelocity: (عددٌ، اختياريٌّ).delay: (عددٌ، اختياريٌّ).duration: (عددٌ، اختياريٌّ).
create()
static create(duration, type, creationProp)
هو تابعٌ مساعدٌ يُنشئ كائنًا يحوي الحقول (create, update, delete)، ليمرَّر للتابع ()configureNext، حيث المُعامل type هو نوع الحركة animation type، والمُعامل creationProp هو خاصيّة التخطيط layout property.
إليك مثال الاستخدام:
import React, { useState } from "react";
import {
View,
Platform,
UIManager,
LayoutAnimation,
StyleSheet,
Button
} from "react-native";
if (
Platform.OS === "android" &&
UIManager.setLayoutAnimationEnabledExperimental
) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
const App = () => {
const [boxPosition, setBoxPosition] = useState("left");
const toggleBox = () => {
LayoutAnimation.configureNext(
LayoutAnimation.create(
500,
LayoutAnimation.Types.spring,
LayoutAnimation.Properties.scaleXY
)
);
setBoxPosition(boxPosition === "left" ? "right" : "left");
};
return (
<View style={styles.container}>
<View style={styles.buttonContainer}>
<Button title="Toggle Layout" onPress={toggleBox} />
</View>
<View
style={[styles.box, boxPosition === "left" ? null : styles.moveRight]}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "flex-start",
justifyContent: "center"
},
box: {
height: 100,
width: 100,
borderRadius: 5,
margin: 8,
backgroundColor: "blue"
},
moveRight: {
alignSelf: "flex-end",
height: 200,
width: 200
},
buttonContainer: {
alignSelf: "center"
}
});
export default App;
import React, { Component } from "react";
import {
View,
Platform,
UIManager,
LayoutAnimation,
StyleSheet,
Button
} from "react-native";
if (
Platform.OS === "android" &&
UIManager.setLayoutAnimationEnabledExperimental
) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
class App extends Component {
state = {
boxPosition: "left"
};
toggleBox = () => {
LayoutAnimation.configureNext(
LayoutAnimation.create(
500,
LayoutAnimation.Types.spring,
LayoutAnimation.Properties.scaleXY
)
);
this.setState({
boxPosition: this.state.boxPosition === "left" ? "right" : "left"
});
};
render() {
return (
<View style={styles.container}>
<View style={styles.buttonContainer}>
<Button title="Toggle Layout" onPress={this.toggleBox} />
</View>
<View
style={[
styles.box,
this.state.boxPosition === "left" ? null : styles.moveRight
]}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "flex-start",
justifyContent: "center"
},
box: {
height: 100,
width: 100,
borderRadius: 5,
margin: 8,
backgroundColor: "blue"
},
moveRight: {
alignSelf: "flex-end",
height: 200,
width: 200
},
buttonContainer: {
alignSelf: "center"
}
});
export default App;
الخاصيات
Types
تستخدم أنواع الحركات من القيم المتعدّدة (enumeration) في التّابع ()create، أو في المعامل config الذي يمرّر إلى create، أو update، أو delete من أجل التّابع ()configureNext، (يمكن أن يستخدم، مثلًا: LayoutAnimation.Types.easeIn)، وهذه الأنواع هي:
springlineareaseInEaseOuteaseIneaseOutkeyboard
Properties
خاصيات التّخطيط من القيم المتعدّدة (enumeration) المستخدمة في الحركات، وتستخدم في التّابع ()create، أو في المعامل (config) الذي يمرّر إلى create، أو update، أو delete من أجل التّابع ()configureNext، (يمكن أن يستخدم مثلًا: LayoutAnimation.Properties.opacity)، وهذه الخاصيات هي:
opacityscaleXscaleYscaleXY
Presets
وهي مجموعة من معاملات (أو مكونات ضبط config) حركةٍ معرّفةٍ مسبقًا، تمرّر للتّابع .configureNext()
| كائن الضبط المسبق | القيمة |
|---|---|
| easeInEaseOut | create(300, 'easeInEaseOut', 'opacity')
|
| linear | create(500, 'linear', 'opacity')
|
| spring | { duration: 700, create: { type: 'linear', property: 'opacity' }, update: { type: 'spring', springDamping: 0.4 }, delete: { type: 'linear', property: 'opacity' } }
|
()easeInEaseOut: يستدعي التّابع()configureNextمعPresets.easeInEaseOut.()liner: يستدعي التّابع()configureNextمعPresets.liner.()spring: يستدعي التّابع()configureNextمعPresets.spring.
إليك مثال الاستخدام التالي:
import React, { useState } from "react";
import {
View,
Platform,
UIManager,
LayoutAnimation,
StyleSheet,
Button
} from "react-native";
if (
Platform.OS === "android" &&
UIManager.setLayoutAnimationEnabledExperimental
) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
const App = () => {
const [firstBoxPosition, setFirstBoxPosition] = useState("left");
const [secondBoxPosition, setSecondBoxPosition] = useState("left");
const [thirdBoxPosition, setThirdBoxPosition] = useState("left");
const toggleFirstBox = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
setFirstBoxPosition(firstBoxPosition === "left" ? "right" : "left");
};
const toggleSecondBox = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.linear);
setSecondBoxPosition(secondBoxPosition === "left" ? "right" : "left");
};
const toggleThirdBox = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
setThirdBoxPosition(thirdBoxPosition === "left" ? "right" : "left");
};
return (
<View style={styles.container}>
<View style={styles.buttonContainer}>
<Button title="EaseInEaseOut" onPress={toggleFirstBox} />
</View>
<View
style={[
styles.box,
firstBoxPosition === "left" ? null : styles.moveRight
]}
/>
<View style={styles.buttonContainer}>
<Button title="Linear" onPress={toggleSecondBox} />
</View>
<View
style={[
styles.box,
secondBoxPosition === "left" ? null : styles.moveRight
]}
/>
<View style={styles.buttonContainer}>
<Button title="Spring" onPress={toggleThirdBox} />
</View>
<View
style={[
styles.box,
thirdBoxPosition === "left" ? null : styles.moveRight
]}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "flex-start",
justifyContent: "center"
},
box: {
height: 100,
width: 100,
borderRadius: 5,
margin: 8,
backgroundColor: "blue"
},
moveRight: {
alignSelf: "flex-end"
},
buttonContainer: {
alignSelf: "center"
}
});
export default App;
import React, { Component } from "react";
import {
View,
Platform,
UIManager,
LayoutAnimation,
StyleSheet,
Button
} from "react-native";
if (
Platform.OS === "android" &&
UIManager.setLayoutAnimationEnabledExperimental
) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
class App extends Component {
state = {
firstBoxPosition: "left",
secondBoxPosition: "left",
thirdBoxPosition: "left"
};
toggleFirstBox = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
this.setState({
firstBoxPosition:
this.state.firstBoxPosition === "left" ? "right" : "left"
});
};
toggleSecondBox = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.linear);
this.setState({
secondBoxPosition:
this.state.secondBoxPosition === "left" ? "right" : "left"
});
};
toggleThirdBox = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
this.setState({
thirdBoxPosition:
this.state.thirdBoxPosition === "left" ? "right" : "left"
});
};
render() {
return (
<View style={styles.container}>
<View style={styles.buttonContainer}>
<Button title="EaseInEaseOut" onPress={this.toggleFirstBox} />
</View>
<View
style={[
styles.box,
this.state.firstBoxPosition === "left" ? null : styles.moveRight
]}
/>
<View style={styles.buttonContainer}>
<Button title="Linear" onPress={this.toggleSecondBox} />
</View>
<View
style={[
styles.box,
this.state.secondBoxPosition === "left" ? null : styles.moveRight
]}
/>
<View style={styles.buttonContainer}>
<Button title="Spring" onPress={this.toggleThirdBox} />
</View>
<View
style={[
styles.box,
this.state.thirdBoxPosition === "left" ? null : styles.moveRight
]}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "flex-start",
justifyContent: "center"
},
box: {
height: 100,
width: 100,
borderRadius: 5,
margin: 8,
backgroundColor: "blue"
},
moveRight: {
alignSelf: "flex-end"
},
buttonContainer: {
alignSelf: "center"
}
});
export default App;