الفرق بين المراجعتين ل"ReactNative/flexbox"

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث
ط
 
(5 مراجعات متوسطة بواسطة مستخدمين اثنين آخرين غير معروضة)
سطر 1: سطر 1:
<noinclude>{{DISPLAYTITLE:التخطيط باستخدام Flexbox في React Native}}</noinclude>
+
<noinclude>{{DISPLAYTITLE:التخطيط باستخدام Flexbox في React Native}}</noinclude>يمكن للمكوّن تحديد تخطيط layout أبنائه باستخدام [[:تصنيف:CSS Flexbox|خوارزمية Flexbox]] التي صُمِّمَت لتوفير تخطيط متناسق على أحجام شاشات مختلفة. سنعتمد على كلّ من الخاصيّات ‎<code>flexDirection</code>‎، و ‎<code>alignItems</code>‎ و ‎<code>justifyContent</code>‎ للحصول على التصميم الصحيح.
  
==التخطيط Layout باستخدام Flexbox==
+
يعمل [[CSS/flex|Flexbox]] في React Native كما يعمل في [[CSS/flex|CSS]] على الويب مع اختلافات طفيفة، إذ تختلف الإعدادات الافتراضية، فالقيمة الافتراضيّة للخاصيّة ‎<code>flexDirection</code>‎ هي ‎<code>column</code>‎ عوضًا عن ‎<code>row</code>‎، والقيمة الافتراضيّة للخاصيّة ‎<code>alignContent</code>‎ هي ‎<code>flex-start</code>‎ عوضًا عن <code>stretch‎</code>، والقيمة الافتراضيّة للخاصيّة ‎<code>flexShrink</code>‎ هي ‎<code>0</code>‎ عوضًا عن <code>1‎</code>، ولا تدعم خاصيّة ‎<code>flex</code>‎ إلّا عددًا واحدًا كقيمة.
يمكن للمكوّن تحديد تخطيط أبنائه باستخدام [[:تصنيف:CSS Flexbox|خوارزمية Flexbox]] التي صُمِّمَت لتوفير تخطيط متناسق على أحجام شاشات مختلفة.
 
  
ستعتمد عادةً على كلّ من الخاصيّات ‎<code>flexDirection</code>‎، و‎<code>alignItems</code>‎، و‎<code>justifyContent</code>‎ للحصول على التصميم الصحيح.
+
== الخاصية <code>flex</code> ==
 +
ستحدّد الخاصية <code>[[ReactNative/layout props#flex|flex]]</code> كيف "تملأ" عناصرك المساحةَ المتاحة على طول المحور الرئيسي main axis، إذ تُقسَم المساحة وفقًا للخاصية flex لكل عنصر.
  
يعمل Flexbox في React Native كما يعمل في [[CSS/flex|CSS]] على الويب مع اختلافات طفيفة، حيث تختلف الإعدادات الافتراضية، إذ أنّ القيمة الافتراضيّة للخاصيّة ‎<code>flexDirection</code>‎ هي ‎<code>column</code>‎ عوضًا عن ‎<code>row</code>‎، والقيمة الافتراضيّة للخاصيّة ‎<code>alignContent</code>‎ هي ‎<code>flex-start</code>‎ عوضًا عن <code>stretch‎</code>، والقيمة الافتراضيّة للخاصيّة ‎<code>flexShrink</code>‎ هي ‎<code>0</code>‎ عوضًا عن <code>1‎</code>، وخاصيّة ‎<code>flex</code>‎ لا تدعم إلّا عددًا واحدًا كقيمة.
+
تكون الواجهات (العروض) views ذات اللون الأحمر والأصفر والأخضر في المثال التالي كلها عناصرًا أبناء في حاوية الواجهة التي لها الخاصية <code>flex: 1</code>. تستخدم الواجهة ذات اللون الأحمر الخاصية <code>flex: 1</code>، وتستخدم الواجهة ذات اللون الأصفر الخاصية <code>flex: 2</code>، وتستخدم الواجهة ذات اللون الأخضر الخاصية <code>flex: 3</code>، أي 1 + 2 + 3 = 6، مما يعني أن الواجهة الحمرات ستحصل على <code>1/6</code> من المساحة، وتحصل الواجهة الصفراء على <code>2/6</code> من المساحة، والخضراء على <code>3/6</code> من المساحة.
  
== الخاصية Flex ==
+
إليك المثال التالي ([https://snack.expo.dev/@hsoubwiki/flex-example تجربة حية]):<syntaxhighlight lang="javascript">
ستحدّد الخاصية <code>[[ReactNative/layout props#flex|flex]]</code> كيف "تملأ" عناصرك المساحةَ المتاحة على طول المحور الرئيسي، حيث تُقسَم المساحة وفقًا للخاصية flex لكل عنصر.
 
 
 
تكون العروض views ذات اللون الأحمر والأصفر والأخضر في المثال التالي كلها عناصرًا أبناء في عرض الحاوية التي لها الخاصية <code>flex: 1</code>. يستخدم العرض ذو اللون الأحمر الخاصية <code>flex: 1</code>، ويستخدم العرض ذو اللون الأصفر الخاصية <code>flex: 2</code>، ويستخدم العرض ذو اللون الأخضر الخاصية <code>flex: 3</code>، أي 1 + 2 + 3 = 6، مما يعني أن العرض الأحمر سيحصل على <code>1/6</code> من المساحة، ويحصل العرض الأصفر على <code>2/6</code> من المساحة، والأخضر على <code>3/6</code> من اللمساحة.<syntaxhighlight lang="javascript">
 
 
import React from "react";
 
import React from "react";
 
import { StyleSheet, Text, View } from "react-native";
 
import { StyleSheet, Text, View } from "react-native";
سطر 39: سطر 36:
  
 
==الخاصية <code>flexDirection</code>==
 
==الخاصية <code>flexDirection</code>==
تتحكّم الخاصية <code>[[ReactNative/layout props#flexDirection|flexDirection]]</code> في اتجاه ترتيب أبناء عقدةٍ ما، حيث يُشار إلى هذا الاتجاه أيضًا بالمحور الرئيسي main axis. يُشمَّى المحور cross axis هو المحور المتعامد مع المحور الرئيسي، أو المحور الذي توضَع فيه الأسطر التي يمكنها الالتفاف.
+
تتحكّم الخاصية <code>[[ReactNative/layout props#flexDirection|flexDirection]]</code> في اتجاه ترتيب أبناء عقدةٍ ما، حيث يُشار إلى هذا الاتجاه أيضًا بالمحور الرئيسي main axis. المحور cross axis هو المحور المتعامد مع المحور الرئيسي، أو المحور الذي توضَع فيه الأسطر التي يمكنها الالتفاف على أكثر من سطر.
  
 
* <code>column</code> (القيمة الافتراضية): تحاذي هذه القيمة العناصر الأبناء من الأعلى إلى الأسفل. إذا كان الالتفاف wrapping مفعَّلًا، فسيبدأ السطر التالي على يمين العنصر الأول أعلى الحاوية.
 
* <code>column</code> (القيمة الافتراضية): تحاذي هذه القيمة العناصر الأبناء من الأعلى إلى الأسفل. إذا كان الالتفاف wrapping مفعَّلًا، فسيبدأ السطر التالي على يمين العنصر الأول أعلى الحاوية.
سطر 46: سطر 43:
 
* <code>row-reverse</code>: تحاذي هذه القيمة العناصر الأبناء من اليمين إلى اليسار. إذا كان الالتفاف wrapping مفعَّلًا، فسيبدأ السطر التالي أسفل العنصر الأول على يمين الحاوية.
 
* <code>row-reverse</code>: تحاذي هذه القيمة العناصر الأبناء من اليمين إلى اليسار. إذا كان الالتفاف wrapping مفعَّلًا، فسيبدأ السطر التالي أسفل العنصر الأول على يمين الحاوية.
  
اطّلع على المزيد من [https://yogalayout.com/docs/flex-direction/ الخاصية <code>flexDirection</code>].<syntaxhighlight lang="javascript">
+
اطّلع على مزيد من المعلومات حول [[CSS/flex-direction|الخاصية <code>flexDirection</code>]] من توثيق [[CSS]].
import React, { Component } from 'react';
+
 
import { AppRegistry, View } from 'react-native';
+
إليك المثال التالي ([https://snack.expo.dev/@hsoubwiki/flex-direction تجربة حية]):<syntaxhighlight lang="javascript">
 +
import React, { useState } from "react";
 +
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
 +
 
 +
const FlexDirectionBasics = () => {
 +
  const [flexDirection, setflexDirection] = useState("column");
 +
 
 +
  return (
 +
    <PreviewLayout
 +
      label="flexDirection"
 +
      values={["column", "row", "row-reverse", "column-reverse"]}
 +
      selectedValue={flexDirection}
 +
      setSelectedValue={setflexDirection}
 +
    >
 +
      <View
 +
        style={[styles.box, { backgroundColor: "powderblue" }]}
 +
      />
 +
      <View
 +
        style={[styles.box, { backgroundColor: "skyblue" }]}
 +
      />
 +
      <View
 +
        style={[styles.box, { backgroundColor: "steelblue" }]}
 +
      />
 +
    </PreviewLayout>
 +
  );
 +
};
 +
 
 +
const PreviewLayout = ({
 +
  label,
 +
  children,
 +
  values,
 +
  selectedValue,
 +
  setSelectedValue,
 +
}) => (
 +
  <View style={{ padding: 10, flex: 1 }}>
 +
    <Text style={styles.label}>{label}</Text>
 +
    <View style={styles.row}>
 +
      {values.map((value) => (
 +
        <TouchableOpacity
 +
          key={value}
 +
          onPress={() => setSelectedValue(value)}
 +
          style={[
 +
            styles.button,
 +
            selectedValue === value && styles.selected,
 +
          ]}
 +
        >
 +
          <Text
 +
            style={[
 +
              styles.buttonLabel,
 +
              selectedValue === value && styles.selectedLabel,
 +
            ]}
 +
          >
 +
            {value}
 +
          </Text>
 +
        </TouchableOpacity>
 +
      ))}
 +
    </View>
 +
    <View style={[styles.container, { [label]: selectedValue }]}>
 +
      {children}
 +
    </View>
 +
  </View>
 +
);
  
export default class FlexDirectionBasics extends Component {
+
const styles = StyleSheet.create({
   render() {
+
  container: {
    return (
+
    flex: 1,
       <View style={{flex: 1, flexDirection: 'row'}}>
+
    marginTop: 8,
        <View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
+
    backgroundColor: "aliceblue",
        <View style={{width: 50, height: 50, backgroundColor: 'skyblue'}} />
+
  },
        <View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} />
+
  box: {
      </View>
+
    width: 50,
    );
+
    height: 50,
  }
+
  },
 +
  row: {
 +
    flexDirection: "row",
 +
    flexWrap: "wrap",
 +
  },
 +
  button: {
 +
    paddingHorizontal: 8,
 +
    paddingVertical: 6,
 +
    borderRadius: 4,
 +
    backgroundColor: "oldlace",
 +
    alignSelf: "flex-start",
 +
    marginHorizontal: "1%",
 +
    marginBottom: 6,
 +
    minWidth: "48%",
 +
    textAlign: "center",
 +
  },
 +
  selected: {
 +
    backgroundColor: "coral",
 +
    borderWidth: 0,
 +
  },
 +
  buttonLabel: {
 +
    fontSize: 12,
 +
    fontWeight: "500",
 +
    color: "coral",
 +
  },
 +
  selectedLabel: {
 +
    color: "white",
 +
  },
 +
  label: {
 +
    textAlign: "center",
 +
    marginBottom: 10,
 +
    fontSize: 24,
 +
  },
 +
});
 +
 
 +
export default FlexDirectionBasics;
 +
</syntaxhighlight>
 +
 
 +
== اتجاه التخطيط Layout Direction ==
 +
تحدّد خاصية اتجاه التخطيط اتجاهَ توزيع الأبناء والنص ضمن تسلسلٍ هرمي، كما يؤثّر اتجاه التخطيط أيضًا على ما تشير إليه بداية <code>start</code> ونهاية <code>end</code> الأطراف. يحدّد React Native اتجاه التخطيط على القيمة LTR افتراضيًا، حيث تشير البداية <code>start</code> إلى اليسار وتشير النهاية <code>end</code> إلى اليمين في هذه الحالة.
 +
 
 +
* <code>LTR</code> (القيمة الافتراضية): يوضَع النص والأبناء من اليسار إلى اليمين باستخدام هذه القيمة، حيث تُطبَّق الهوامش والحاشية المُطبَّقة على بداية العنصر من الجانب الأيسر.
 +
* <code>RTL</code>: يُوضَع النص والأبناء من اليمين إلى اليسار باستخدام هذه القيمة، حيث تُطبَّق الهوامش والحاشية المُطبَّقة على بداية العنصر من الجانب الأيمن.
 +
إليك المثال التالي ([https://snack.expo.dev/@hsoubwiki/flex-direction-02 تجربة حية]):<syntaxhighlight lang="javascript">
 +
import React, { useState } from "react";
 +
import { View, TouchableOpacity, Text, StyleSheet } from "react-native";
 +
 
 +
const DirectionLayout = () => {
 +
   const [direction, setDirection] = useState("ltr");
 +
 
 +
  return (
 +
    <PreviewLayout
 +
       label="direction"
 +
      selectedValue={direction}
 +
      values={["ltr", "rtl"]}
 +
      setSelectedValue={setDirection}>
 +
      <View
 +
        style={[styles.box, { backgroundColor: "powderblue" }]}
 +
      />
 +
      <View
 +
        style={[styles.box, { backgroundColor: "skyblue" }]}
 +
      />
 +
      <View
 +
        style={[styles.box, { backgroundColor: "steelblue" }]}
 +
      />
 +
    </PreviewLayout>
 +
  );
 
};
 
};
  
// تخطّ هذا السطر إن كنت تستعمل أداة
+
const PreviewLayout = ({
// Create React Native App
+
  label,
AppRegistry.registerComponent('AwesomeProject', () => FlexDirectionBasics);
+
  children,
 +
  values,
 +
  selectedValue,
 +
  setSelectedValue,
 +
}) => (
 +
  <View style={{ padding: 10, flex: 1 }}>
 +
    <Text style={styles.label}>{label}</Text>
 +
    <View style={styles.row}>
 +
      {values.map((value) => (
 +
        <TouchableOpacity
 +
          key={value}
 +
          onPress={() => setSelectedValue(value)}
 +
          style={[
 +
            styles.button,
 +
            selectedValue === value && styles.selected,
 +
          ]}
 +
        >
 +
          <Text
 +
            style={[
 +
              styles.buttonLabel,
 +
              selectedValue === value && styles.selectedLabel,
 +
            ]}
 +
          >
 +
            {value}
 +
          </Text>
 +
        </TouchableOpacity>
 +
      ))}
 +
    </View>
 +
    <View style={[styles.container, { [label]: selectedValue }]}>
 +
      {children}
 +
    </View>
 +
  </View>
 +
);
 +
 
 +
const styles = StyleSheet.create({
 +
  container: {
 +
    flex: 1,
 +
    marginTop: 8,
 +
    backgroundColor: "aliceblue",
 +
  },
 +
  box: {
 +
    width: 50,
 +
    height: 50,
 +
  },
 +
  row: {
 +
    flexDirection: "row",
 +
    flexWrap: "wrap",
 +
  },
 +
  button: {
 +
    paddingHorizontal: 8,
 +
    paddingVertical: 6,
 +
    borderRadius: 4,
 +
    backgroundColor: "oldlace",
 +
    alignSelf: "flex-start",
 +
    marginHorizontal: "1%",
 +
    marginBottom: 6,
 +
    minWidth: "48%",
 +
    textAlign: "center",
 +
  },
 +
  selected: {
 +
    backgroundColor: "coral",
 +
    borderWidth: 0,
 +
  },
 +
  buttonLabel: {
 +
    fontSize: 12,
 +
    fontWeight: "500",
 +
    color: "coral",
 +
  },
 +
  selectedLabel: {
 +
    color: "white",
 +
  },
 +
  label: {
 +
    textAlign: "center",
 +
    marginBottom: 10,
 +
    fontSize: 24,
 +
  },
 +
});
 +
 
 +
export default DirectionLayout;
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
==الخاصية ‎<code>justifyContent</code>‎==
 
==الخاصية ‎<code>justifyContent</code>‎==
تُحدِّد الخاصية <code>justifyContent</code>‎ كيفيّة توزيع المسافة بين العناصر وحولها على امتداد المحور الرئيسي. هل تريد توزيع الأطفال بجوار بعضها بدءًا من بداية المحور الرئيسي، أو المركز، أو في النهاية، أو متباعدةً بالتساوي؟ الخيارات المتاحة هي ‎<code>flex-start</code>‎، و‎<code>center</code>‎، و‎<code>flex-end</code>‎، و‎<code>space-around</code>‎، و‎<code>space-between</code>‎، ‎<code>space-evenly</code>. جرّب تعديل قيمة الخاصيّة ‎<code>justifyContent</code>‎ وانظر النتيجة لتفهم آلية التنسيق، يُمكنك كذلك تغيير قيمة ‎<code>flexDirection</code>إلى <code>row</code>‎ لتفهم أكثر:
+
تحدّد الخاصية <code>[[ReactNative/layout props#justifyContent|justifyContent]]</code> كيفية محاذاة المكونات الأبناء وفق محور الحاوية الرئيسي، حيث يمكنك استخدام هذه الخاصية لتوسيط ابنٍ أفقيًا ضمن حاوية مع ضبط الخاصية <code>flexDirection</code> على القيمة <code>row</code> أو عموديًا ضمن حاوية مع ضبط الخاصية <code>flexDirection</code> على القيمة <code>column</code>.
 +
 
 +
* <code>flex-start</code> (القيمة الافتراضية): تحاذي أبناء الحاوية إلى بداية محور الحاوية الرئيسي.
 +
* <code>flex-end</code>: تحاذي هذه القيمة الحاوية إلى نهاية محور الحاوية الرئيسي.
 +
* <code>center</code>: تحاذي أبناء الحاوية إلى مركز محور الحاوية الرئيسي.
 +
* <code>space-between</code>: تكون المسافة بين الأبناء متساوية على طول محور الحاوية الرئيسي، وتُوزَّع المسافة المتبقية بين الأبناء.
 +
* <code>space-around</code>: تكون المسافة متساوية بين الأبناء على طول محور الحاوية الرئيسي، وتُوزَّع المسافة المتبقية حول الأبناء، فإن استخدام القيمة <code>space-around</code> سيؤدي إلى توزيع المسافة المتبقية على بداية الابن الأول ونهاية الابن الأخير.
 +
* <code>space-evenly</code>: يُوزَّع الأبناء بمسافة متساوية ضمن حاوية المحاذاة على طول المحور الرئيسي. التباعد بين كل زوج من العناصر المتجاورة، وطرف البداية الرئيسية والعنصر الأول، وطرف النهاية الرئيسية والعنصر الأخير، كلها متماثلة تمامًا.
 +
 
 +
اطّلع على مزيد من المعلومات حول [[CSS/justify-content|الخاصية <code>justifyContent</code>]] من توثيق [[CSS]].
 +
 
 +
إليك المثال التالي ([https://snack.expo.dev/@hsoubwiki/justify-content تجربة حية]):<syntaxhighlight lang="javascript">
 +
import React, { useState } from "react";
 +
import { View, TouchableOpacity, Text, StyleSheet } from "react-native";
 +
 
 +
const JustifyContentBasics = () => {
 +
  const [justifyContent, setJustifyContent] = useState("flex-start");
 +
 
 +
  return (
 +
    <PreviewLayout
 +
      label="justifyContent"
 +
      selectedValue={justifyContent}
 +
      values={[
 +
        "flex-start",
 +
        "flex-end",
 +
        "center",
 +
        "space-between",
 +
        "space-around",
 +
        "space-evenly",
 +
      ]}
 +
      setSelectedValue={setJustifyContent}
 +
    >
 +
      <View
 +
        style={[styles.box, { backgroundColor: "powderblue" }]}
 +
      />
 +
      <View
 +
        style={[styles.box, { backgroundColor: "skyblue" }]}
 +
      />
 +
      <View
 +
        style={[styles.box, { backgroundColor: "steelblue" }]}
 +
      />
 +
    </PreviewLayout>
 +
  );
 +
};
 +
 
 +
const PreviewLayout = ({
 +
  label,
 +
  children,
 +
  values,
 +
  selectedValue,
 +
  setSelectedValue,
 +
}) => (
 +
  <View style={{ padding: 10, flex: 1 }}>
 +
    <Text style={styles.label}>{label}</Text>
 +
    <View style={styles.row}>
 +
      {values.map((value) => (
 +
        <TouchableOpacity
 +
          key={value}
 +
          onPress={() => setSelectedValue(value)}
 +
          style={[styles.button, selectedValue === value && styles.selected]}
 +
        >
 +
          <Text
 +
            style={[
 +
              styles.buttonLabel,
 +
              selectedValue === value && styles.selectedLabel,
 +
            ]}
 +
          >
 +
            {value}
 +
          </Text>
 +
        </TouchableOpacity>
 +
      ))}
 +
    </View>
 +
    <View style={[styles.container, { [label]: selectedValue }]}>
 +
      {children}
 +
    </View>
 +
  </View>
 +
);
 +
 
 +
const styles = StyleSheet.create({
 +
  container: {
 +
    flex: 1,
 +
    marginTop: 8,
 +
    backgroundColor: "aliceblue",
 +
  },
 +
  box: {
 +
    width: 50,
 +
    height: 50,
 +
  },
 +
  row: {
 +
    flexDirection: "row",
 +
    flexWrap: "wrap",
 +
  },
 +
  button: {
 +
    paddingHorizontal: 8,
 +
    paddingVertical: 6,
 +
    borderRadius: 4,
 +
    backgroundColor: "oldlace",
 +
    alignSelf: "flex-start",
 +
    marginHorizontal: "1%",
 +
    marginBottom: 6,
 +
    minWidth: "48%",
 +
    textAlign: "center",
 +
  },
 +
  selected: {
 +
    backgroundColor: "coral",
 +
    borderWidth: 0,
 +
  },
 +
  buttonLabel: {
 +
    fontSize: 12,
 +
    fontWeight: "500",
 +
    color: "coral",
 +
  },
 +
  selectedLabel: {
 +
    color: "white",
 +
  },
 +
  label: {
 +
    textAlign: "center",
 +
    marginBottom: 10,
 +
    fontSize: 24,
 +
  },
 +
});
 +
 
 +
export default JustifyContentBasics;
 +
</syntaxhighlight>
 +
==الخاصية ‎<code>alignItems</code>‎==
 +
تحدّد الخاصية <code>[[ReactNative/layout props#alignItems|alignItems]]</code> كيفية محاذاة الأبناء وفق محور الحاوية المتعامد مع المحور الرئيسي. تتشابه محاذاة العناصر إلى حد كبير مع الخاصية <code>justifyContent</code> ولكن تُطبَّق الخاصية <code>alignItems</code> على المحور المتعامد مع المحور الرئيسي cross axis بدلًا من تطبيقها على المحور الرئيسي main axis.
 +
 
 +
* <code>stretch</code> (القيمة الافتراضية): يمتد أبناء الحاوية للتطابق مع ارتفاع <code>height</code> محور الحاوية المتعامد مع المحور الرئيسي.
 +
* <code>flex-start</code>: تحاذي هذه القيمة أبناء الحاوية مع بداية محور الحاوية المتعامد مع المحور الرئيسي.
 +
* <code>flex-end</code>: تحاذي هذه القيمة أبناء الحاوية إلى نهاية محور الحاوية المتعامد مع المحور الرئيسي.
 +
* <code>center</code>: تحاذي هذه القيمة أبناء الحاوية إلى مركز محور الحاوية المتعامد مع المحور الرئيسي.
 +
 
 +
* <code>baseline</code>: تحاذي هذه القيمة أبناء الحاوية على طول خط الأساس baseline المشترك، إذ يمكن ضبط الأبناء ليكونوا خط الأساس المرجعي لآبائهم.
 +
<blockquote>'''ملاحظة:''' يجب ألا يكون للأبناء بُعدٌ ثابت على طول المحور الثانوي ليكون للخاصيّة ‎<code>stretch</code>‎ (التي تتحكّم بالتمدّد) تأثير، فضبط القيمة ‎<code>alignItems: stretch</code>‎ في المثال التالي لا تأثير له حتى تُزالَ القيمة ‎<code>width: 50</code>من الأبناء.</blockquote>اطّلع على مزيد من المعلومات حول [[CSS/align-items|الخاصية <code>alignItems</code>]] من توثيق [[CSS]].
 +
 
 +
إليك المثال التالي ([https://snack.expo.dev/@hsoubwiki/align-items تجربة حية]):<syntaxhighlight lang="javascript">
 +
import React, { useState } from "react";
 +
import {
 +
  View,
 +
  TouchableOpacity,
 +
  Text,
 +
  StyleSheet,
 +
} from "react-native";
 +
 
 +
const AlignItemsLayout = () => {
 +
  const [alignItems, setAlignItems] = useState("stretch");
 +
 
 +
  return (
 +
    <PreviewLayout
 +
      label="alignItems"
 +
      selectedValue={alignItems}
 +
      values={[
 +
        "stretch",
 +
        "flex-start",
 +
        "flex-end",
 +
        "center",
 +
        "baseline",
 +
      ]}
 +
      setSelectedValue={setAlignItems}
 +
    >
 +
      <View
 +
        style={[styles.box, { backgroundColor: "powderblue" }]}
 +
      />
 +
      <View
 +
        style={[styles.box, { backgroundColor: "skyblue" }]}
 +
      />
 +
      <View
 +
        style={[
 +
          styles.box,
 +
          {
 +
            backgroundColor: "steelblue",
 +
            width: "auto",
 +
            minWidth: 50,
 +
          },
 +
        ]}
 +
      />
 +
    </PreviewLayout>
 +
  );
 +
};
 +
 
 +
const PreviewLayout = ({
 +
  label,
 +
  children,
 +
  values,
 +
  selectedValue,
 +
  setSelectedValue,
 +
}) => (
 +
  <View style={{ padding: 10, flex: 1 }}>
 +
    <Text style={styles.label}>{label}</Text>
 +
    <View style={styles.row}>
 +
      {values.map((value) => (
 +
        <TouchableOpacity
 +
          key={value}
 +
          onPress={() => setSelectedValue(value)}
 +
          style={[
 +
            styles.button,
 +
            selectedValue === value && styles.selected,
 +
          ]}
 +
        >
 +
          <Text
 +
            style={[
 +
              styles.buttonLabel,
 +
              selectedValue === value &&
 +
                styles.selectedLabel,
 +
            ]}
 +
          >
 +
            {value}
 +
          </Text>
 +
        </TouchableOpacity>
 +
      ))}
 +
    </View>
 +
    <View
 +
      style={[
 +
        styles.container,
 +
        { [label]: selectedValue },
 +
      ]}
 +
    >
 +
      {children}
 +
    </View>
 +
  </View>
 +
);
 +
 
 +
const styles = StyleSheet.create({
 +
  container: {
 +
    flex: 1,
 +
    marginTop: 8,
 +
    backgroundColor: "aliceblue",
 +
    minHeight: 200,
 +
  },
 +
  box: {
 +
    width: 50,
 +
    height: 50,
 +
  },
 +
  row: {
 +
    flexDirection: "row",
 +
    flexWrap: "wrap",
 +
  },
 +
  button: {
 +
    paddingHorizontal: 8,
 +
    paddingVertical: 6,
 +
    borderRadius: 4,
 +
    backgroundColor: "oldlace",
 +
    alignSelf: "flex-start",
 +
    marginHorizontal: "1%",
 +
    marginBottom: 6,
 +
    minWidth: "48%",
 +
    textAlign: "center",
 +
  },
 +
  selected: {
 +
    backgroundColor: "coral",
 +
    borderWidth: 0,
 +
  },
 +
  buttonLabel: {
 +
    fontSize: 12,
 +
    fontWeight: "500",
 +
    color: "coral",
 +
  },
 +
  selectedLabel: {
 +
    color: "white",
 +
  },
 +
  label: {
 +
    textAlign: "center",
 +
    marginBottom: 10,
 +
    fontSize: 24,
 +
  },
 +
});
 +
 
 +
export default AlignItemsLayout;
 +
</syntaxhighlight>
 +
 
 +
== الخاصية <code>alignSelf</code> ==
 +
تتمتع الخاصية <code>[[ReactNative/layout props#alignSelf|alignSelf]]</code> بنفس خيارات وتأثير الخاصية <code>alignItems</code>، ولكن يمكنك تطبيق الخاصية <code>alignSelf</code> على ابن واحد لتغيير محاذاته ضمن المكوّن الأب، بدلًا من التأثير على الأبناء ضمن الحاوية. تعدّل الخاصية <code>alignSelf</code> أيّ خيار ضبطه الأب مستخدمًا الخاصية <code>alignItems</code>.
 +
 
 +
إليك المثال التالي ([https://snack.expo.dev/@hsoubwiki/align-self تجربة حية]):<syntaxhighlight lang="javascript">
 +
import React, { useState } from "react";
 +
import { View, TouchableOpacity, Text, StyleSheet } from "react-native";
 +
 
 +
const AlignSelfLayout = () => {
 +
  const [alignSelf, setAlignSelf] = useState("stretch");
 +
 
 +
  return (
 +
    <PreviewLayout
 +
      label="alignSelf"
 +
      selectedValue={alignSelf}
 +
      values={["stretch", "flex-start", "flex-end", "center", "baseline"]}
 +
      setSelectedValue={setAlignSelf}>
 +
        <View
 +
          style={[styles.box, {
 +
            alignSelf,
 +
            width: "auto",
 +
            minWidth: 50,
 +
            backgroundColor: "powderblue",
 +
          }]}
 +
        />
 +
      <View
 +
        style={[styles.box, { backgroundColor: "skyblue" }]}
 +
      />
 +
      <View
 +
        style={[styles.box, { backgroundColor: "steelblue" }]}
 +
      />
 +
    </PreviewLayout>
 +
  );
 +
};
 +
 
 +
const PreviewLayout = ({
 +
  label,
 +
  children,
 +
  values,
 +
  selectedValue,
 +
  setSelectedValue,
 +
}) => (
 +
  <View style={{ padding: 10, flex: 1 }}>
 +
    <Text style={styles.label}>{label}</Text>
 +
    <View style={styles.row}>
 +
      {values.map((value) => (
 +
        <TouchableOpacity
 +
          key={value}
 +
          onPress={() => setSelectedValue(value)}
 +
          style={[
 +
            styles.button,
 +
            selectedValue === value && styles.selected,
 +
          ]}
 +
        >
 +
          <Text
 +
            style={[
 +
              styles.buttonLabel,
 +
              selectedValue === value &&
 +
                styles.selectedLabel,
 +
            ]}
 +
          >
 +
            {value}
 +
          </Text>
 +
        </TouchableOpacity>
 +
      ))}
 +
    </View>
 +
    <View style={styles.container}>
 +
      {children}
 +
    </View>
 +
  </View>
 +
);
 +
 
 +
const styles = StyleSheet.create({
 +
  container: {
 +
    flex: 1,
 +
    marginTop: 8,
 +
    backgroundColor: "aliceblue",
 +
    minHeight: 200,
 +
  },
 +
  box: {
 +
    width: 50,
 +
    height: 50,
 +
  },
 +
  row: {
 +
    flexDirection: "row",
 +
    flexWrap: "wrap",
 +
  },
 +
  button: {
 +
    paddingHorizontal: 8,
 +
    paddingVertical: 6,
 +
    borderRadius: 4,
 +
    backgroundColor: "oldlace",
 +
    alignSelf: "flex-start",
 +
    marginHorizontal: "1%",
 +
    marginBottom: 6,
 +
    minWidth: "48%",
 +
    textAlign: "center",
 +
  },
 +
  selected: {
 +
    backgroundColor: "coral",
 +
    borderWidth: 0,
 +
  },
 +
  buttonLabel: {
 +
    fontSize: 12,
 +
    fontWeight: "500",
 +
    color: "coral",
 +
  },
 +
  selectedLabel: {
 +
    color: "white",
 +
  },
 +
  label: {
 +
    textAlign: "center",
 +
    marginBottom: 10,
 +
    fontSize: 24,
 +
  },
 +
});
 +
 
 +
export default AlignSelfLayout;
 +
</syntaxhighlight>
 +
 
 +
== الخاصية <code>alignContent</code> ==
 +
تحدد الخاصية <code>[[ReactNative/layout props#alignContent|alignContent]]</code> توزيع السطور على طول المحور المتعامد مع المحور الرئيسي، وهذا له تأثير فقط عندما تستطيع العناصر الالتفاف إلى عدة أسطر باستخدام الخاصية <code>flexWrap</code>.
 +
 
 +
* <code>flex-start</code> (القيمة الافتراضية): تحاذي هذه القيمة السطور الملتفّة مع بداية محور الحاوية المتعامد مع المحور الرئيسي.
 +
* <code>flex-end</code>: تحاذي السطور الملتفة مع نهاية محور الحاوية المتعامد مع المحور الرئيسي.
 +
* <code>stretch</code> (القيمة الافتراضية عند استخدام Yoga على الويب): تمدّد السطور الملتفة لتتناسب مع ارتفاع محور الحاوية المتعامد مع المحور الرئيسي.
 +
* <code>center</code>: تحاذي السطور الملتفة مع مركز محور الحاوية المتعامد مع المحور الرئيسي.
 +
 
 +
* <code>space-between</code>: تكون المسافة بين السطور الملتفة متساوية على طول محور الحاوية المتعامد مع المحور الرئيسي، وتُوزَّع المسافة المتبقية بين السطور.
 +
*<code>space-around</code>: تكون المسافة متساوية بين السطور الملتفة على طول محور الحاوية المتعامد مع المحور الرئيسي، وتُوزَّع المسافة المتبقية حول السطور، فإن استخدام القيمة <code>space-around</code> سيؤدي إلى توزيع المسافة المتبقية على بداية السطر الأول ونهاية السطر الأخير.
 +
 
 +
اطّلع على مزيد من المعلومات حول [[CSS/align-content|الخاصية <code>alignContent</code>]] من توثيق [[CSS]].
 +
 
 +
إليك المثال التالي ([https://snack.expo.dev/@hsoubwiki/align-content تجربة حية]):<syntaxhighlight lang="javascript">
 +
import React, { useState } from "react";
 +
import { View, TouchableOpacity, Text, StyleSheet } from "react-native";
 +
 
 +
const AlignContentLayout = () => {
 +
  const [alignContent, setAlignContent] = useState("flex-start");
 +
 
 +
  return (
 +
    <PreviewLayout
 +
      label="alignContent"
 +
      selectedValue={alignContent}
 +
      values={[
 +
        "flex-start",
 +
        "flex-end",
 +
        "stretch",
 +
        "center",
 +
        "space-between",
 +
        "space-around",
 +
      ]}
 +
      setSelectedValue={setAlignContent}>
 +
      <View
 +
        style={[styles.box, { backgroundColor: "orangered" }]}
 +
      />
 +
      <View
 +
        style={[styles.box, { backgroundColor: "orange" }]}
 +
      />
 +
      <View
 +
        style={[styles.box, { backgroundColor: "mediumseagreen" }]}
 +
      />
 +
      <View
 +
        style={[styles.box, { backgroundColor: "deepskyblue" }]}
 +
      />
 +
      <View
 +
        style={[styles.box, { backgroundColor: "mediumturquoise" }]}
 +
      />
 +
      <View
 +
        style={[styles.box, { backgroundColor: "mediumslateblue" }]}
 +
      />
 +
      <View
 +
        style={[styles.box, { backgroundColor: "purple" }]}
 +
      />
 +
    </PreviewLayout>
 +
  );
 +
};
 +
 
 +
const PreviewLayout = ({
 +
  label,
 +
  children,
 +
  values,
 +
  selectedValue,
 +
  setSelectedValue,
 +
}) => (
 +
  <View style={{ padding: 10, flex: 1 }}>
 +
    <Text style={styles.label}>{label}</Text>
 +
    <View style={styles.row}>
 +
      {values.map((value) => (
 +
        <TouchableOpacity
 +
          key={value}
 +
          onPress={() => setSelectedValue(value)}
 +
          style={[
 +
            styles.button,
 +
            selectedValue === value && styles.selected,
 +
          ]}
 +
        >
 +
          <Text
 +
            style={[
 +
              styles.buttonLabel,
 +
              selectedValue === value &&
 +
                styles.selectedLabel,
 +
            ]}
 +
          >
 +
            {value}
 +
          </Text>
 +
        </TouchableOpacity>
 +
      ))}
 +
    </View>
 +
    <View
 +
      style={[
 +
        styles.container,
 +
        { [label]: selectedValue },
 +
      ]}
 +
    >
 +
      {children}
 +
    </View>
 +
  </View>
 +
);
 +
 
 +
const styles = StyleSheet.create({
 +
  container: {
 +
    flex: 1,
 +
    flexWrap: "wrap",
 +
    marginTop: 8,
 +
    backgroundColor: "aliceblue",
 +
    maxHeight: 400,
 +
  },
 +
  box: {
 +
    width: 50,
 +
    height: 80,
 +
  },
 +
  row: {
 +
    flexDirection: "row",
 +
    flexWrap: "wrap",
 +
  },
 +
  button: {
 +
    paddingHorizontal: 8,
 +
    paddingVertical: 6,
 +
    borderRadius: 4,
 +
    backgroundColor: "oldlace",
 +
    alignSelf: "flex-start",
 +
    marginHorizontal: "1%",
 +
    marginBottom: 6,
 +
    minWidth: "48%",
 +
    textAlign: "center",
 +
  },
 +
  selected: {
 +
    backgroundColor: "coral",
 +
    borderWidth: 0,
 +
  },
 +
  buttonLabel: {
 +
    fontSize: 12,
 +
    fontWeight: "500",
 +
    color: "coral",
 +
  },
 +
  selectedLabel: {
 +
    color: "white",
 +
  },
 +
  label: {
 +
    textAlign: "center",
 +
    marginBottom: 10,
 +
    fontSize: 24,
 +
  },
 +
});
 +
 
 +
export default AlignContentLayout;
 +
</syntaxhighlight>
 +
 
 +
== الخاصية <code>flexWrap</code> ==
 +
تُضبَط الخاصية <code>[[ReactNative/layout props#flexWrap|flexWrap]]</code> للحاويات وتتحكّم بما يحدث عندما يتجاوز الأبناء حجم الحاوية على طول المحور الرئيسي. يُجبَر الأبناء افتراضيًا على الالتزام بسطر واحد فقط (والذي يمكن أن يؤدي إلى تصغير shrink العناصر). إذا كان الالتفاف wrapping مسموحًا، فستلتف العناصر إلى عدة أسطر على طول المحور الرئيسي إن لزم الأمر.
 +
 
 +
يمكن استخدام الخاصية <code>alignContent</code> عند التفاف الأسطر لتحديد كيفية وضع الأسطر في الحاوية.
 +
 
 +
اطّلع على مزيد من المعلومات حول [[CSS/flex-wrap|الخاصية <code>flexWrap</code>]] من توثيق [[CSS]].
 +
 
 +
إليك المثال التالي ([https://snack.expo.dev/@hsoubwiki/flex-wrap تجربة حية]):<syntaxhighlight lang="javascript">
 +
import React, { useState } from "react";
 +
import { View, TouchableOpacity, Text, StyleSheet } from "react-native";
 +
 
 +
const FlexWrapLayout = () => {
 +
  const [flexWrap, setFlexWrap] = useState("wrap");
 +
 
 +
  return (
 +
    <PreviewLayout
 +
      label="flexWrap"
 +
      selectedValue={flexWrap}
 +
      values={["wrap", "no-wrap"]}
 +
      setSelectedValue={setFlexWrap}>
 +
      <View
 +
        style={[styles.box, { backgroundColor: "orangered" }]}
 +
      />
 +
      <View
 +
        style={[styles.box, { backgroundColor: "orange" }]}
 +
      />
 +
      <View
 +
        style={[styles.box, { backgroundColor: "mediumseagreen" }]}
 +
      />
 +
      <View
 +
        style={[styles.box, { backgroundColor: "deepskyblue" }]}
 +
      />
 +
      <View
 +
        style={[styles.box, { backgroundColor: "mediumturquoise" }]}
 +
      />
 +
      <View
 +
        style={[styles.box, { backgroundColor: "mediumslateblue" }]}
 +
      />
 +
      <View
 +
        style={[styles.box, { backgroundColor: "purple" }]}
 +
      />
 +
    </PreviewLayout>
 +
  );
 +
};
  
<syntaxhighlight lang="javascript">
+
const PreviewLayout = ({
import React, { Component } from 'react';
+
  label,
import { AppRegistry, View } from 'react-native';
+
  children,
 +
  values,
 +
  selectedValue,
 +
  setSelectedValue,
 +
}) => (
 +
  <View style={{ padding: 10, flex: 1 }}>
 +
    <Text style={styles.label}>{label}</Text>
 +
    <View style={styles.row}>
 +
      {values.map((value) => (
 +
        <TouchableOpacity
 +
          key={value}
 +
          onPress={() => setSelectedValue(value)}
 +
          style={[
 +
            styles.button,
 +
            selectedValue === value && styles.selected,
 +
          ]}
 +
        >
 +
          <Text
 +
            style={[
 +
              styles.buttonLabel,
 +
              selectedValue === value &&
 +
                styles.selectedLabel,
 +
            ]}
 +
          >
 +
            {value}
 +
          </Text>
 +
        </TouchableOpacity>
 +
      ))}
 +
    </View>
 +
    <View
 +
      style={[
 +
        styles.container,
 +
        { [label]: selectedValue },
 +
      ]}
 +
    >
 +
      {children}
 +
    </View>
 +
  </View>
 +
);
  
export default class JustifyContentBasics extends Component {
+
const styles = StyleSheet.create({
   render() {
+
  container: {
     return (
+
    flex: 1,
       <View style={{
+
    marginTop: 8,
        flex: 1,
+
    backgroundColor: "aliceblue",
        flexDirection: 'column',
+
    maxHeight: 400,
        justifyContent: 'space-between',
+
  },
       }}>
+
  box: {
         <View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
+
    width: 50,
         <View style={{width: 50, height: 50, backgroundColor: 'skyblue'}} />
+
    height: 80,
         <View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} />
+
  },
 +
  row: {
 +
    flexDirection: "row",
 +
    flexWrap: "wrap",
 +
  },
 +
  button: {
 +
    paddingHorizontal: 8,
 +
    paddingVertical: 6,
 +
    borderRadius: 4,
 +
    backgroundColor: "oldlace",
 +
    marginHorizontal: "1%",
 +
    marginBottom: 6,
 +
    minWidth: "48%",
 +
    textAlign: "center",
 +
  },
 +
  selected: {
 +
    backgroundColor: "coral",
 +
    borderWidth: 0,
 +
  },
 +
  buttonLabel: {
 +
    fontSize: 12,
 +
    fontWeight: "500",
 +
    color: "coral",
 +
  },
 +
  selectedLabel: {
 +
    color: "white",
 +
  },
 +
  label: {
 +
    textAlign: "center",
 +
    marginBottom: 10,
 +
    fontSize: 24,
 +
  },
 +
});
 +
 
 +
export default FlexWrapLayout;
 +
</syntaxhighlight>
 +
 
 +
== الخاصيات <code>flexBasis</code> و <code>flexGrow</code> و <code>flexShrink</code> ==
 +
 
 +
* الخاصية <code>[[ReactNative/layout props#flexBasis|flexBasis]]</code> هي طريقة مستقلة عن المحاور لإعطاء العنصر حجمًا افتراضيًّا على طول المحور الرئيسي، ويتشابه إعداد <code>flexBasis</code> للمكوّن الابن مع إعداد العرض <code>width</code> للمكوّن الابن إذا كان الأب حاويةً لها الخاصية <code>flexDirection: row</code>، أو مع إعداد الارتفاع <code>height</code> للمكوّن الابن إذا كان الأب عبارة عن حاويةً لها الخاصية <code>flexDirection: column</code>. وتمثّل الخاصية <code>flexBasis</code> حجم العنصر الافتراضي قبل أن تُطبَّق عليه الخاصيتان <code>flexShrink</code> و<code>flexGrow</code>.
 +
* تحدّد الخاصية <code>[[ReactNative/layout props#flexGrow|flexGrow]]</code> كيفيّة توزيع المسافات بين المكوّنات الأبناء ضمن الحاوية على طول المحور الرئيسي، حيث توزّع الحاوية -بعد وضع المكونات الأبناء- المسافة المتبقية بينها، بناءً على قيم الخاصية <code>flexGrow</code> الخاصّة بكلّ مكوّن ابن، وتقبل <code>flexGrow</code> أيّ قيمةٍ عشرية أكبر من الصفر أو تساويه، حيث يكون الصفر هو قيمتها الافتراضيّة. توزّع الحاوية المسافةَ المتبقية بين المكونات الأبناء توزيعًا متناسبًا مع قيم <code>flexGrow</code> الخاصة بالأبناء.
 +
 
 +
* تحدّد الخاصية <code>[[ReactNative/layout props#flexShrink|flexShrink]]</code> كيفيّة تصغير المكونات الأبناء على طول المحور الرئيسي عندما يتجاوز حجم المكونات الأبناء الكلي حجمَ الحاوية على طول المحور الرئيسيّ، وهذه الخاصيّة شبيهةٌ جدًا بالخاصيّة <code>flexGrow</code> عند عَدّ الحجم الزائد بمثابة مسافة متبقيةٍ سالبة القيمة، وتتعاون هاتان الخاصيتان فيما بينهما للسماح للمكونات الأبناء بالتمدد والتقلص حسب الحاجة. تقبل الخاصية <code>flexShrink</code> أيّ قيمةٍ عشريّة أكبر من الصفر أو تساويه، حيث يكون الصفر هو قيمتها الافتراضيّة (الواحد هو قيمتها الافتراضيّة على الويب)، وتقلّص الحاوية المكونات الأبناء تقليصًا متناسبًا مع قيم <code>flexShrink</code> الخاصة بالأبناء.
 +
 
 +
اطّلع على مزيد من المعلومات حول الخاصيات <code>[[CSS/flex-basis|flexBasis]]</code> و <code>[[CSS/flex-grow|flexGrow]]</code> و <code>[[CSS/flex-shrink|flexShrink]]</code> من توثيق [[CSS]].
 +
 
 +
إليك المثال التالي ([https://snack.expo.dev/@hsoubwiki/flex-basis,-grow,-and-shrink تجربة حية]):<syntaxhighlight lang="javascript">
 +
import React, { useState } from "react";
 +
import {
 +
  View,
 +
  Text,
 +
  TextInput,
 +
  StyleSheet,
 +
} from "react-native";
 +
 
 +
const App = () => {
 +
   const [powderblue, setPowderblue] = useState({
 +
    flexGrow: 0,
 +
    flexShrink: 1,
 +
    flexBasis: "auto",
 +
  });
 +
  const [skyblue, setSkyblue] = useState({
 +
     flexGrow: 1,
 +
    flexShrink: 0,
 +
    flexBasis: 100,
 +
  });
 +
  const [steelblue, setSteelblue] = useState({
 +
    flexGrow: 0,
 +
    flexShrink: 1,
 +
    flexBasis: 200,
 +
  });
 +
  return (
 +
    <View style={styles.container}>
 +
       <View
 +
        style={[
 +
          styles.container,
 +
          {
 +
            flexDirection: "row",
 +
            alignContent: "space-between",
 +
          },
 +
        ]}
 +
       >
 +
        <BoxInfo
 +
          color="powderblue"
 +
          {...powderblue}
 +
          setStyle={setPowderblue}
 +
        />
 +
        <BoxInfo
 +
          color="skyblue"
 +
          {...skyblue}
 +
          setStyle={setSkyblue}
 +
        />
 +
        <BoxInfo
 +
          color="steelblue"
 +
          {...steelblue}
 +
          setStyle={setSteelblue}
 +
        />
 +
      </View>
 +
      <View style={styles.previewContainer}>
 +
         <View
 +
          style={[
 +
            styles.box,
 +
            {
 +
              flexBasis: powderblue.flexBasis,
 +
              flexGrow: powderblue.flexGrow,
 +
              flexShrink: powderblue.flexShrink,
 +
              backgroundColor: "powderblue",
 +
            },
 +
          ]}
 +
        />
 +
         <View
 +
          style={[
 +
            styles.box,
 +
            {
 +
              flexBasis: skyblue.flexBasis,
 +
              flexGrow: skyblue.flexGrow,
 +
              flexShrink: skyblue.flexShrink,
 +
              backgroundColor: "skyblue",
 +
            },
 +
          ]}
 +
        />
 +
         <View
 +
          style={[
 +
            styles.box,
 +
            {
 +
              flexBasis: steelblue.flexBasis,
 +
              flexGrow: steelblue.flexGrow,
 +
              flexShrink: steelblue.flexShrink,
 +
              backgroundColor: "steelblue",
 +
            },
 +
          ]}
 +
        />
 
       </View>
 
       </View>
     );
+
     </View>
  }
+
  );
 
};
 
};
  
// تخطّ هذا السطر إن كنت تستعمل أداة
+
const BoxInfo = ({
// Create React Native App
+
  color,
AppRegistry.registerComponent('AwesomeProject', () => JustifyContentBasics);
+
  flexBasis,
 +
  flexShrink,
 +
  setStyle,
 +
  flexGrow,
 +
}) => (
 +
  <View style={[styles.row, { flexDirection: "column" }]}>
 +
    <View
 +
      style={[
 +
        styles.boxLabel,
 +
        {
 +
          backgroundColor: color,
 +
        },
 +
      ]}
 +
    >
 +
      <Text
 +
        style={{
 +
          color: "#fff",
 +
          fontWeight: 500,
 +
          textAlign: "center",
 +
        }}
 +
      >
 +
        Box
 +
      </Text>
 +
    </View>
 +
    <Text style={styles.label}>flexBasis</Text>
 +
    <TextInput
 +
      value={flexBasis}
 +
      style={styles.input}
 +
      onChangeText={(fB) =>
 +
        setStyle((value) => ({
 +
          ...value,
 +
          flexBasis: isNaN(parseInt(fB))
 +
            ? "auto"
 +
            : parseInt(fB),
 +
        }))
 +
      }
 +
    />
 +
    <Text style={styles.label}>flexShrink</Text>
 +
    <TextInput
 +
      value={flexShrink}
 +
      style={styles.input}
 +
      onChangeText={(fS) =>
 +
        setStyle((value) => ({
 +
          ...value,
 +
          flexShrink: isNaN(parseInt(fS))
 +
            ? ""
 +
            : parseInt(fS),
 +
        }))
 +
      }
 +
    />
 +
    <Text style={styles.label}>flexGrow</Text>
 +
    <TextInput
 +
      value={flexGrow}
 +
      style={styles.input}
 +
      onChangeText={(fG) =>
 +
        setStyle((value) => ({
 +
          ...value,
 +
          flexGrow: isNaN(parseInt(fG))
 +
            ? ""
 +
            : parseInt(fG),
 +
        }))
 +
      }
 +
    />
 +
  </View>
 +
);
 +
 
 +
const styles = StyleSheet.create({
 +
  container: {
 +
    flex: 1,
 +
    paddingHorizontal: 10,
 +
  },
 +
  box: {
 +
    flex: 1,
 +
    height: 50,
 +
    width: 50,
 +
  },
 +
  boxLabel: {
 +
    minWidth: 80,
 +
    padding: 8,
 +
    borderRadius: 4,
 +
    marginTop: 8,
 +
  },
 +
  label: {
 +
    marginTop: 6,
 +
    fontSize: 16,
 +
    fontWeight: "100",
 +
  },
 +
  previewContainer: {
 +
    flex: 1,
 +
    flexDirection: "row",
 +
    backgroundColor: "aliceblue",
 +
  },
 +
  row: {
 +
    flex: 1,
 +
    flexDirection: "row",
 +
    flexWrap: "wrap",
 +
    alignItems: "center",
 +
    marginBottom: 10,
 +
  },
 +
  input: {
 +
    borderBottomWidth: 1,
 +
    paddingVertical: 3,
 +
    width: 50,
 +
    textAlign: "center",
 +
  },
 +
});
 +
 
 +
export default App;
 
</syntaxhighlight>
 
</syntaxhighlight>
==الخاصية ‎<code>alignItems</code>‎==
 
تؤدي إضافة ‎<code>alignItems</code>‎ إلى نمطِ مكونٍ إلى تحديد محاذاة الأطفال على طول المحور الثانوي (إذا كان المحور الأساسي صفًا (‎<code>row</code>‎)، فسيكون المحور الثانوي هو العمود (‎<code>column</code>‎) والعكس صحيح). هل تريد مُحاذاة الأطفال في البداية، أو المركز، أو النهاية، أو أن تمتدّ لملء المساحة؟ الخيارات المتاحة هي ‎<code>flex-start</code>‎، و‎<code>center</code>‎، و‎<code>flex-end</code>‎، و‎<code>stretch</code>‎.
 
  
'''ملاحظة:''' ليكون للخاصيّة ‎<code>stretch</code>(التي تتحكّم بالتمدّد) تأثير، يجب ألا يكون للأطفال بعدٌ ثابت على طول المحور الثانوي. في المثال التالي، ضبط ‎<code>alignItems: stretch</code>لا تأثير له حتى تُزالَ القيمة ‎<code>width: 50</code>من الأطفال (جرّب تغيير مختلف القيم وانظر النّتيجة):
+
== العرض والارتفاع ==
<syntaxhighlight lang="javascript">
+
تحدد خاصية العرض <code>width</code> عرض منطقة محتوى العنصر، وتحدّد خاصية الارتفاع <code>height</code> ارتفاع منطقة محتوى العنصر.
import React, { Component } from 'react';
+
 
import { AppRegistry, View } from 'react-native';
+
يمكن أن تأخذ كلٌّ من الخاصيتين <code>width</code> و <code>height</code> القيم التالية:
 +
 
 +
* <code>auto</code> (القيمة الافتراضية): يحسب إطار عمل React Native عرض أو ارتفاع العنصر بناءً على محتواه، سواء كان ذلك المحتوى ابنًا آخر أو نصًا أو صورة.
 +
* <code>pixels</code>: تحدّد هذه القيمة العرض أو الارتفاع بالبكسلات المطلقة، حيث قد يكون هذا هو بُعد العقدة النهائي وقد لا يكون كذلك، اعتمادًا على الأنماط الأخرى التي تُضبَط للمكوّن.
 +
* <code>percentage</code>: تحدّد هذه القيمة العرض أو الارتفاع على أنها نسبة مئوية من عرض المكوّن الأب أو ارتفاعه.
 +
إليك المثال التالي ([https://snack.expo.dev/@hsoubwiki/width-and-height-01 تجربة حية]):<syntaxhighlight lang="javascript">
 +
import React, { useState } from "react";
 +
import {
 +
  View,
 +
  SafeAreaView,
 +
  TouchableOpacity,
 +
  Text,
 +
  StyleSheet,
 +
} from "react-native";
 +
 
 +
const WidthHeightBasics = () => {
 +
  const [widthType, setWidthType] = useState("auto");
 +
  const [heightType, setHeightType] = useState("auto");
  
export default class AlignItemsBasics extends Component {
+
   return (
   render() {
+
    <PreviewLayout
    return (
+
      widthType={widthType}
       // Try setting `alignItems` to 'flex-start'
+
      heightType={heightType}
       // Try setting `justifyContent` to `flex-end`.
+
      widthValues={["auto", 300, "80%"]}
       // Try setting `flexDirection` to `row`.
+
       heightValues={["auto", 200, "60%"]}
       <View style={{
+
       setWidthType={setWidthType}
        flex: 1,
+
       setHeightType={setHeightType}
        flexDirection: 'column',
+
    >
        justifyContent: 'center',
+
       <View
        alignItems: 'stretch',
+
        style={{
      }}>
+
          alignSelf: "flex-start",
         <View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
+
          backgroundColor: "aliceblue",
         <View style={{height: 50, backgroundColor: 'skyblue'}} />
+
          height: heightType,
         <View style={{height: 100, backgroundColor: 'steelblue'}} />
+
          width: widthType,
 +
          padding: 15,
 +
        }}
 +
      >
 +
         <View
 +
          style={[
 +
            styles.box,
 +
            { backgroundColor: "powderblue" },
 +
          ]}
 +
        />
 +
         <View
 +
          style={[
 +
            styles.box,
 +
            { backgroundColor: "skyblue" },
 +
          ]}
 +
        />
 +
         <View
 +
          style={[
 +
            styles.box,
 +
            { backgroundColor: "steelblue" },
 +
          ]}
 +
        />
 
       </View>
 
       </View>
     );
+
     </PreviewLayout>
   }
+
  );
 +
};
 +
 
 +
const PreviewLayout = ({
 +
  children,
 +
  widthType,
 +
  heightType,
 +
  widthValues,
 +
  heightValues,
 +
  setWidthType,
 +
  setHeightType,
 +
}) => (
 +
  <View style={{ flex: 1, padding: 10 }}>
 +
    <View style={styles.row}>
 +
      <Text style={styles.label}>width </Text>
 +
      {widthValues.map((value) => (
 +
        <TouchableOpacity
 +
          key={value}
 +
          onPress={() => setWidthType(value)}
 +
          style={[
 +
            styles.button,
 +
            widthType === value && styles.selected,
 +
          ]}
 +
        >
 +
          <Text
 +
            style={[
 +
              styles.buttonLabel,
 +
              widthType === value && styles.selectedLabel,
 +
            ]}
 +
          >
 +
            {value}
 +
          </Text>
 +
        </TouchableOpacity>
 +
      ))}
 +
    </View>
 +
    <View style={styles.row}>
 +
      <Text style={styles.label}>height </Text>
 +
      {heightValues.map((value) => (
 +
        <TouchableOpacity
 +
          key={value}
 +
          onPress={() => setHeightType(value)}
 +
          style={[
 +
            styles.button,
 +
            heightType === value && styles.selected,
 +
          ]}
 +
        >
 +
          <Text
 +
            style={[
 +
              styles.buttonLabel,
 +
              heightType === value && styles.selectedLabel,
 +
            ]}
 +
          >
 +
            {value}
 +
          </Text>
 +
        </TouchableOpacity>
 +
      ))}
 +
    </View>
 +
    {children}
 +
  </View>
 +
);
 +
 
 +
const styles = StyleSheet.create({
 +
  box: {
 +
    width: 50,
 +
    height: 50,
 +
  },
 +
  row: {
 +
    flexDirection: "row",
 +
    flexWrap: "wrap",
 +
  },
 +
  button: {
 +
    padding: 8,
 +
    borderRadius: 4,
 +
    backgroundColor: "oldlace",
 +
    alignSelf: "flex-start",
 +
    marginRight: 10,
 +
    marginBottom: 10,
 +
  },
 +
  selected: {
 +
    backgroundColor: "coral",
 +
    shadowOpacity: 0,
 +
    borderWidth: 0,
 +
  },
 +
  buttonLabel: {
 +
    fontSize: 12,
 +
    fontWeight: "500",
 +
    color: "coral",
 +
  },
 +
  selectedLabel: {
 +
    color: "white",
 +
  },
 +
  label: {
 +
    textAlign: "center",
 +
    marginBottom: 10,
 +
    fontSize: 24,
 +
  },
 +
});
 +
 
 +
export default WidthHeightBasics;
 +
</syntaxhighlight>
 +
 
 +
== التخطيط المطلق Absolute والنسبي Relative ==
 +
يحدّد نوع خاصية الموضع <code>position</code> لعنصرٍ ما كيفية وضعه ضمن المكوّن الأب.
 +
 
 +
* <code>relative</code> (القيمة الافتراضية): يوضَع العنصر افتراضيًا موضعًا نسبيًا، وهذا يعني أن العنصر يُوضَع وفقًا لتدفق التخطيط الطبيعي، ثم يُزاح بالنسبة إلى هذا الموضع بناءً على القيم <code>top</code> و <code>right</code> و <code>bottom</code> و <code>left</code>، إذ لا تؤثر الإزاحة على موضع أي عنصر شقيق أو أب.
 +
* <code>absolute</code>: لا يشترك العنصر في تدفق التخطيط الطبيعي عند وضعه بموضع مطلق، وإنما يوضَع بصورةٍ مستقلة عن أشقائه، حيث يُحدَّد الموضع بناءً على القيم <code>top</code> و <code>right</code> و <code>bottom</code> و <code>left</code>.
 +
إليك المثال التالي ([https://snack.expo.dev/@hsoubwiki/absolute- تجربة حية]):<syntaxhighlight lang="javascript">
 +
import React, { useState } from "react";
 +
import {
 +
  View,
 +
  SafeAreaView,
 +
  TouchableOpacity,
 +
  Text,
 +
  StyleSheet,
 +
} from "react-native";
 +
 
 +
const PositionLayout = () => {
 +
  const [position, setPosition] = useState("relative");
 +
 
 +
   return (
 +
    <PreviewLayout
 +
      label="position"
 +
      selectedValue={position}
 +
      values={["relative", "absolute"]}
 +
      setSelectedValue={setPosition}
 +
    >
 +
      <View
 +
        style={[
 +
          styles.box,
 +
          {
 +
            top: 25,
 +
            left: 25,
 +
            position,
 +
            backgroundColor: "powderblue",
 +
          },
 +
        ]}
 +
      />
 +
      <View
 +
        style={[
 +
          styles.box,
 +
          {
 +
            top: 50,
 +
            left: 50,
 +
            position,
 +
            backgroundColor: "skyblue",
 +
          },
 +
        ]}
 +
      />
 +
      <View
 +
        style={[
 +
          styles.box,
 +
          {
 +
            top: 75,
 +
            left: 75,
 +
            position,
 +
            backgroundColor: "steelblue",
 +
          },
 +
        ]}
 +
      />
 +
    </PreviewLayout>
 +
  );
 
};
 
};
  
// تخطّ هذا السطر إن كنت تستعمل أداة
+
const PreviewLayout = ({
// Create React Native App
+
  label,
AppRegistry.registerComponent('AwesomeProject', () => AlignItemsBasics);
+
  children,
 +
  values,
 +
  selectedValue,
 +
  setSelectedValue,
 +
}) => (
 +
  <View style={{ padding: 10, flex: 1 }}>
 +
    <Text style={styles.label}>{label}</Text>
 +
    <View style={styles.row}>
 +
      {values.map((value) => (
 +
        <TouchableOpacity
 +
          key={value}
 +
          onPress={() => setSelectedValue(value)}
 +
          style={[
 +
            styles.button,
 +
            selectedValue === value && styles.selected,
 +
          ]}
 +
        >
 +
          <Text
 +
            style={[
 +
              styles.buttonLabel,
 +
              selectedValue === value &&
 +
                styles.selectedLabel,
 +
            ]}
 +
          >
 +
            {value}
 +
          </Text>
 +
        </TouchableOpacity>
 +
      ))}
 +
    </View>
 +
    <View style={styles.container}>{children}</View>
 +
  </View>
 +
);
 +
 
 +
const styles = StyleSheet.create({
 +
  container: {
 +
    flex: 1,
 +
    marginTop: 8,
 +
    backgroundColor: "aliceblue",
 +
    minHeight: 200,
 +
  },
 +
  box: {
 +
    width: 50,
 +
    height: 50,
 +
  },
 +
  row: {
 +
    flexDirection: "row",
 +
    flexWrap: "wrap",
 +
  },
 +
  button: {
 +
    paddingHorizontal: 8,
 +
    paddingVertical: 6,
 +
    borderRadius: 4,
 +
    backgroundColor: "oldlace",
 +
    alignSelf: "flex-start",
 +
    marginHorizontal: "1%",
 +
    marginBottom: 6,
 +
    minWidth: "48%",
 +
    textAlign: "center",
 +
  },
 +
  selected: {
 +
    backgroundColor: "coral",
 +
    borderWidth: 0,
 +
  },
 +
  buttonLabel: {
 +
    fontSize: 12,
 +
    fontWeight: "500",
 +
    color: "coral",
 +
  },
 +
  selectedLabel: {
 +
    color: "white",
 +
  },
 +
  label: {
 +
    textAlign: "center",
 +
    marginBottom: 10,
 +
    fontSize: 24,
 +
  },
 +
});
 +
 
 +
export default PositionLayout;
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== المزيد من المعلومات==
+
== مزيد من المعلومات==
هذه هي الأساسيات، لكن هناك عدّة أنماط أخرى قد تحتاج إليها لتخطيط تطبيقاتك. اطّلع على [[ReactNative/layout props|قائمة خاصيّات التخطيط الكاملة هنا.]]
+
اطّلع على [https://yogalayout.com/playground/ ملعب yoga التفاعلي] الذي يمكنك استخدامه لفهم flexbox فهمًا أفضل، واطلع أيضًا على توثيق [[CSS]] العربي، ويمكنك أيضًا الاطّلاع على بعض الأمثلة من [https://medium.com/wix-engineering/the-full-react-native-layout-cheat-sheet-a4147802405c Wix Engineers].
  
اقتربنا من التمّكن من بناء تطبيق واقعيّ. لكن ما زلنا بحاجة إلى طريقة للحصول على مدخلات المستخدم ليتمكّن من التفاعل مع التطبيق، لذا سننتقل إلى [[ReactNative/handling text input|تعلم كيفية التعامل مع إدخال النص بالمكون <code>TextInput</code>.]]
+
هذه هي الأساسيات، لكن هناك عدّة أنماط أخرى قد تحتاج إليها لتخطيط تطبيقاتك. اطّلع على [[ReactNative/layout props|قائمة خاصيّات التخطيط الكاملة]][[ReactNative/handling text input|.]]
  
 
== مصادر ==
 
== مصادر ==
* [https://facebook.github.io/react-native/docs/flexbox صفحة Layout with Flexbox في توثيق React Native الرسمي.]
+
* [https://reactnative.dev/docs/flexbox صفحة Layout with Flexbox في توثيق React Native الرسمي.]
 
[[تصنيف:ReactNative]]
 
[[تصنيف:ReactNative]]
 +
[[تصنيف:React Native Docs]]

المراجعة الحالية بتاريخ 13:40، 9 أكتوبر 2021

يمكن للمكوّن تحديد تخطيط layout أبنائه باستخدام خوارزمية Flexbox التي صُمِّمَت لتوفير تخطيط متناسق على أحجام شاشات مختلفة. سنعتمد على كلّ من الخاصيّات ‎flexDirection‎، و ‎alignItems‎ و ‎justifyContent‎ للحصول على التصميم الصحيح.

يعمل Flexbox في React Native كما يعمل في CSS على الويب مع اختلافات طفيفة، إذ تختلف الإعدادات الافتراضية، فالقيمة الافتراضيّة للخاصيّة ‎flexDirection‎ هي ‎column‎ عوضًا عن ‎row‎، والقيمة الافتراضيّة للخاصيّة ‎alignContent‎ هي ‎flex-start‎ عوضًا عن stretch‎، والقيمة الافتراضيّة للخاصيّة ‎flexShrink‎ هي ‎0‎ عوضًا عن 1‎، ولا تدعم خاصيّة ‎flex‎ إلّا عددًا واحدًا كقيمة.

الخاصية flex

ستحدّد الخاصية flex كيف "تملأ" عناصرك المساحةَ المتاحة على طول المحور الرئيسي main axis، إذ تُقسَم المساحة وفقًا للخاصية flex لكل عنصر.

تكون الواجهات (العروض) views ذات اللون الأحمر والأصفر والأخضر في المثال التالي كلها عناصرًا أبناء في حاوية الواجهة التي لها الخاصية flex: 1. تستخدم الواجهة ذات اللون الأحمر الخاصية flex: 1، وتستخدم الواجهة ذات اللون الأصفر الخاصية flex: 2، وتستخدم الواجهة ذات اللون الأخضر الخاصية flex: 3، أي 1 + 2 + 3 = 6، مما يعني أن الواجهة الحمرات ستحصل على 1/6 من المساحة، وتحصل الواجهة الصفراء على 2/6 من المساحة، والخضراء على 3/6 من المساحة.

إليك المثال التالي (تجربة حية):

import React from "react";
import { StyleSheet, Text, View } from "react-native";

const Flex = () => {
  return (
    <View style={[styles.container, {
      // ‫جرّب ضبط الخاصية flexDirection على القيمة row
      flexDirection: "column"
    }]}>
      <View style={{ flex: 1, backgroundColor: "red" }} />
      <View style={{ flex: 2, backgroundColor: "darkorange" }} />
      <View style={{ flex: 3, backgroundColor: "green" }} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
  },
});

export default Flex;

الخاصية flexDirection

تتحكّم الخاصية flexDirection في اتجاه ترتيب أبناء عقدةٍ ما، حيث يُشار إلى هذا الاتجاه أيضًا بالمحور الرئيسي main axis. المحور cross axis هو المحور المتعامد مع المحور الرئيسي، أو المحور الذي توضَع فيه الأسطر التي يمكنها الالتفاف على أكثر من سطر.

  • column (القيمة الافتراضية): تحاذي هذه القيمة العناصر الأبناء من الأعلى إلى الأسفل. إذا كان الالتفاف wrapping مفعَّلًا، فسيبدأ السطر التالي على يمين العنصر الأول أعلى الحاوية.
  • row: تحاذي هذه القيمة العناصر الأبناء من اليسار إلى اليمين. إذا كان الالتفاف wrapping مفعَّلًا، فسيبدأ السطر التالي أسفل العنصر الأول على يسار الحاوية.
  • column-reverse: تحاذي هذه القيمة العناصر الأبناء من الأسفل إلى الأعلى. إذا كان الالتفاف wrapping مفعَّلًا، فسيبدأ السطر التالي على يمين العنصر الأول في أسفل الحاوية.
  • row-reverse: تحاذي هذه القيمة العناصر الأبناء من اليمين إلى اليسار. إذا كان الالتفاف wrapping مفعَّلًا، فسيبدأ السطر التالي أسفل العنصر الأول على يمين الحاوية.

اطّلع على مزيد من المعلومات حول الخاصية flexDirection من توثيق CSS.

إليك المثال التالي (تجربة حية):

import React, { useState } from "react";
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";

const FlexDirectionBasics = () => {
  const [flexDirection, setflexDirection] = useState("column");

  return (
    <PreviewLayout
      label="flexDirection"
      values={["column", "row", "row-reverse", "column-reverse"]}
      selectedValue={flexDirection}
      setSelectedValue={setflexDirection}
    >
      <View
        style={[styles.box, { backgroundColor: "powderblue" }]}
      />
      <View
        style={[styles.box, { backgroundColor: "skyblue" }]}
      />
      <View
        style={[styles.box, { backgroundColor: "steelblue" }]}
      />
    </PreviewLayout>
  );
};

const PreviewLayout = ({
  label,
  children,
  values,
  selectedValue,
  setSelectedValue,
}) => (
  <View style={{ padding: 10, flex: 1 }}>
    <Text style={styles.label}>{label}</Text>
    <View style={styles.row}>
      {values.map((value) => (
        <TouchableOpacity
          key={value}
          onPress={() => setSelectedValue(value)}
          style={[
            styles.button,
            selectedValue === value && styles.selected,
          ]}
        >
          <Text
            style={[
              styles.buttonLabel,
              selectedValue === value && styles.selectedLabel,
            ]}
          >
            {value}
          </Text>
        </TouchableOpacity>
      ))}
    </View>
    <View style={[styles.container, { [label]: selectedValue }]}>
      {children}
    </View>
  </View>
);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: 8,
    backgroundColor: "aliceblue",
  },
  box: {
    width: 50,
    height: 50,
  },
  row: {
    flexDirection: "row",
    flexWrap: "wrap",
  },
  button: {
    paddingHorizontal: 8,
    paddingVertical: 6,
    borderRadius: 4,
    backgroundColor: "oldlace",
    alignSelf: "flex-start",
    marginHorizontal: "1%",
    marginBottom: 6,
    minWidth: "48%",
    textAlign: "center",
  },
  selected: {
    backgroundColor: "coral",
    borderWidth: 0,
  },
  buttonLabel: {
    fontSize: 12,
    fontWeight: "500",
    color: "coral",
  },
  selectedLabel: {
    color: "white",
  },
  label: {
    textAlign: "center",
    marginBottom: 10,
    fontSize: 24,
  },
});

export default FlexDirectionBasics;

اتجاه التخطيط Layout Direction

تحدّد خاصية اتجاه التخطيط اتجاهَ توزيع الأبناء والنص ضمن تسلسلٍ هرمي، كما يؤثّر اتجاه التخطيط أيضًا على ما تشير إليه بداية start ونهاية end الأطراف. يحدّد React Native اتجاه التخطيط على القيمة LTR افتراضيًا، حيث تشير البداية start إلى اليسار وتشير النهاية end إلى اليمين في هذه الحالة.

  • LTR (القيمة الافتراضية): يوضَع النص والأبناء من اليسار إلى اليمين باستخدام هذه القيمة، حيث تُطبَّق الهوامش والحاشية المُطبَّقة على بداية العنصر من الجانب الأيسر.
  • RTL: يُوضَع النص والأبناء من اليمين إلى اليسار باستخدام هذه القيمة، حيث تُطبَّق الهوامش والحاشية المُطبَّقة على بداية العنصر من الجانب الأيمن.

إليك المثال التالي (تجربة حية):

import React, { useState } from "react";
import { View, TouchableOpacity, Text, StyleSheet } from "react-native";

const DirectionLayout = () => {
  const [direction, setDirection] = useState("ltr");

  return (
    <PreviewLayout
      label="direction"
      selectedValue={direction}
      values={["ltr", "rtl"]}
      setSelectedValue={setDirection}>
      <View
        style={[styles.box, { backgroundColor: "powderblue" }]}
      />
      <View
        style={[styles.box, { backgroundColor: "skyblue" }]}
      />
      <View
        style={[styles.box, { backgroundColor: "steelblue" }]}
      />
    </PreviewLayout>
  );
};

const PreviewLayout = ({
  label,
  children,
  values,
  selectedValue,
  setSelectedValue,
}) => (
  <View style={{ padding: 10, flex: 1 }}>
    <Text style={styles.label}>{label}</Text>
    <View style={styles.row}>
      {values.map((value) => (
        <TouchableOpacity
          key={value}
          onPress={() => setSelectedValue(value)}
          style={[
            styles.button,
            selectedValue === value && styles.selected,
          ]}
        >
          <Text
            style={[
              styles.buttonLabel,
              selectedValue === value && styles.selectedLabel,
            ]}
          >
            {value}
          </Text>
        </TouchableOpacity>
      ))}
    </View>
    <View style={[styles.container, { [label]: selectedValue }]}>
      {children}
    </View>
  </View>
);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: 8,
    backgroundColor: "aliceblue",
  },
  box: {
    width: 50,
    height: 50,
  },
  row: {
    flexDirection: "row",
    flexWrap: "wrap",
  },
  button: {
    paddingHorizontal: 8,
    paddingVertical: 6,
    borderRadius: 4,
    backgroundColor: "oldlace",
    alignSelf: "flex-start",
    marginHorizontal: "1%",
    marginBottom: 6,
    minWidth: "48%",
    textAlign: "center",
  },
  selected: {
    backgroundColor: "coral",
    borderWidth: 0,
  },
  buttonLabel: {
    fontSize: 12,
    fontWeight: "500",
    color: "coral",
  },
  selectedLabel: {
    color: "white",
  },
  label: {
    textAlign: "center",
    marginBottom: 10,
    fontSize: 24,
  },
});

export default DirectionLayout;

الخاصية ‎justifyContent

تحدّد الخاصية justifyContent كيفية محاذاة المكونات الأبناء وفق محور الحاوية الرئيسي، حيث يمكنك استخدام هذه الخاصية لتوسيط ابنٍ أفقيًا ضمن حاوية مع ضبط الخاصية flexDirection على القيمة row أو عموديًا ضمن حاوية مع ضبط الخاصية flexDirection على القيمة column.

  • flex-start (القيمة الافتراضية): تحاذي أبناء الحاوية إلى بداية محور الحاوية الرئيسي.
  • flex-end: تحاذي هذه القيمة الحاوية إلى نهاية محور الحاوية الرئيسي.
  • center: تحاذي أبناء الحاوية إلى مركز محور الحاوية الرئيسي.
  • space-between: تكون المسافة بين الأبناء متساوية على طول محور الحاوية الرئيسي، وتُوزَّع المسافة المتبقية بين الأبناء.
  • space-around: تكون المسافة متساوية بين الأبناء على طول محور الحاوية الرئيسي، وتُوزَّع المسافة المتبقية حول الأبناء، فإن استخدام القيمة space-around سيؤدي إلى توزيع المسافة المتبقية على بداية الابن الأول ونهاية الابن الأخير.
  • space-evenly: يُوزَّع الأبناء بمسافة متساوية ضمن حاوية المحاذاة على طول المحور الرئيسي. التباعد بين كل زوج من العناصر المتجاورة، وطرف البداية الرئيسية والعنصر الأول، وطرف النهاية الرئيسية والعنصر الأخير، كلها متماثلة تمامًا.

اطّلع على مزيد من المعلومات حول الخاصية justifyContent من توثيق CSS.

إليك المثال التالي (تجربة حية):

import React, { useState } from "react";
import { View, TouchableOpacity, Text, StyleSheet } from "react-native";

const JustifyContentBasics = () => {
  const [justifyContent, setJustifyContent] = useState("flex-start");

  return (
    <PreviewLayout
      label="justifyContent"
      selectedValue={justifyContent}
      values={[
        "flex-start",
        "flex-end",
        "center",
        "space-between",
        "space-around",
        "space-evenly",
      ]}
      setSelectedValue={setJustifyContent}
    >
      <View
        style={[styles.box, { backgroundColor: "powderblue" }]}
      />
      <View
        style={[styles.box, { backgroundColor: "skyblue" }]}
      />
      <View
        style={[styles.box, { backgroundColor: "steelblue" }]}
      />
    </PreviewLayout>
  );
};

const PreviewLayout = ({
  label,
  children,
  values,
  selectedValue,
  setSelectedValue,
}) => (
  <View style={{ padding: 10, flex: 1 }}>
    <Text style={styles.label}>{label}</Text>
    <View style={styles.row}>
      {values.map((value) => (
        <TouchableOpacity
          key={value}
          onPress={() => setSelectedValue(value)}
          style={[styles.button, selectedValue === value && styles.selected]}
        >
          <Text
            style={[
              styles.buttonLabel,
              selectedValue === value && styles.selectedLabel,
            ]}
          >
            {value}
          </Text>
        </TouchableOpacity>
      ))}
    </View>
    <View style={[styles.container, { [label]: selectedValue }]}>
      {children}
    </View>
  </View>
);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: 8,
    backgroundColor: "aliceblue",
  },
  box: {
    width: 50,
    height: 50,
  },
  row: {
    flexDirection: "row",
    flexWrap: "wrap",
  },
  button: {
    paddingHorizontal: 8,
    paddingVertical: 6,
    borderRadius: 4,
    backgroundColor: "oldlace",
    alignSelf: "flex-start",
    marginHorizontal: "1%",
    marginBottom: 6,
    minWidth: "48%",
    textAlign: "center",
  },
  selected: {
    backgroundColor: "coral",
    borderWidth: 0,
  },
  buttonLabel: {
    fontSize: 12,
    fontWeight: "500",
    color: "coral",
  },
  selectedLabel: {
    color: "white",
  },
  label: {
    textAlign: "center",
    marginBottom: 10,
    fontSize: 24,
  },
});

export default JustifyContentBasics;

الخاصية ‎alignItems

تحدّد الخاصية alignItems كيفية محاذاة الأبناء وفق محور الحاوية المتعامد مع المحور الرئيسي. تتشابه محاذاة العناصر إلى حد كبير مع الخاصية justifyContent ولكن تُطبَّق الخاصية alignItems على المحور المتعامد مع المحور الرئيسي cross axis بدلًا من تطبيقها على المحور الرئيسي main axis.

  • stretch (القيمة الافتراضية): يمتد أبناء الحاوية للتطابق مع ارتفاع height محور الحاوية المتعامد مع المحور الرئيسي.
  • flex-start: تحاذي هذه القيمة أبناء الحاوية مع بداية محور الحاوية المتعامد مع المحور الرئيسي.
  • flex-end: تحاذي هذه القيمة أبناء الحاوية إلى نهاية محور الحاوية المتعامد مع المحور الرئيسي.
  • center: تحاذي هذه القيمة أبناء الحاوية إلى مركز محور الحاوية المتعامد مع المحور الرئيسي.
  • baseline: تحاذي هذه القيمة أبناء الحاوية على طول خط الأساس baseline المشترك، إذ يمكن ضبط الأبناء ليكونوا خط الأساس المرجعي لآبائهم.

ملاحظة: يجب ألا يكون للأبناء بُعدٌ ثابت على طول المحور الثانوي ليكون للخاصيّة ‎stretch‎ (التي تتحكّم بالتمدّد) تأثير، فضبط القيمة ‎alignItems: stretch‎ في المثال التالي لا تأثير له حتى تُزالَ القيمة ‎width: 50‎ من الأبناء.

اطّلع على مزيد من المعلومات حول الخاصية alignItems من توثيق CSS. إليك المثال التالي (تجربة حية):

import React, { useState } from "react";
import {
  View,
  TouchableOpacity,
  Text,
  StyleSheet,
} from "react-native";

const AlignItemsLayout = () => {
  const [alignItems, setAlignItems] = useState("stretch");

  return (
    <PreviewLayout
      label="alignItems"
      selectedValue={alignItems}
      values={[
        "stretch",
        "flex-start",
        "flex-end",
        "center",
        "baseline",
      ]}
      setSelectedValue={setAlignItems}
    >
      <View
        style={[styles.box, { backgroundColor: "powderblue" }]}
      />
      <View
        style={[styles.box, { backgroundColor: "skyblue" }]}
      />
      <View
        style={[
          styles.box,
          {
            backgroundColor: "steelblue",
            width: "auto",
            minWidth: 50,
          },
        ]}
      />
    </PreviewLayout>
  );
};

const PreviewLayout = ({
  label,
  children,
  values,
  selectedValue,
  setSelectedValue,
}) => (
  <View style={{ padding: 10, flex: 1 }}>
    <Text style={styles.label}>{label}</Text>
    <View style={styles.row}>
      {values.map((value) => (
        <TouchableOpacity
          key={value}
          onPress={() => setSelectedValue(value)}
          style={[
            styles.button,
            selectedValue === value && styles.selected,
          ]}
        >
          <Text
            style={[
              styles.buttonLabel,
              selectedValue === value &&
                styles.selectedLabel,
            ]}
          >
            {value}
          </Text>
        </TouchableOpacity>
      ))}
    </View>
    <View
      style={[
        styles.container,
        { [label]: selectedValue },
      ]}
    >
      {children}
    </View>
  </View>
);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: 8,
    backgroundColor: "aliceblue",
    minHeight: 200,
  },
  box: {
    width: 50,
    height: 50,
  },
  row: {
    flexDirection: "row",
    flexWrap: "wrap",
  },
  button: {
    paddingHorizontal: 8,
    paddingVertical: 6,
    borderRadius: 4,
    backgroundColor: "oldlace",
    alignSelf: "flex-start",
    marginHorizontal: "1%",
    marginBottom: 6,
    minWidth: "48%",
    textAlign: "center",
  },
  selected: {
    backgroundColor: "coral",
    borderWidth: 0,
  },
  buttonLabel: {
    fontSize: 12,
    fontWeight: "500",
    color: "coral",
  },
  selectedLabel: {
    color: "white",
  },
  label: {
    textAlign: "center",
    marginBottom: 10,
    fontSize: 24,
  },
});

export default AlignItemsLayout;

الخاصية alignSelf

تتمتع الخاصية alignSelf بنفس خيارات وتأثير الخاصية alignItems، ولكن يمكنك تطبيق الخاصية alignSelf على ابن واحد لتغيير محاذاته ضمن المكوّن الأب، بدلًا من التأثير على الأبناء ضمن الحاوية. تعدّل الخاصية alignSelf أيّ خيار ضبطه الأب مستخدمًا الخاصية alignItems.

إليك المثال التالي (تجربة حية):

import React, { useState } from "react";
import { View, TouchableOpacity, Text, StyleSheet } from "react-native";

const AlignSelfLayout = () => {
  const [alignSelf, setAlignSelf] = useState("stretch");

  return (
    <PreviewLayout
      label="alignSelf"
      selectedValue={alignSelf}
      values={["stretch", "flex-start", "flex-end", "center", "baseline"]}
      setSelectedValue={setAlignSelf}>
        <View
          style={[styles.box, {
            alignSelf,
            width: "auto",
            minWidth: 50,
            backgroundColor: "powderblue",
          }]}
        />
      <View
        style={[styles.box, { backgroundColor: "skyblue" }]}
      />
      <View
        style={[styles.box, { backgroundColor: "steelblue" }]}
      />
    </PreviewLayout>
  );
};

const PreviewLayout = ({
  label,
  children,
  values,
  selectedValue,
  setSelectedValue,
}) => (
  <View style={{ padding: 10, flex: 1 }}>
    <Text style={styles.label}>{label}</Text>
    <View style={styles.row}>
      {values.map((value) => (
        <TouchableOpacity
          key={value}
          onPress={() => setSelectedValue(value)}
          style={[
            styles.button,
            selectedValue === value && styles.selected,
          ]}
        >
          <Text
            style={[
              styles.buttonLabel,
              selectedValue === value &&
                styles.selectedLabel,
            ]}
          >
            {value}
          </Text>
        </TouchableOpacity>
      ))}
    </View>
    <View style={styles.container}>
      {children}
    </View>
  </View>
);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: 8,
    backgroundColor: "aliceblue",
    minHeight: 200,
  },
  box: {
    width: 50,
    height: 50,
  },
  row: {
    flexDirection: "row",
    flexWrap: "wrap",
  },
  button: {
    paddingHorizontal: 8,
    paddingVertical: 6,
    borderRadius: 4,
    backgroundColor: "oldlace",
    alignSelf: "flex-start",
    marginHorizontal: "1%",
    marginBottom: 6,
    minWidth: "48%",
    textAlign: "center",
  },
  selected: {
    backgroundColor: "coral",
    borderWidth: 0,
  },
  buttonLabel: {
    fontSize: 12,
    fontWeight: "500",
    color: "coral",
  },
  selectedLabel: {
    color: "white",
  },
  label: {
    textAlign: "center",
    marginBottom: 10,
    fontSize: 24,
  },
});

export default AlignSelfLayout;

الخاصية alignContent

تحدد الخاصية alignContent توزيع السطور على طول المحور المتعامد مع المحور الرئيسي، وهذا له تأثير فقط عندما تستطيع العناصر الالتفاف إلى عدة أسطر باستخدام الخاصية flexWrap.

  • flex-start (القيمة الافتراضية): تحاذي هذه القيمة السطور الملتفّة مع بداية محور الحاوية المتعامد مع المحور الرئيسي.
  • flex-end: تحاذي السطور الملتفة مع نهاية محور الحاوية المتعامد مع المحور الرئيسي.
  • stretch (القيمة الافتراضية عند استخدام Yoga على الويب): تمدّد السطور الملتفة لتتناسب مع ارتفاع محور الحاوية المتعامد مع المحور الرئيسي.
  • center: تحاذي السطور الملتفة مع مركز محور الحاوية المتعامد مع المحور الرئيسي.
  • space-between: تكون المسافة بين السطور الملتفة متساوية على طول محور الحاوية المتعامد مع المحور الرئيسي، وتُوزَّع المسافة المتبقية بين السطور.
  • space-around: تكون المسافة متساوية بين السطور الملتفة على طول محور الحاوية المتعامد مع المحور الرئيسي، وتُوزَّع المسافة المتبقية حول السطور، فإن استخدام القيمة space-around سيؤدي إلى توزيع المسافة المتبقية على بداية السطر الأول ونهاية السطر الأخير.

اطّلع على مزيد من المعلومات حول الخاصية alignContent من توثيق CSS.

إليك المثال التالي (تجربة حية):

import React, { useState } from "react";
import { View, TouchableOpacity, Text, StyleSheet } from "react-native";

const AlignContentLayout = () => {
  const [alignContent, setAlignContent] = useState("flex-start");

  return (
    <PreviewLayout
      label="alignContent"
      selectedValue={alignContent}
      values={[
        "flex-start",
        "flex-end",
        "stretch",
        "center",
        "space-between",
        "space-around",
      ]}
      setSelectedValue={setAlignContent}>
      <View
        style={[styles.box, { backgroundColor: "orangered" }]}
      />
      <View
        style={[styles.box, { backgroundColor: "orange" }]}
      />
      <View
        style={[styles.box, { backgroundColor: "mediumseagreen" }]}
      />
      <View
        style={[styles.box, { backgroundColor: "deepskyblue" }]}
      />
      <View
        style={[styles.box, { backgroundColor: "mediumturquoise" }]}
      />
      <View
        style={[styles.box, { backgroundColor: "mediumslateblue" }]}
      />
      <View
        style={[styles.box, { backgroundColor: "purple" }]}
      />
    </PreviewLayout>
  );
};

const PreviewLayout = ({
  label,
  children,
  values,
  selectedValue,
  setSelectedValue,
}) => (
  <View style={{ padding: 10, flex: 1 }}>
    <Text style={styles.label}>{label}</Text>
    <View style={styles.row}>
      {values.map((value) => (
        <TouchableOpacity
          key={value}
          onPress={() => setSelectedValue(value)}
          style={[
            styles.button,
            selectedValue === value && styles.selected,
          ]}
        >
          <Text
            style={[
              styles.buttonLabel,
              selectedValue === value &&
                styles.selectedLabel,
            ]}
          >
            {value}
          </Text>
        </TouchableOpacity>
      ))}
    </View>
    <View
      style={[
        styles.container,
        { [label]: selectedValue },
      ]}
    >
      {children}
    </View>
  </View>
);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexWrap: "wrap",
    marginTop: 8,
    backgroundColor: "aliceblue",
    maxHeight: 400,
  },
  box: {
    width: 50,
    height: 80,
  },
  row: {
    flexDirection: "row",
    flexWrap: "wrap",
  },
  button: {
    paddingHorizontal: 8,
    paddingVertical: 6,
    borderRadius: 4,
    backgroundColor: "oldlace",
    alignSelf: "flex-start",
    marginHorizontal: "1%",
    marginBottom: 6,
    minWidth: "48%",
    textAlign: "center",
  },
  selected: {
    backgroundColor: "coral",
    borderWidth: 0,
  },
  buttonLabel: {
    fontSize: 12,
    fontWeight: "500",
    color: "coral",
  },
  selectedLabel: {
    color: "white",
  },
  label: {
    textAlign: "center",
    marginBottom: 10,
    fontSize: 24,
  },
});

export default AlignContentLayout;

الخاصية flexWrap

تُضبَط الخاصية flexWrap للحاويات وتتحكّم بما يحدث عندما يتجاوز الأبناء حجم الحاوية على طول المحور الرئيسي. يُجبَر الأبناء افتراضيًا على الالتزام بسطر واحد فقط (والذي يمكن أن يؤدي إلى تصغير shrink العناصر). إذا كان الالتفاف wrapping مسموحًا، فستلتف العناصر إلى عدة أسطر على طول المحور الرئيسي إن لزم الأمر.

يمكن استخدام الخاصية alignContent عند التفاف الأسطر لتحديد كيفية وضع الأسطر في الحاوية.

اطّلع على مزيد من المعلومات حول الخاصية flexWrap من توثيق CSS.

إليك المثال التالي (تجربة حية):

import React, { useState } from "react";
import { View, TouchableOpacity, Text, StyleSheet } from "react-native";

const FlexWrapLayout = () => {
  const [flexWrap, setFlexWrap] = useState("wrap");

  return (
    <PreviewLayout
      label="flexWrap"
      selectedValue={flexWrap}
      values={["wrap", "no-wrap"]}
      setSelectedValue={setFlexWrap}>
      <View
        style={[styles.box, { backgroundColor: "orangered" }]}
      />
      <View
        style={[styles.box, { backgroundColor: "orange" }]}
      />
      <View
        style={[styles.box, { backgroundColor: "mediumseagreen" }]}
      />
      <View
        style={[styles.box, { backgroundColor: "deepskyblue" }]}
      />
      <View
        style={[styles.box, { backgroundColor: "mediumturquoise" }]}
      />
      <View
        style={[styles.box, { backgroundColor: "mediumslateblue" }]}
      />
      <View
        style={[styles.box, { backgroundColor: "purple" }]}
      />
    </PreviewLayout>
  );
};

const PreviewLayout = ({
  label,
  children,
  values,
  selectedValue,
  setSelectedValue,
}) => (
  <View style={{ padding: 10, flex: 1 }}>
    <Text style={styles.label}>{label}</Text>
    <View style={styles.row}>
      {values.map((value) => (
        <TouchableOpacity
          key={value}
          onPress={() => setSelectedValue(value)}
          style={[
            styles.button,
            selectedValue === value && styles.selected,
          ]}
        >
          <Text
            style={[
              styles.buttonLabel,
              selectedValue === value &&
                styles.selectedLabel,
            ]}
          >
            {value}
          </Text>
        </TouchableOpacity>
      ))}
    </View>
    <View
      style={[
        styles.container,
        { [label]: selectedValue },
      ]}
    >
      {children}
    </View>
  </View>
);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: 8,
    backgroundColor: "aliceblue",
    maxHeight: 400,
  },
  box: {
    width: 50,
    height: 80,
  },
  row: {
    flexDirection: "row",
    flexWrap: "wrap",
  },
  button: {
    paddingHorizontal: 8,
    paddingVertical: 6,
    borderRadius: 4,
    backgroundColor: "oldlace",
    marginHorizontal: "1%",
    marginBottom: 6,
    minWidth: "48%",
    textAlign: "center",
  },
  selected: {
    backgroundColor: "coral",
    borderWidth: 0,
  },
  buttonLabel: {
    fontSize: 12,
    fontWeight: "500",
    color: "coral",
  },
  selectedLabel: {
    color: "white",
  },
  label: {
    textAlign: "center",
    marginBottom: 10,
    fontSize: 24,
  },
});

export default FlexWrapLayout;

الخاصيات flexBasis و flexGrow و flexShrink

  • الخاصية flexBasis هي طريقة مستقلة عن المحاور لإعطاء العنصر حجمًا افتراضيًّا على طول المحور الرئيسي، ويتشابه إعداد flexBasis للمكوّن الابن مع إعداد العرض width للمكوّن الابن إذا كان الأب حاويةً لها الخاصية flexDirection: row، أو مع إعداد الارتفاع height للمكوّن الابن إذا كان الأب عبارة عن حاويةً لها الخاصية flexDirection: column. وتمثّل الخاصية flexBasis حجم العنصر الافتراضي قبل أن تُطبَّق عليه الخاصيتان flexShrink وflexGrow.
  • تحدّد الخاصية flexGrow كيفيّة توزيع المسافات بين المكوّنات الأبناء ضمن الحاوية على طول المحور الرئيسي، حيث توزّع الحاوية -بعد وضع المكونات الأبناء- المسافة المتبقية بينها، بناءً على قيم الخاصية flexGrow الخاصّة بكلّ مكوّن ابن، وتقبل flexGrow أيّ قيمةٍ عشرية أكبر من الصفر أو تساويه، حيث يكون الصفر هو قيمتها الافتراضيّة. توزّع الحاوية المسافةَ المتبقية بين المكونات الأبناء توزيعًا متناسبًا مع قيم flexGrow الخاصة بالأبناء.
  • تحدّد الخاصية flexShrink كيفيّة تصغير المكونات الأبناء على طول المحور الرئيسي عندما يتجاوز حجم المكونات الأبناء الكلي حجمَ الحاوية على طول المحور الرئيسيّ، وهذه الخاصيّة شبيهةٌ جدًا بالخاصيّة flexGrow عند عَدّ الحجم الزائد بمثابة مسافة متبقيةٍ سالبة القيمة، وتتعاون هاتان الخاصيتان فيما بينهما للسماح للمكونات الأبناء بالتمدد والتقلص حسب الحاجة. تقبل الخاصية flexShrink أيّ قيمةٍ عشريّة أكبر من الصفر أو تساويه، حيث يكون الصفر هو قيمتها الافتراضيّة (الواحد هو قيمتها الافتراضيّة على الويب)، وتقلّص الحاوية المكونات الأبناء تقليصًا متناسبًا مع قيم flexShrink الخاصة بالأبناء.

اطّلع على مزيد من المعلومات حول الخاصيات flexBasis و flexGrow و flexShrink من توثيق CSS.

إليك المثال التالي (تجربة حية):

import React, { useState } from "react";
import {
  View,
  Text,
  TextInput,
  StyleSheet,
} from "react-native";

const App = () => {
  const [powderblue, setPowderblue] = useState({
    flexGrow: 0,
    flexShrink: 1,
    flexBasis: "auto",
  });
  const [skyblue, setSkyblue] = useState({
    flexGrow: 1,
    flexShrink: 0,
    flexBasis: 100,
  });
  const [steelblue, setSteelblue] = useState({
    flexGrow: 0,
    flexShrink: 1,
    flexBasis: 200,
  });
  return (
    <View style={styles.container}>
      <View
        style={[
          styles.container,
          {
            flexDirection: "row",
            alignContent: "space-between",
          },
        ]}
      >
        <BoxInfo
          color="powderblue"
          {...powderblue}
          setStyle={setPowderblue}
        />
        <BoxInfo
          color="skyblue"
          {...skyblue}
          setStyle={setSkyblue}
        />
        <BoxInfo
          color="steelblue"
          {...steelblue}
          setStyle={setSteelblue}
        />
      </View>
      <View style={styles.previewContainer}>
        <View
          style={[
            styles.box,
            {
              flexBasis: powderblue.flexBasis,
              flexGrow: powderblue.flexGrow,
              flexShrink: powderblue.flexShrink,
              backgroundColor: "powderblue",
            },
          ]}
        />
        <View
          style={[
            styles.box,
            {
              flexBasis: skyblue.flexBasis,
              flexGrow: skyblue.flexGrow,
              flexShrink: skyblue.flexShrink,
              backgroundColor: "skyblue",
            },
          ]}
        />
        <View
          style={[
            styles.box,
            {
              flexBasis: steelblue.flexBasis,
              flexGrow: steelblue.flexGrow,
              flexShrink: steelblue.flexShrink,
              backgroundColor: "steelblue",
            },
          ]}
        />
      </View>
    </View>
  );
};

const BoxInfo = ({
  color,
  flexBasis,
  flexShrink,
  setStyle,
  flexGrow,
}) => (
  <View style={[styles.row, { flexDirection: "column" }]}>
    <View
      style={[
        styles.boxLabel,
        {
          backgroundColor: color,
        },
      ]}
    >
      <Text
        style={{
          color: "#fff",
          fontWeight: 500,
          textAlign: "center",
        }}
      >
        Box
      </Text>
    </View>
    <Text style={styles.label}>flexBasis</Text>
    <TextInput
      value={flexBasis}
      style={styles.input}
      onChangeText={(fB) =>
        setStyle((value) => ({
          ...value,
          flexBasis: isNaN(parseInt(fB))
            ? "auto"
            : parseInt(fB),
        }))
      }
    />
    <Text style={styles.label}>flexShrink</Text>
    <TextInput
      value={flexShrink}
      style={styles.input}
      onChangeText={(fS) =>
        setStyle((value) => ({
          ...value,
          flexShrink: isNaN(parseInt(fS))
            ? ""
            : parseInt(fS),
        }))
      }
    />
    <Text style={styles.label}>flexGrow</Text>
    <TextInput
      value={flexGrow}
      style={styles.input}
      onChangeText={(fG) =>
        setStyle((value) => ({
          ...value,
          flexGrow: isNaN(parseInt(fG))
            ? ""
            : parseInt(fG),
        }))
      }
    />
  </View>
);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingHorizontal: 10,
  },
  box: {
    flex: 1,
    height: 50,
    width: 50,
  },
  boxLabel: {
    minWidth: 80,
    padding: 8,
    borderRadius: 4,
    marginTop: 8,
  },
  label: {
    marginTop: 6,
    fontSize: 16,
    fontWeight: "100",
  },
  previewContainer: {
    flex: 1,
    flexDirection: "row",
    backgroundColor: "aliceblue",
  },
  row: {
    flex: 1,
    flexDirection: "row",
    flexWrap: "wrap",
    alignItems: "center",
    marginBottom: 10,
  },
  input: {
    borderBottomWidth: 1,
    paddingVertical: 3,
    width: 50,
    textAlign: "center",
  },
});

export default App;

العرض والارتفاع

تحدد خاصية العرض width عرض منطقة محتوى العنصر، وتحدّد خاصية الارتفاع height ارتفاع منطقة محتوى العنصر.

يمكن أن تأخذ كلٌّ من الخاصيتين width و height القيم التالية:

  • auto (القيمة الافتراضية): يحسب إطار عمل React Native عرض أو ارتفاع العنصر بناءً على محتواه، سواء كان ذلك المحتوى ابنًا آخر أو نصًا أو صورة.
  • pixels: تحدّد هذه القيمة العرض أو الارتفاع بالبكسلات المطلقة، حيث قد يكون هذا هو بُعد العقدة النهائي وقد لا يكون كذلك، اعتمادًا على الأنماط الأخرى التي تُضبَط للمكوّن.
  • percentage: تحدّد هذه القيمة العرض أو الارتفاع على أنها نسبة مئوية من عرض المكوّن الأب أو ارتفاعه.

إليك المثال التالي (تجربة حية):

import React, { useState } from "react";
import {
  View,
  SafeAreaView,
  TouchableOpacity,
  Text,
  StyleSheet,
} from "react-native";

const WidthHeightBasics = () => {
  const [widthType, setWidthType] = useState("auto");
  const [heightType, setHeightType] = useState("auto");

  return (
    <PreviewLayout
      widthType={widthType}
      heightType={heightType}
      widthValues={["auto", 300, "80%"]}
      heightValues={["auto", 200, "60%"]}
      setWidthType={setWidthType}
      setHeightType={setHeightType}
    >
      <View
        style={{
          alignSelf: "flex-start",
          backgroundColor: "aliceblue",
          height: heightType,
          width: widthType,
          padding: 15,
        }}
      >
        <View
          style={[
            styles.box,
            { backgroundColor: "powderblue" },
          ]}
        />
        <View
          style={[
            styles.box,
            { backgroundColor: "skyblue" },
          ]}
        />
        <View
          style={[
            styles.box,
            { backgroundColor: "steelblue" },
          ]}
        />
      </View>
    </PreviewLayout>
  );
};

const PreviewLayout = ({
  children,
  widthType,
  heightType,
  widthValues,
  heightValues,
  setWidthType,
  setHeightType,
}) => (
  <View style={{ flex: 1, padding: 10 }}>
    <View style={styles.row}>
      <Text style={styles.label}>width </Text>
      {widthValues.map((value) => (
        <TouchableOpacity
          key={value}
          onPress={() => setWidthType(value)}
          style={[
            styles.button,
            widthType === value && styles.selected,
          ]}
        >
          <Text
            style={[
              styles.buttonLabel,
              widthType === value && styles.selectedLabel,
            ]}
          >
            {value}
          </Text>
        </TouchableOpacity>
      ))}
    </View>
    <View style={styles.row}>
      <Text style={styles.label}>height </Text>
      {heightValues.map((value) => (
        <TouchableOpacity
          key={value}
          onPress={() => setHeightType(value)}
          style={[
            styles.button,
            heightType === value && styles.selected,
          ]}
        >
          <Text
            style={[
              styles.buttonLabel,
              heightType === value && styles.selectedLabel,
            ]}
          >
            {value}
          </Text>
        </TouchableOpacity>
      ))}
    </View>
    {children}
  </View>
);

const styles = StyleSheet.create({
  box: {
    width: 50,
    height: 50,
  },
  row: {
    flexDirection: "row",
    flexWrap: "wrap",
  },
  button: {
    padding: 8,
    borderRadius: 4,
    backgroundColor: "oldlace",
    alignSelf: "flex-start",
    marginRight: 10,
    marginBottom: 10,
  },
  selected: {
    backgroundColor: "coral",
    shadowOpacity: 0,
    borderWidth: 0,
  },
  buttonLabel: {
    fontSize: 12,
    fontWeight: "500",
    color: "coral",
  },
  selectedLabel: {
    color: "white",
  },
  label: {
    textAlign: "center",
    marginBottom: 10,
    fontSize: 24,
  },
});

export default WidthHeightBasics;

التخطيط المطلق Absolute والنسبي Relative

يحدّد نوع خاصية الموضع position لعنصرٍ ما كيفية وضعه ضمن المكوّن الأب.

  • relative (القيمة الافتراضية): يوضَع العنصر افتراضيًا موضعًا نسبيًا، وهذا يعني أن العنصر يُوضَع وفقًا لتدفق التخطيط الطبيعي، ثم يُزاح بالنسبة إلى هذا الموضع بناءً على القيم top و right و bottom و left، إذ لا تؤثر الإزاحة على موضع أي عنصر شقيق أو أب.
  • absolute: لا يشترك العنصر في تدفق التخطيط الطبيعي عند وضعه بموضع مطلق، وإنما يوضَع بصورةٍ مستقلة عن أشقائه، حيث يُحدَّد الموضع بناءً على القيم top و right و bottom و left.

إليك المثال التالي (تجربة حية):

import React, { useState } from "react";
import {
  View,
  SafeAreaView,
  TouchableOpacity,
  Text,
  StyleSheet,
} from "react-native";

const PositionLayout = () => {
  const [position, setPosition] = useState("relative");

  return (
    <PreviewLayout
      label="position"
      selectedValue={position}
      values={["relative", "absolute"]}
      setSelectedValue={setPosition}
    >
      <View
        style={[
          styles.box,
          {
            top: 25,
            left: 25,
            position,
            backgroundColor: "powderblue",
          },
        ]}
      />
      <View
        style={[
          styles.box,
          {
            top: 50,
            left: 50,
            position,
            backgroundColor: "skyblue",
          },
        ]}
      />
      <View
        style={[
          styles.box,
          {
            top: 75,
            left: 75,
            position,
            backgroundColor: "steelblue",
          },
        ]}
      />
    </PreviewLayout>
  );
};

const PreviewLayout = ({
  label,
  children,
  values,
  selectedValue,
  setSelectedValue,
}) => (
  <View style={{ padding: 10, flex: 1 }}>
    <Text style={styles.label}>{label}</Text>
    <View style={styles.row}>
      {values.map((value) => (
        <TouchableOpacity
          key={value}
          onPress={() => setSelectedValue(value)}
          style={[
            styles.button,
            selectedValue === value && styles.selected,
          ]}
        >
          <Text
            style={[
              styles.buttonLabel,
              selectedValue === value &&
                styles.selectedLabel,
            ]}
          >
            {value}
          </Text>
        </TouchableOpacity>
      ))}
    </View>
    <View style={styles.container}>{children}</View>
  </View>
);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: 8,
    backgroundColor: "aliceblue",
    minHeight: 200,
  },
  box: {
    width: 50,
    height: 50,
  },
  row: {
    flexDirection: "row",
    flexWrap: "wrap",
  },
  button: {
    paddingHorizontal: 8,
    paddingVertical: 6,
    borderRadius: 4,
    backgroundColor: "oldlace",
    alignSelf: "flex-start",
    marginHorizontal: "1%",
    marginBottom: 6,
    minWidth: "48%",
    textAlign: "center",
  },
  selected: {
    backgroundColor: "coral",
    borderWidth: 0,
  },
  buttonLabel: {
    fontSize: 12,
    fontWeight: "500",
    color: "coral",
  },
  selectedLabel: {
    color: "white",
  },
  label: {
    textAlign: "center",
    marginBottom: 10,
    fontSize: 24,
  },
});

export default PositionLayout;

مزيد من المعلومات

اطّلع على ملعب yoga التفاعلي الذي يمكنك استخدامه لفهم flexbox فهمًا أفضل، واطلع أيضًا على توثيق CSS العربي، ويمكنك أيضًا الاطّلاع على بعض الأمثلة من Wix Engineers.

هذه هي الأساسيات، لكن هناك عدّة أنماط أخرى قد تحتاج إليها لتخطيط تطبيقاتك. اطّلع على قائمة خاصيّات التخطيط الكاملة.

مصادر