{"id":"l-rn-2-2","courseId":"react-native-apps","lang":"ar","kind":"lesson","summary":"رتّب صفوف القوائم والشاشات في Trailhead باستخدام flexbox، مع معرفة القيم الافتراضية على الجوّال (الاتجاه العمودي، وعدم الانكماش، والتمدّد) التي تفسّر معظم التخطيطات المنضغطة أو الفائضة.","html":"<p>هذا خطأ تخطيط يواجهه كل مطوّر ويب في أسبوعه الأول مع React Native: صفّ فيه أيقونة وعنوان وسهم يبدو مثاليًا مع “Ridge Loop”، وينكسر مع “Old Mill Creek Trail to Eagle Point Lookout”. يختفي السهم خلف الحافة اليمنى. لا عيب في معرفتك بالـ flexbox؛ كل ما في الأمر أن flexbox في React Native يبدأ من قيم افتراضية مختلفة.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">الـ flexbox نفسه، بقيم افتراضية مختلفة</h2>\n<p>يرتّب React Native كل View باستخدام flexbox (عبر Yoga، محرّك تخطيط يطبّق المواصفة). لا يوجد <code dir=\"ltr\">display: block</code> ولا <code dir=\"ltr\">inline</code>؛ فكل View حاوية flex. أربع قيم افتراضية تختلف عن الويب:</p>\n<div class=\"table-wrap\" role=\"region\" aria-label=\"جدول قابل للتمرير\" tabindex=\"0\"><table><thead>\n<tr>\n<th>الخاصية</th>\n<th>الافتراضي على الويب</th>\n<th>الافتراضي في React Native</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code dir=\"ltr\">flexDirection</code></td>\n<td><code dir=\"ltr\">row</code></td>\n<td><code dir=\"ltr\">column</code></td>\n</tr>\n<tr>\n<td><code dir=\"ltr\">flexShrink</code></td>\n<td><code dir=\"ltr\">1</code></td>\n<td><code dir=\"ltr\">0</code></td>\n</tr>\n<tr>\n<td><code dir=\"ltr\">alignContent</code></td>\n<td><code dir=\"ltr\">normal</code></td>\n<td><code dir=\"ltr\">flex-start</code></td>\n</tr>\n<tr>\n<td><code dir=\"ltr\">flex</code></td>\n<td>اختصار لعدّة خصائص</td>\n<td>رقم واحد</td>\n</tr>\n</tbody>\n</table></div><p>أول اثنتين تفسّران معظم المفاجآت. الأبناء يتكدّسون عموديًا ما لم تقل <code dir=\"ltr\">flexDirection: 'row'</code>، و<strong>لا ينكمشون</strong> حين تنفد المساحة، ولهذا دفع ذلك العنوان الطويل السهمَ بعيدًا.</p>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 680 260\" role=\"img\" aria-labelledby=\"l-rn-2-2-t1\"><defs><marker id=\"arrow-l-rn-2-2-1\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\"><path d=\"M0 0 L10 5 L0 10 z\" class=\"d-arrowhead\"/></marker></defs>\n  <title id=\"l-rn-2-2-t1\">في العمود، يمتد المحور الرئيسي من الأعلى إلى الأسفل، فيعمل justifyContent عموديًا ويعمل alignItems أفقيًا. وفي الصف، يمتد المحور الرئيسي من اليسار إلى اليمين وتتبادل الخاصيتان دوريهما.</title>\n  <text class=\"d-label-strong\" x=\"160\" y=\"24\" text-anchor=\"middle\">flexDirection: 'column' (الافتراضي)</text>\n  <rect class=\"d-box\" x=\"70\" y=\"40\" width=\"180\" height=\"200\" rx=\"12\"/>\n  <rect class=\"d-box-primary\" x=\"90\" y=\"58\" width=\"140\" height=\"36\" rx=\"8\"/>\n  <rect class=\"d-box-primary\" x=\"90\" y=\"104\" width=\"140\" height=\"36\" rx=\"8\"/>\n  <rect class=\"d-box-primary\" x=\"90\" y=\"150\" width=\"140\" height=\"36\" rx=\"8\"/>\n  <path class=\"d-arrow\" d=\"M40 50 L40 225\" marker-end=\"url(#arrow-l-rn-2-2-1)\"/>\n  <text class=\"d-label-muted\" x=\"30\" y=\"140\" text-anchor=\"middle\" transform=\"rotate(-90 30 140)\">الرئيسي: justifyContent</text>\n  <path class=\"d-arrow d-dashed\" d=\"M80 225 L240 225\" marker-end=\"url(#arrow-l-rn-2-2-1)\"/>\n  <text class=\"d-label-muted\" x=\"160\" y=\"214\" text-anchor=\"middle\">العرضي: alignItems</text>\n  <text class=\"d-label-strong\" x=\"500\" y=\"24\" text-anchor=\"middle\">flexDirection: 'row'</text>\n  <rect class=\"d-box\" x=\"370\" y=\"40\" width=\"270\" height=\"140\" rx=\"12\"/>\n  <rect class=\"d-box-accent\" x=\"386\" y=\"60\" width=\"56\" height=\"56\" rx=\"8\"/>\n  <rect class=\"d-box-accent\" x=\"454\" y=\"60\" width=\"130\" height=\"56\" rx=\"8\"/>\n  <text class=\"d-label\" x=\"519\" y=\"93\" text-anchor=\"middle\">flex: 1</text>\n  <rect class=\"d-box-accent\" x=\"596\" y=\"60\" width=\"30\" height=\"56\" rx=\"8\"/>\n  <path class=\"d-arrow\" d=\"M380 205 L630 205\" marker-end=\"url(#arrow-l-rn-2-2-1)\"/>\n  <text class=\"d-label-muted\" x=\"505\" y=\"228\" text-anchor=\"middle\">الرئيسي: justifyContent</text>\n  <path class=\"d-arrow d-dashed\" d=\"M655 50 L655 170\" marker-end=\"url(#arrow-l-rn-2-2-1)\"/>\n</svg><figcaption>المحور الرئيسي والمحور العرضي في عمود وفي صف</figcaption></figure>\n<p>القواعد التي تعرفها ما زالت سارية: <code dir=\"ltr\">justifyContent</code> يعمل على المحور الرئيسي، و<code dir=\"ltr\">alignItems</code> على المحور العرضي. في العمود (الافتراضي)، يوسّط <code dir=\"ltr\">justifyContent: 'center'</code> عموديًا، ويوسّط <code dir=\"ltr\">alignItems: 'center'</code> أفقيًا. انتقل إلى صف فتتبادل الخاصيتان دوريهما.</p>\n<p>القيمة الافتراضية لـ <code dir=\"ltr\">alignItems</code> هي <code dir=\"ltr\">stretch</code>، فالابن في عمود يملأ العرض كاملًا ما لم تعطه عرضًا أو تغيّر <code dir=\"ltr\">alignItems</code>. ولهذا يمتد <code dir=\"ltr\">Text</code> له لون خلفية في عمود عادي من الحافة إلى الحافة.</p>\n<h2 id=\"sec-2\" tabindex=\"-1\">flex: 1، الخاصية التي ستكتبها أكثر من غيرها</h2>\n<p>في React Native، يأخذ <code dir=\"ltr\">flex</code> رقمًا واحدًا. و<code dir=\"ltr\">flex: 1</code> تعني «اكبر لتملأ المساحة المتبقية على المحور الرئيسي، ويُسمح لك بالانكماش». مكانان لا يكادان يستغنيان عنها أبدًا:</p>\n<ol>\n<li><strong>الـ View الجذري في كل شاشة</strong>، ليملأ الشاشة بدلًا من أن يلتصق بمحتواه.</li>\n<li><strong>كل أب لـ ScrollView أو FlatList</strong>، لأن حاوية التمرير تتمرّر داخل الارتفاع الذي يُعطى لها. فإن لم يحدّد أي سلف هذا الارتفاع، تكبر بحجم محتواها كله، ويُقطع الجزء السفلي دون أن تتمرّر أبدًا.</li>\n</ol>\n<p>حين تظهر الشاشة كشريط رفيع في الأعلى، أو حين لا تتمرّر قائمة، اصعد في الشجرة وابحث عن الـ <code dir=\"ltr\">flex: 1</code> المفقود.</p>\n<h2 id=\"sec-3\" tabindex=\"-1\">بناء صفّ الرحلة</h2>\n<p>هذا هو الصف الذي انكسر، بعد إصلاحه:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"tsx\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">src/components/HikeRow.tsx</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { Image, StyleSheet, Text, View } </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> 'react-native'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">export</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> HikeRow</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">({ </span><span style=\"color:#953800;--shiki-dark:#FFA657\">hike</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> }</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#953800;--shiki-dark:#FFA657\">hike</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#953800;--shiki-dark:#FFA657\">name</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> string</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; </span><span style=\"color:#953800;--shiki-dark:#FFA657\">distanceKm</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> number</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; </span><span style=\"color:#953800;--shiki-dark:#FFA657\">date</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> string</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; </span><span style=\"color:#953800;--shiki-dark:#FFA657\">thumbUrl</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> string</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> } }) {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">View</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> style</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">styles.row</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">      &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Image</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> source</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">{ uri: hike.thumbUrl }</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> style</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">styles.thumb</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> /></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">      &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">View</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> style</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">styles.body</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">        &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Text</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> style</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">styles.title</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> numberOfLines</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">{</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">hike.name</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Text</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">        &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Text</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> style</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">styles.meta</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">{</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">hike.distanceKm</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> km · </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">{</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">hike.date</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Text</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">      &#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">View</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">      &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Text</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> style</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">styles.chevron</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>›&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Text</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    &#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">View</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  );</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> styles</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> StyleSheet.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">create</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">({</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  row: { flexDirection: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'row'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, alignItems: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'center'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, gap: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">12</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, padding: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">12</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> },</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  thumb: { width: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">56</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, height: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">56</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, borderRadius: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">8</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> },</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  body: { flex: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> },</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  title: { fontSize: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">17</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, fontWeight: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'600'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> },</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  meta: { fontSize: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">14</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, color: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'#5c6b62'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, marginTop: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">2</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> },</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  chevron: { fontSize: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">24</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, color: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'#9aa79f'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> },</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">});</span></span></code></pre></div>\n<p>اقرأه محورًا محورًا. المحور الرئيسي للصف أفقي؛ و<code dir=\"ltr\">alignItems: 'center'</code> يوسّط الأبناء الثلاثة عموديًا بالنسبة إلى أطولهم (الصورة المصغّرة). للصورة المصغّرة والسهم أحجام ثابتة. أما الجسم فعليه <code dir=\"ltr\">flex: 1</code>، فيأخذ أي عرض يتبقّى، و<code dir=\"ltr\">numberOfLines={1}</code> يقتطع الاسم الطويل بعلامة حذف بدلًا من دفع السهم خارج الشاشة.</p>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">خطأ شائع</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>إصلاح الفيضان بعرض ثابت</span></p>\n<p>ضبط <code dir=\"ltr\">width: 220</code> على العنوان يناسب هاتف الاختبار لديك، وينكسر على هاتف Android صغير، وفي الوضع الأفقي، ولدى المستخدمين الذين يكبّرون النص. دع الـ flex يوزّع المساحة: أحجام ثابتة لما هو ثابت فعلًا (الأيقونات، الصور المصغّرة)، و<code dir=\"ltr\">flex: 1</code> للجزء الذي يجب أن يمتصّ الفرق.</p>\n</aside>\n<p>أداتان أخريان تُكملان التخطيط اليومي. يسمح <code dir=\"ltr\">alignSelf</code> لابن واحد بالخروج عن <code dir=\"ltr\">alignItems</code> الخاصة بأبيه: زرّ “Log a hike” في عمود متمدّد يمكنه استخدام <code dir=\"ltr\">alignSelf: 'flex-end'</code> ليستقرّ على اليمين بعرضه الطبيعي. أما <code dir=\"ltr\">aspectRatio</code> فيحدّد حجم الصندوق انطلاقًا من بُعد واحد، وهذا مثالي للصور: أعطِ صورة الدرب <code dir=\"ltr\">width: '100%'</code> و<code dir=\"ltr\">aspectRatio: 4 / 3</code>، فيتبع ارتفاعها عرض الشاشة على كل هاتف دون أن تحسب أي شيء.</p>\n<p>وحين يسيء تخطيطٌ التصرّف، تبقى أسرع حيلة لتصحيحه هي الأقدم: أعطِ الـ Views المشتبه بها لون خلفية فاقعًا مؤقتًا. سترى فورًا أي صندوق أصغر من اللازم، وأيها تمدّد، وأيها لم يحصل قط على <code dir=\"ltr\">flex: 1</code>.</p>\n<h2 id=\"sec-4\" tabindex=\"-1\">التموضع المطلق والالتفاف</h2>\n<p>كل View يكون <code dir=\"ltr\">position: 'relative'</code> افتراضيًا، لذا يضع <code dir=\"ltr\">position: 'absolute'</code> الابن بالنسبة إلى أبيه. هكذا تضع شارة “New” على زاوية صورة مصغّرة:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"tsx\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">TSX</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">View</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Image</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> source</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">{ uri: hike.thumbUrl }</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> style</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">styles.thumb</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> /></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">View</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> style</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">{ position: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'absolute'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, top: </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">-</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">4</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, right: </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">-</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">4</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, backgroundColor: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'#e8590c'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, borderRadius: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">8</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, paddingHorizontal: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">6</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> }</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Text</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> style</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">{ color: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'white'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, fontSize: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">11</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, fontWeight: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'700'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> }</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>NEW&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">Text</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  &#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">View</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">View</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span></code></pre></div>\n<p>ولصفّ من الوسوم (“steep”، “lake”، “dog-friendly”) يجب أن ينتقل إلى سطر ثانٍ حين تنفد المساحة، اجمع بين <code dir=\"ltr\">flexDirection: 'row'</code> و<code dir=\"ltr\">flexWrap: 'wrap'</code> و<code dir=\"ltr\">gap: 8</code>. التموضع المطلق يُخرج الابن من تدفّق الـ flex كليًا، لذا استخدمه للعناصر العائمة فقط، ولا تستخدمه أبدًا لتزييف تخطيط يستطيع الـ flex التعبير عنه.</p>\n<p>في الدرس التالي ستجعل هذه التخطيطات تصمد أمام أحجام الهواتف المختلفة، والنتوءات (notches)، والزوايا المستديرة، والفروق بين المنصّتين.</p>\n","toc":[{"id":"sec-1","text":"الـ flexbox نفسه، بقيم افتراضية مختلفة","level":2},{"id":"sec-2","text":"flex: 1، الخاصية التي ستكتبها أكثر من غيرها","level":2},{"id":"sec-3","text":"بناء صفّ الرحلة","level":2},{"id":"sec-4","text":"التموضع المطلق والالتفاف","level":2}],"takeaways":["كل View حاوية flex، والمحور الرئيسي يمتد من الأعلى إلى الأسفل افتراضيًا (<code dir=\"ltr\">flexDirection: 'column'</code>).","<code dir=\"ltr\">justifyContent</code> يحدّد مواضع الأبناء على المحور الرئيسي؛ و<code dir=\"ltr\">alignItems</code> يحدّدها على المحور العرضي، وقيمته الافتراضية <code dir=\"ltr\">stretch</code>.","الأبناء لا ينكمشون افتراضيًا في React Native، لذا يدفع العنوان الطويل إخوته خارج الشاشة حتى تعطيه <code dir=\"ltr\">flex: 1</code>.","<code dir=\"ltr\">flex: 1</code> تعني «خذ المساحة المتبقية»؛ والـ View الجذري في كل شاشة وكل أب لـ ScrollView يحتاجان إليها.","استخدم <code dir=\"ltr\">position: 'absolute'</code> للعناصر العائمة مثل الشارات، و<code dir=\"ltr\">flexWrap: 'wrap'</code> مع <code dir=\"ltr\">gap</code> لصفوف الوسوم."],"further":[{"title":"Layout with Flexbox","url":"https://reactnative.dev/docs/flexbox"},{"title":"Layout Props","url":"https://reactnative.dev/docs/layout-props"}],"quiz":[{"q":"<p>صفّ فيه صورة مصغّرة بعرض 56 نقطة، وعنوان، وسهم (chevron). أسماء الرحلات الطويلة تدفع السهم خارج الحافة اليمنى. ما الإصلاح؟</p>","options":[{"text":"أضف <code dir=\"ltr\">flexWrap: 'wrap'</code> إلى الصف.","why":"الالتفاف ينقل السهم إلى سطر ثانٍ، وهذا تخطيط معطوب من نوع آخر."},{"text":"أعطِ حاوية العنوان <code dir=\"ltr\">flex: 1</code> لتأخذ المساحة المتبقية فقط، فيلتفّ نصّها أو يُقتطع.","why":"صحيح. الأبناء لا ينكمشون افتراضيًا، وضبط <code dir=\"ltr\">flex</code> على 1 يجعل العمود الأوسط يمتصّ العرض المتبقي بدلًا من المطالبة بكامل عرض نصّه."},{"text":"اضبط <code dir=\"ltr\">overflow: 'hidden'</code> على الصف.","why":"هذا يقصّ السهم بدلًا من أن يفسح له مكانًا."},{"text":"أعطِ السهم <code dir=\"ltr\">flex: 1</code>.","why":"هذا يجعل السهم يكبر ليملأ المساحة، وهو عكس ما تريده تمامًا."}],"answer":1},{"q":"<p>في View بالتنسيقات الافتراضية، ضبطت <code dir=\"ltr\">justifyContent: 'center'</code>. أين يذهب الأبناء؟</p>","options":[{"text":"إلى المنتصف أفقيًا، في صف.","why":"هذا هو الافتراضي على الويب، حيث <code dir=\"ltr\">flex-direction</code> تساوي <code dir=\"ltr\">row</code>. أما React Native فالافتراضي فيه <code dir=\"ltr\">column</code>."},{"text":"لا يتغيّر مكانهم، لأن <code dir=\"ltr\">justifyContent</code> يحتاج أولًا إلى <code dir=\"ltr\">display: 'flex'</code>.","why":"كل View حاوية flex أصلًا، فلا يوجد شيء تحتاج إلى تفعيله."},{"text":"إلى المنتصف عموديًا، مكدّسين في عمود.","why":"صحيح. المحور الرئيسي عمودي افتراضيًا، لذا يوسّط <code dir=\"ltr\">justifyContent</code> الأبناء على امتداده."}],"answer":2},{"q":"<p>شاشة التفاصيل في Trailhead عبارة عن ScrollView داخل View، وهي لا تتمرّر؛ المحتوى يُقطَع ببساطة. ما السبب المرجّح؟</p>","options":[{"text":"الـ View الخارجي ليس عليه <code dir=\"ltr\">flex: 1</code>، فلا يجد الـ ScrollView ارتفاعًا محدودًا يتمرّر داخله.","why":"صحيح. يتمرّر الـ ScrollView داخل المساحة التي يمنحه إياها أبوه؛ ودون ارتفاع محدود يكبر بحجم محتواه فتقطعه الشاشة."},{"text":"يحتاج ScrollView إلى <code dir=\"ltr\">scrollEnabled={true}</code> ليتمرّر.","why":"قيمتها <code dir=\"ltr\">true</code> افتراضيًا أصلًا. تضبطها على <code dir=\"ltr\">false</code> لتعطيل التمرير."},{"text":"لا يتمرّر ScrollView على Android إلا أفقيًا.","why":"يتمرّر عموديًا على المنصّتين افتراضيًا؛ والـ prop المسمّى <code dir=\"ltr\">horizontal</code> هو ما يغيّر الاتجاه."}],"answer":0}],"exercise":{"kind":"fill","language":"tsx","template":"const styles = StyleSheet.create({\n  screen: { {{0}}: 1, backgroundColor: '#f6f8f6' },\n  row: {\n    flexDirection: '{{1}}',\n    alignItems: '{{2}}',\n    gap: 12,\n    padding: 12,\n  },\n  thumb: { width: 56, height: 56, borderRadius: 8 },\n  body: { flex: {{3}} },\n  chips: { flexDirection: 'row', flexWrap: '{{4}}', gap: 8 },\n  badge: { position: '{{5}}', top: -4, right: -4 },\n});","blanks":[{"answers":["flex"]},{"answers":["row"]},{"answers":["center"]},{"answers":["1"]},{"answers":["wrap"]},{"answers":["absolute"]}],"title":"نسّق صفّ الرحلة","prompt":"<p>أكمل تنسيقات القائمة في Trailhead بحيث:</p>\n<ol>\n<li>تملأ الشاشةُ مساحة العرض كلها،</li>\n<li>يرتّب كل صف الصورة المصغّرة والنص والسهم <strong>جنبًا إلى جنب</strong>، موسّطة عموديًا،</li>\n<li>يأخذ عمود النص العرض المتبقي فلا تدفع الأسماء الطويلة السهم بعيدًا،</li>\n<li>تنتقل وسوم الصعوبة إلى سطر ثانٍ حين تنفد المساحة،</li>\n<li>تستقرّ شارة “NEW” على زاوية الصورة المصغّرة دون أن تؤثّر في التخطيط.</li>\n</ol>\n","hints":["الاتجاه الافتراضي في React Native عمود. أيّ قيمة تضع الأبناء جنبًا إلى جنب؟","الخاصية التي تجعل View يأخذ المساحة المتبقية تأخذ رقمًا واحدًا.","الوسوم التي يجب أن تنتقل إلى السطر التالي تحتاج إلى قيمة التفاف؛ والعنصر العائم يخرج من تدفّق الـ flex بقيمة الـ position الخاصة به."],"explanation":"<p><code dir=\"ltr\">flex: 1</code> على الشاشة يجعلها تملأ مساحة العرض كلها. يغيّر الصف المحور الرئيسي بـ <code dir=\"ltr\">flexDirection: 'row'</code>، ويوسّط <code dir=\"ltr\">alignItems: 'center'</code> الأبناء على المحور العرضي (عموديًا). و<code dir=\"ltr\">flex: 1</code> على الجسم يمتصّ العرض المتبقي، وهذا مهم لأن الأبناء لا ينكمشون افتراضيًا. يسمح <code dir=\"ltr\">flexWrap: 'wrap'</code> للوسوم بالالتفاف، ويضع <code dir=\"ltr\">position: 'absolute'</code> الشارة بالنسبة إلى أبيها دون أن تشغل مساحة.</p>\n","checkLabels":{}},"words":618,"readMinutes":4}