الفرق بين المراجعتين لصفحة: «ReactNative/animated»
رقية-بورية (نقاش | مساهمات) |
رقية-بورية (نقاش | مساهمات) |
||
سطر 355: | سطر 355: | ||
* <code>iterations</code>: عدد مرات تكرار التأثيرات الحركية، والقيمة الافتراضية هي -1 وتعني إعادة التكرار إلى ما لا نهاية. | * <code>iterations</code>: عدد مرات تكرار التأثيرات الحركية، والقيمة الافتراضية هي -1 وتعني إعادة التكرار إلى ما لا نهاية. | ||
=== <code>event()</code> === | === <code>event()</code> === | ||
<syntaxhighlight class="react" lang="javascript">static event(argMapping, config?)</syntaxhighlight> | <syntaxhighlight class="react" lang="javascript">static event(argMapping, config?)</syntaxhighlight> | ||
سطر 376: | سطر 376: | ||
* <code>listener</code>: (اختياري) مستمع غير متزامن. | * <code>listener</code>: (اختياري) مستمع غير متزامن. | ||
* <code>useNativeDriver:</code> تستخدم برنامج التشغيل الأصلي عندما تكون قيمتها <code>true</code>، والقيمة الإفتراضية هي<code>false</code>. | * <code>useNativeDriver:</code> تستخدم برنامج التشغيل الأصلي عندما تكون قيمتها <code>true</code>، والقيمة الإفتراضية هي<code>false</code>. | ||
=== <code>forkEvent()</code> === | === <code>forkEvent()</code> === | ||
مراجعة 11:04، 5 مارس 2021
صُمِّمَت واجهة Animated
البرمجيّة لتسهيل التعبير عن مجموعة متنوعة من أنماط التحريك والتفاعل بطريقة فائقة الأداء. تركّز واجهة Animated
على العلاقات التعريفية بين المدخلات (inputs) والمخرجات (outputs)، مع وجود تحويلات قابلة للضّبط بينهما، إضافة إلى تابعَي start
وstop
بسيطين للتحكم في تنفيذ التّحريك على أساس الوقت.
لإنشاء تأثير حركي عليك أولًا البدء بإنشاء متغيّر Animated.Value
وربطه بواحدة أو أكثر من أنماط المكون المتحركة ودفع التحديثات عبر التأثيرات الحركية باستخدام الدالة ()Animated.timing
.
مثال: استخدام مكون دالِّي (Function component)
عند استخدام المكونات الدالِّية لإنشاء التأثيرات الحركية يجب عدم تعديل قيمة animmated.value
مباشرةً، وإنما يجب استخدام الخطاف useRef
لإرجاع كائن مرجعي قابل للتعديل، وتُهيّئ الخاصية current
للكائن ref
على أنّها المعاملات المبدئية، وتستمر طوال دورة حياة المكون.
import React, { useRef } from "react";
import { Animated, Text, View, StyleSheet, Button } from "react-native";
const App = () => {
// fadeAnim will be used as the value for opacity. Initial Value: 0
const fadeAnim = useRef(new Animated.Value(0)).current;
const fadeIn = () => {
// Will change fadeAnim value to 1 in 5 seconds
Animated.timing(fadeAnim, {
toValue: 1,
duration: 5000
}).start();
};
const fadeOut = () => {
// Will change fadeAnim value to 0 in 5 seconds
Animated.timing(fadeAnim, {
toValue: 0,
duration: 5000
}).start();
};
return (
<View style={styles.container}>
<Animated.View
style={[
styles.fadingContainer,
{
opacity: fadeAnim // Bind opacity to animated value
}
]}
>
<Text style={styles.fadingText}>Fading View!</Text>
</Animated.View>
<View style={styles.buttonRow}>
<Button title="Fade In" onPress={fadeIn} />
<Button title="Fade Out" onPress={fadeOut} />
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center"
},
fadingContainer: {
paddingVertical: 8,
paddingHorizontal: 16,
backgroundColor: "powderblue"
},
fadingText: {
fontSize: 28,
textAlign: "center",
margin: 10
},
buttonRow: {
flexDirection: "row",
marginVertical: 16
}
});
export default App;
مثال: عند استخدام مكون صنفي (Class component) لإنشاء التأثيرات الحركية يجب عدم تعديل قيمة animmated.value
مباشرةً، وإنما يجب تخزينها في صورة متغيّر في الحالة الخاصة بالمكون state
.
import React, { Component } from "react";
import { Animated, Text, View, StyleSheet, Button } from "react-native";
class App extends Component {
// fadeAnim will be used as the value for opacity. Initial Value: 0
state = {
fadeAnim: new Animated.Value(0)
};
fadeIn = () => {
// Will change fadeAnim value to 1 in 5 seconds
Animated.timing(this.state.fadeAnim, {
toValue: 1,
duration: 5000
}).start();
};
fadeOut = () => {
// Will change fadeAnim value to 0 in 5 seconds
Animated.timing(this.state.fadeAnim, {
toValue: 0,
duration: 5000
}).start();
};
render() {
return (
<View style={styles.container}>
<Animated.View
style={[
styles.fadingContainer,
{
opacity: this.state.fadeAnim // Bind opacity to animated value
}
]}
>
<Text style={styles.fadingText}>Fading View!</Text>
</Animated.View>
<View style={styles.buttonRow}>
<Button title="Fade In" onPress={this.fadeIn} />
<Button title="Fade Out" onPress={this.fadeOut} />
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center"
},
fadingContainer: {
paddingVertical: 8,
paddingHorizontal: 16,
backgroundColor: "powderblue"
},
fadingText: {
fontSize: 28,
textAlign: "center",
margin: 10
},
buttonRow: {
flexDirection: "row",
marginVertical: 16
}
});
export default App;
إرجع إلى دليل التأثيرات الحركية لمزيد من الأمثلة.
نظرة عامة
هناك نوعان من البيانات يمكن استخدامهم مع المكون Animated
هما:
()Animated.Value
: للقيم المُفردة.()Animated.ValueXY
: للمُتجهات.
قد ترتبط Animated.Value
بخصائص النمط أو الخواص الأخرى، كما قد تؤدّي قيمة Animated.Value
واحدة العديد من الخصائص.
إنشاء وضبط التأثيرات الحركية
يوفر المكون Animated
ثلاثة أنواع من التأثيرات الحركية يُمثّل كلٌّ منها منحنى حركة معيّن يتحكم في معدَّل تغير قيمة التأثير الحركي من القيمة الأولية إلى القيمة النهائية.
()Animated.decay
: يبدأ بسرعة أولية و يتباطأ تدريجيًا حتى يتوقف.Animated.spring
: تُمثل نموذجًا أساسيًا لفيزياء النوابض.Animated.timing
: يُغيِّر قيمة التأثير الحركي مع مرور الزمن باستخدام دوال التسارع (easing functions).
في أغلب الأحيان تُستعمل الدالة ()timing
، والتي تستخدم منحنى easeInOut
إفتراضيًّا. هذا المنحنى يمثل التسارع التدريجي لجسمٍ ما إلى أقصى سرعة ثم التباطؤ تدريجيًأ حتى التوقف.
التعامل مع التأثيرات الحركية
تبدأ التأثيرات الحركية عن طريق استدعاء الدالة ()start
على التأثير الحركي. تأخذ الدالة start
رد نداء (callback) يُستدعى عند انتهاء التأثير الحركي، حيثُ تكون قيمة المعامل finished
فيه هي true
إذا اكتمل التأثير الحركي بنجاح وحينها يتم استدعاء دالة إيقاف التأثير الحركي stop
، وتكون قيمته false
فيما عدا ذلك.
Animated.timing({}).start(({ finished }) => {
/* completion callback */
});
استخدام برامج التشغيل الأصلية
المُشغِّل الأصلي (Native driver) يُحوِّل جميع المعلومات الخاصة بالتأثير الحركي المُراد إنشاءه إلى شيفرة أصلية (Native Code) قبل بدء التنفيذ، مما يسمج للشيفرة الأصلية بتنفيذ التأثيرات على واجهة المستخدم مباشرة دون المرور بالجسر الذي يربط بين شيفرة React Native والشيفرة الأصلية.
يمكن تفعيل استخدام المشغلات الأصلية من خلال إعطاء الخاصية useNativeDriver
القيمة true
. لمزيد من المعلومات انظر دليل التأثيرات الحركية.
المكونات القابلة للتحريك
يمكن تطبيق التأثيرات الحركية على المكونات القابلة للتحريك فقط، حيث تستطيع هذه المكونات الربط بين القيم المختلفة للخصائص والانتقال بينها بطريقة سلسة عن طريق عمل تحديثات بسيطة للمكون في كلّ مرّة لتجنب إعادة رسمه بالكامل. وكذلك لديهم القابلية لتنفيذ عمليات التنظيف عند حذف المكون من شاشة العرض.
تُستخدم الدالة ()createAnimatedComponent
لإنشاء مكوّنات قابلة للتحريك.
يشمل المكون Animated
المكونات التالية:
Animated.Image
Animated.ScrollView
Animated.Text
Animated.View
Animated.FlatList
Animated.SectionList
تركيب التأثيرات الحركية
يُمكن تركيب التأثيرات الحركية المختلفة لإنشاء تأثيرات أكثر تعقيدًا عن طريق استخدام دوال الدمج.
()nimated.delay
: تؤخِّر بدء تنفيذ التحريك بمقدار زمنيّ معيّن.()Animated.parallel
: تبدأ تنفيذ عدد من التأثيرات الحركية في نفس الوقت.()Animated.squence
: تُنفِّذ التأثيرات الحركية واحدًا تلوَ الآخر بالتسلسل.()Animated.stagger
: تبدأ التأثيرات الحركية متوازيةً ومتسلسلة، ولكن مع تأخيرات متتالية.
ويمكن أيضًأ ربط التأثيرات الحركية ببعضها البعض عن طريق تعيين قيمة الخاصية toValue
لأحد التأثيرات لتكوّن Animated.Value
. انظر تتبع القيم في دليل التأثيرات الحركية.
دمج التأثيرات الحركية
يمكن دمج التأثيرات الحركية عن طريق عمليات الجمع، والطرح، والضرب، والقسمة، وباقي القسمة للحصول على تأثيرات حركية جديدة.
()Animated.add
()Animated.subtract
()Animated.divide
()Animated.modulo
()Animated.multiply
الاستيفاء
تُستخدم الدالة interpolate
لتحديد مدى معيّن للمُدخلات للحصول على مُخرجات في مدى معيّن آخر. حيث تقرأ افتراضيًّا المنحنى خارج المدى المحدَّد، ولكن يمكنك جعله يثبّت قيمة المخرجات. تستخدم الدالة الاستيفاء الخطي افتراضيًّأ ولكنها تدعم جميع وظائف التحريك (easing functions).
التعامل مع الإيماءات والأحداث الأخرى
يمكن تحديد قيم للإيماءات، مثل التحريك أو التمرير، والأحداث الأخرى باستخدام الدالة ()Animated.event
، حيث تُستخدم بنية الخريطة الهيكلية لاستخراج القيم من الكائنات المعقدة.
المستوى الأول عبارة عن مصفوفة تسمح باستخراج البيانات عبر العديد من الوسائط، وتحتوي هذه المجموعة على كائنات متداخلة.
عند التعامل مع إيماءات التمرير الأفقي على سبيل المثال، يمكنك القيام بما يلي من أجل تعيين event.nativeEvent.contentOffset.x
إلى scrollY
.
onScroll={Animated.event(
// scrollX = e.nativeEvent.contentOffset.x
[{ nativeEvent: {
contentOffset: {
x: scrollX
}
}
}]
)}
التوابع
ملاحظة عندما استخدام ValueXY
بدلًا عن Value
لإستقبال المُدخلات، فستُصبح خيارات الضبط (Config options) مجموعة متجهات (vectors) بدلًا عن قيم قياسية (أرقام).
decay()
static decay(value, config)
تُحرك قيمة معيّنة من السرعة الإبتدائية إلى الصفر بمعدَّل معيّن.
يحتوي الكائن config
على خيارات التحريك وهي:
velocity
: (مطلوب) ويمثل السرعة الإبتدائية.deceleration
: معدَّل التباطؤ، والقيمة الافتراضية هي 0.997.isInteraction
: تُحدِّد ما إذا كان التأثير الحركي سيُنشئ مُتحكِّمًا تفاعليًا (interaction handle) فيinteracionManager
أم لا، والقيمة الافتراضية هيtrue
.useNativeDriver
: تستخدم برنامج التشغيل الأصلي عندما تكون قيمتهاtrue
، القيمة الافتراضية هيfalse
.
timing
static timing(value, config)
تُحرك قيمة على منحنى معيّن، تحتوي وِحدة التسارع على العديد من المنحنيات المُعرفَّة مسبقًا، ويمكنك أيضًا تعريف منحنيات جديدة باستخدام دوال معيّنة.
يحتوي الكائن config
على خيارات التحريك وهي:
duration
: تُحدّد المدة الزمنية (بالملي ثانية) التي يستغرقها التأثير الحركي للوصول لنقطة النهاية، والقيمة الافتراضية لها هي 500.easing
: تُحدّد دالة التسارع التي بدورها تُعرِّف منحى التأثير الحركي. القيمة الافتراضية هي(Easing.inOut(Easing.ease
.delay
: تؤخّر بدء التأثير الحركي بمقدار زمني محدد. القيمة الافتراضية هي صفر.isInteraction
: تُحدد ما إذا كان التأثير الحركي سيُنشئ مُتحكِّم تفاعلي (interaction handle) فيinteracionManager
أم لا، والقيمة الافتراضية هيtrue
.useNativeDriver
: تُستخدم برنامج التشغيل الأصلي عندما تكون قيمتهاtrue
. القيمة الافتراضية هيfalse
.
spring
static spring(value, config)
يُحرِّك القيمة وفقًأ لنموذج النابض القائم على الحركة التذبذبية التوافقية.
ملاحظة يمكنك تعريف واحد فقط من الخيارات التالية: bounciness/speed
أو tension/friction
أو stiffness/damping/mass
.
تُطابق friction/tension
وbounciness/speed
خيارات نموذج النابض الخاص بفيسبوك وRebound وOrigami.
friction
: يتحكم في النسبةbounciness/overshoot
، والقيمة الافتراضية هي 7.tension
: يتحكم في السرعة، والقيمة الافتراضية هي 40.- speed`: يتحكم في سرعة التأثير الحركي، والقيمة الافتراضية هي 12.
- bounciness`: يتحكم في القفزات، والقيمة الافتراضية هي 8.
تحديد المعاملات stiffness/damping/mass
يجعل Animated.spring
تستخدم نموذج نابض تحليلي يعتمد على معاطلات الحركة التذبذبية التوافقية. هذا الأسلوب يستعمل قوانين الفيزياء ويُحاكي تطبيق CASpringAnimation
على نظام iOS.
stiffness
: يُحدد معامل صلابة النابض، والقيمة الافتراضية هي 100.damping
: يُحدد كيف تتباطأ سُرعة حركة النابض بسبب قوى الاحتكاك، والقيمة الافتراضية هي 10.mass
: تُحدد كتلة الجسم المُعَلَّق على النابض، والقيمة الافتراضية هي 1.
معاملات اضافية
velocity
: السرعة الابتدائية للجسم المعلَّق على النابض. القيمة الافتراضية هي صفر.overshootClamping
: قيمة منطقية تشير إلى ما إذا كان ينبغي تثبيت النابض وإيقاف الارتداد. القيمة الافتراضية هيfalse
.restDisplacementThreshold
: يحدد قيمة عتبة الإزاحة من السكون والتي يجب اعتبار النابض تحتها في حالة سكون (عدم حركة). القيمة الافتراضية هي 0.001.restSpeedThreshold
: يحدد السرعة التي يعتبر عندها النابض في حالة سكون، وتقاس بوحدات البكسل في الثانية، أمّا القيمة الافتراضية فهي 0.001.delay
: تؤخر بدء التأثير الحركي بمقدار زمني محدد، والقيمة الافتراضية هي الصفر.isInteraction
: تُحدد ما إذا كان التأثير الحركي سيُنشئ مُتحكِّم تفاعلي (interaction handle) فيinteracionManager
أم لا. القيمة الافتراضية هيtrue
.useNativeDriver
: تستخدم برنامج التشغيل الأصلي عندما تكون قيمتهاtrue
. القيمة الافتراضية هيfalse
.
add()
تُنشئ تأثير حركي جديد ناتج عن دمج تأثيرين حركيين مع بعضهما البعض.
static add(a,b)
substract
تُنشئ تأثير حركي جديد عن طريق طرح التأثير الحركي الثاني من التأثير الحركي الأول.
static subtract(a,b)
divide()
تُنشئ تأثير حركي جديد عن طريق قسمة التأثير الحركي الأول على التأثير الحركي الثاني.
static divide(a,b)
multiply()
تُنشئ تأثير حركي جديد عن طريق ضرب التأثير الحركي الأول في التأثير الحركي الثاني.
static multiply(a,b)
modulo()
تُنشئ تأثير حركي جديد عن طريق أخذ باقي قسمة التأثير الحركي الأول على التأثير الحركي الثاني.
static modulo(a,b)
diffClamp
تُنشئ قيمةً متحركةً جديدةً محدودة بين قيمتين، ويُستخدم الفرق بين القيمة الأخيرة، لذلك فحتى إذا كانت القيمة بعيدةً عن الحدود فستبدأ في التغيير عندما تبدأ القيمة في الاقتراب مرّةً أخرى.
هذا مفيد مع أحداث التمرير، فلإظهار شريط التنقل عند التمرير لأعلى مثلًا وإخفاءه عند التمرير لأسفل، نستخدم ما يلي:
static diffClamp(a, min, max)
delay()
تؤخّر بدء التأثير الحركي بمقدار زمني محدَّد.
static delay(time)
sequence()
تُنفذ عددًا من التأثيرات الحركية متتابعةً الواحدة تلو الآخرى.
static sequence(animations)
parallel()
تنفذ عددًا من التأثيرات الحركية (مصفوفة من الحركات) في نفس الوقت متوازيةً، وعند توقف تأثير حركي واحد افتراضيًا فستتوقف جميع التأثيرات الحركية الأخرى، ويمكن تجاوز هذا السلوك باستخدام المُعرِّف stopTogether
.
static parallel(animations, config?)
stagger()
مصفوفة من التأثيرات الحركية تنفذ متوازيةً (متداخلة)، ولكنها تبدأ تسلسليًا بتأخيرات معيّنة مناسبة لعمل تأثيرات زائدة.
loop()
تُكرر التأثيرات الحركية باستمرار، إذ يحدث التكرار دون حظر سلسلة جافا سكريبت، وفي حال كانت قيمة الخاصية useNativeDriver
هي true
.
من الممكن منع الحلقات للمكونات المبنية على المكون VirtualizedList
من عرض المزيد من الصفوف أثناء تشغيل التأثير الحركي، ويمكن إصلاح هذا عن طريق إعطاء الخاصية isInteraction
القيمةَ false
.
iterations
: عدد مرات تكرار التأثيرات الحركية، والقيمة الافتراضية هي -1 وتعني إعادة التكرار إلى ما لا نهاية.
event()
static event(argMapping, config?)
تأخذ مصفوفة بيانات وتستخرج قيم التأثيرات الحركية من هذه البيانات. ثم تستدعى الدالة setValue
على المخرجات المعيّنة.
*مثال
onScroll={Animated.event(
[{nativeEvent: {contentOffset: {x: this._scrollX}}}],
{listener: (event) => console.log(event)}, // Optional async listener
)}
...
onPanResponderMove: Animated.event([
null, // raw event arg ignored
{dx: this._panX}], // gestureState arg
{listener: (event, gestureState) => console.log(event, gestureState)}, // Optional async listener
),
يحتوي الكائن config
على الخيارات التالية:
listener
: (اختياري) مستمع غير متزامن.useNativeDriver:
تستخدم برنامج التشغيل الأصلي عندما تكون قيمتهاtrue
، والقيمة الإفتراضية هيfalse
.
forkEvent()
static forkEvent(event, listener)
واجهة برمجية حديثة لمراقبة الأحداث المتحركة التي تُمرّر في صورة معاملات، حيث تسمح بإضافة مستمع جديد إلى المستمع AnimatedEvent
الموجود مسبقًا، فإذا كان animatedEvent
مستمعًا لجافا سكريبت فسيدمج المستعمان معًا في مستمع واحد؛ أمّا إذا كان animatedEvent
خالي (أي قيمته null
أو undefined
)، فسيُعيَّن مستمع جافا سكريبت مباشرةً. تستخدم القيم مباشرةً إذا كان ذلك ممكنًا.
unforkEvent()
static unforkEvent(event, listener)
start()
static start([callback]: ?(result?: {finished: boolean}) => void)
تبدأ التأثيرات الحركية عندما تُستدعى الدالة ()start
، والتي بدورها تأخذ دالة أخرى تُستدعى عند إيقاف التأثير الحركي عن طريق الدالة ()stop
.
الاسم | النوع | مطلوب | الوصف |
---|---|---|---|
callback | ({result?: {finished: boolean)? | لا | تُستدعى الدالة عندما يوقّف التأثير الحركي باستخدام الدالة stop أو عن انتهائه.
|
مثال
Animated.timing({}).start(({ finished }) => {
/* completion callback */
});
stop()
static stop()
توقف جميع التأثيرات الحركية قيد التنفيذ.
reset()
static reset()
توقف جميع التأثيرات الحركية قيد التنفيذ وتعيد قيمتها للقيمة الابتدائية.
مرجع الخاصيّات
value
القيمة الأساسية للتأثيرات الحركية، وعادةً ما تأخذ القيمة صفر
في البداية.
new Animated.Value(0)
مزيد من المعلومات حول Animated.Value
.
valueXY()
كائن ثُنائي الابعاد يستخدم لإنشاء التأثيرات الحركية ثنائية الابعاد.
مزيد من المعلومات حول Animated.ValueXY
.
Interpolation
صُدّرت لاستخدام أنواع الاستيفاء في التدفق
Node
جميع القيم المتحركة مشتقة من هذا الصنف، وذلك لسهولة فحص أنواع البيانات عليه.
createAnimatedComponent
تستخدم لجعل المكونات قابلة للتحريك.
attachNativeEvent
واجهة برمجية ضرورية لاضافة القيم المتحرِّكة للأحداث في مكون العرض. يُفضّل استخدام Animated.event
مع الخاصية useNativeDriver: true
.