Layout

בבסיס של עימוד מסך ב-React עומד מודל Flexbox. בעזרתו אפשר להגדיר האם הרכיבים בעמוד יוצבו לרוחב או לאורך. בעזרתו אפשר גם להגדיר בקלות את הרווחים והיישורים של הרכיבים.

Flexbox מכיל container ו-items.

כשעובדים עם Flexbox צריך לחשוב על הצירים שהרכיבים יושבים עליהם. בדרך כלל, הציר הראשי זורם משמאל לימין והציר המשני מלמעלה למטה. ב-React Native זה עובד אחרת. הציר הראשי הולך מלמעלה למטה והמשני משמאל לימין.

Code Setup

ניצור קומפוננטת Box מותאמת על מנת שנוכל להשתמש בה בקלות. הקומפוננטה הזאת תתפקד כ-item בתוך ה-flex container.

Box.js

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

export default function Box({ children, style }){
    return(
        <View style={[styles.box, style]}>
            <Text style={styles.text}>{ children }</Text>
        </View>
    )
}

const styles = StyleSheet.create({
    box: {
        backgroundColor: "#fff",
        padding: 20
    },
    text: {
        fontSize: 24,
        fontWeight: "bold",
        textAlign: "center",
        color: "#fff"
    }
})

נבנה מיכל בסיסי שמכיל Boxes על המסך. כל Box בצבע אחרת עם מסגרת מסביב ל-container כדי שנוכל לראות את הגבולות שלו.

import { View, Text, StyleSheet } from "react-native";
import Box from "../components/Box"

export default function Index() {
  return (
    <View style={styles.container}>
      <Box style={{ backgroundColor: "#8e9b00" }}>Box 1</Box>
      <Box style={{ backgroundColor: "#b65d1f" }}>Box 2</Box>
      <Box style={{ backgroundColor: "#1c4c56" }}>Box 3</Box>
      <Box style={{ backgroundColor: "#ab9156" }}>Box 4</Box>
      <Box style={{ backgroundColor: "#6b0803" }}>Box 5</Box>
      <Box style={{ backgroundColor: "#1c4c56" }}>Box 6</Box>
      <Box style={{ backgroundColor: "#b95f21" }}>Box 7</Box>
    </View>
  );
}

const styles = StyleSheet.create({
  container:{ 
    marginTop: 64,
    borderWidth: 6,
    borderColor: "red"
  },
})

ככה המסך נראה בשלב הזה:

Flex

התכונה Flex מגדירה לנו כמה מהתוכן ימלא את הציר הראשי שלנו. Flex מקבל ערך בין 0-1 שמגדיר כמה מהשטח הפנוי התוכן ימלא.

אם נגדיר View הוא ימלא את החלק שהילדים שלו תופסים, כלומר View ריק לא יתפוס שטח כלל. הגדרה של flex: 1 תגרום ל-View לתפוס את כל שטח המסך.

<View style={{backgroundColor: "lightblue", flex: 1}}></View>

בתמונה למעלה אפשר לראות לפי המסגרת האדומה שהשטח של ה-View עם 7 הקופסאות שבתוכו תופס רק מה שנחוץ להצגת הקופסאות. כדי שהוא יכיל את כל השטח הזמין נשנה את ערך ה-flex.

const styles = StyleSheet.create({
  container:{ 
    flex: 1,
    borderWidth: 6,
    borderColor: "red"
  },
}) 

אם נשים flex: 1 לקופסא הראשונה, נראה שהיא עשי וממלאת את כל השטח הפנוי.

<Box style={{ backgroundColor: "#8e9b00", flex: 1 }}>Box 1</Box>

אפשר לחלק את השטח באופן יחסי. למשל אם ניתן את flex: 1 לתיבה הראשונה ואת flex: 3 לתיבה השנייה, יהיה חיבור של 1+3 שזה 4 חלקים. התיבה הראשונה תקבל חלק אחד מהשטח הפנוי והשנייה 3 חלקים.

ככה זה יראה:

Flex Direction

Flex Direction קובע את הכיוון של הרכיבים בתוך ה-container. כברירת מחדל הכיוון הוא מלמעלה למטה מסומן על ידי הערך column.

ערך נוסף הוא column-reverse שהופך את סדר ההופעה על המסך. בתמונה השתמשתי ב-3 תיבות להצגה.

const styles = StyleSheet.create({
  container:{ 
    flex: 1,
    flexDirection: "column-reverse",
    borderWidth: 6,
    borderColor: "red"
  },
}) 

הערך הבא הוא row שמסדר את הרכיבים לשמאל לימין.

הערך האחרון הוא row-reverse שמסדר את העמודות מימין לשמאל.

Justify Content

Justify Content מגדיר את הפיזור של הרכיבים. ערך ברירת המחדל הוא flex-start. אם נגדיר את Justify Content להיות flex-end הרכיבים יהיו מיושרים לסוף הציר הראשי.

const styles = StyleSheet.create({
  container:{ 
    flex: 1,
    justifyContent: "flex-end",
    borderWidth: 6,
    borderColor: "red"
  },
}) 

אפשר לשים את התוכן גם במרכז עם center.

הערך space-between יחלק את העצמים בתוך השטח הפנוי.

יש את הערך space-around ואת space-evenly שיחלקו את הרכיבים עם רווחים בהתחלה ובסוף.

Align Items

Align Items מגדיר את יישור הרכיבים. ברירת המחדל היא stretch. כל תיבת נמתחת משמאל לימין. אפשרות נוספת היא flex-start, כל תיבה תצמד לשמאל ותתפוס את השטח של הרכיבים שבה.

const styles = StyleSheet.create({
  container:{ 
    flex: 1,
    alignItems: "flex-start",
    borderWidth: 6,
    borderColor: "red"
  },
}) 

באותו העקרון יעבוד flex-end. בחירה ב-center ימרכז את הרכיבים. אפשרות נוספת היא baseline. באפשרות זו יהיה מרכוז לפי המרכז של תוכן התיבה ולא לפי הגודל של התיבה עצמה.

Align Self

Align Self נותן שליטה למירכוז של כל רכיב בנפרד ולא לכל הרכיבים של ה-container. ברירת המחדל היא auto, מה שאומר שהתכונה נלקחת מרכיב האב. בקוד יש את אפשרויות היישור של הרכיבים וניתן לראות את ההשפעה של כל אחד בתמונה.

<View style={styles.container}>
      <Box style={{ backgroundColor: "#8e9b00", alignSelf: "flex-start" }}>Box 1</Box>
      <Box style={{ backgroundColor: "#b65d1f", alignSelf: "flex-end" }}>Box 2</Box>
      <Box style={{ backgroundColor: "#1c4c56", alignSelf: "center" }}>Box 3</Box>
      <Box style={{ backgroundColor: "#ab9156", alignSelf: "stretch" }}>Box 4</Box>
      <Box style={{ backgroundColor: "#6b0803", alignSelf: "auto" }}>Box 5</Box>
      <Box style={{ backgroundColor: "#1c4c56" }}>Box 6</Box>
      <Box style={{ backgroundColor: "#b95f21" }}>Box 7</Box>
</View>

Flex Wrap

Flex Wrap מאפשר שליטה על זרימת הרכיבים כאשר יש מקום מוגבל לשטח שמכיל אותם. אם נגביל את שטח ה-container נראה שיש שגלישה של הרכיבים אל מחוץ לו.

const styles = StyleSheet.create({
  container:{ 
    // flex: 1,
    height: 300,
    borderWidth: 6,
    borderColor: "red"
  },
}) 

כדי למנוע את זה אפשר להשתמש ב-Flex Wrap. Flex Wrap יכול לקבל אחת מ-3 אפשרויות. no-wrap, זאת ברירת המחדל. באפשרות הזאת התוכן יגלוש מחוץ ל-container. האפשרות הבאה היא wrap. באפשרות הזאת הרכיבים יתכנסו לתוך ה-container. האפשרות הזאת תפעל רק במידה ואין מספיק מקום.

const styles = StyleSheet.create({
  container:{ 
    // flex: 1,
    flexWrap: "wrap",
    height: 300,
    borderWidth: 6,
    borderColor: "red"
  },
})

האפשרות השלישית היא wrap-reverse. הרכיבים יתחילו מסוף המיכל ולא מהתחלתו.

אפשר לערום את הרכיבים בשורה ולא רק בעמודה.

const styles = StyleSheet.create({
  container:{ 
    flex: 1,
    flexDirection: "row",
    flexWrap: "wrap",
    borderWidth: 6,
    borderColor: "red"
  },
})

Align Content

Align Content שולט ביישור התוכן של ה-container. ברירת המחדל היא flex-start. אם נבחר באפשרות flex-end נראה שכל התוכן של ה-container נדחף לימין.

const styles = StyleSheet.create({
  container:{ 
    // flex: 1,
    height: 300,
    flexWrap: "wrap",
    alignContent: "flex-end",
    borderWidth: 6,
    borderColor: "red"
  },
})

אפשר למרכז עם הערך center או להשתמש בערך stretch והתוכן יקח את כל המקום הזמין. הערך space-between ימקם את התוכן בין הקצוות. יש גם את האפשרות space-around.

Gap

Gap מנהל את הרווחים בין השורות והעמודות. שימוש ב-rowGap יגדיר את הרווח בין השורות.

const styles = StyleSheet.create({
  container:{ 
    // flex: 1,
    height: 300,
    flexWrap: "wrap",
    rowGap: 20,
    borderWidth: 6,
    borderColor: "red"
  },
})

הוספת columnGap יוסיף מרחק בין העמודות.

const styles = StyleSheet.create({
  container:{ 
    // flex: 1,
    height: 300,
    flexWrap: "wrap",
    rowGap: 20,
    columnGap: 30,
    borderWidth: 6,
    borderColor: "red"
  },
}) 

אם רוצים להוסיף את אותו המרחק בין השורות והעמודות אפשר להשתמש בתכונה gap.

Flex Basis

Flex Basis קובע את הגודל ההתחלתי של רכיבים לפני שמוסיפים רווחים. כברירת מחדל הרכיבים מקבילים את הגודל שלהם לפי התוכן שיש בהם. אם רוצים לשנות את זה משתמשים ב-Flex Basis.

<View style={styles.container}>
      <Box style={{ backgroundColor: "#8e9b00" }}>Box 1</Box>
      <Box style={{ backgroundColor: "#b65d1f" }}>Box 2</Box>
      <Box style={{ backgroundColor: "#1c4c56", flexBasis: 140 }}>Box 3</Box>
      <Box style={{ backgroundColor: "#ab9156" }}>Box 4</Box>
      <Box style={{ backgroundColor: "#6b0803" }}>Box 5</Box>
      <Box style={{ backgroundColor: "#1c4c56" }}>Box 6</Box>
      <Box style={{ backgroundColor: "#b95f21" }}>Box 7</Box>
</View>

אפשר להשתמש בתכונה Height, אבל ההבדל הוא שחלוקת שטח פנוי תעבוד עם flex basis, כי התכונה קובעת רק גודל התחלתי לרכיב.

Flex Shrink

Flex Shrink קובע איך רכיבי ילדים בתוך container יתכוותו כאשר הגודל הכולל של הילדים עובר את הגודל של ה-container.

אם נגביל את הרוחב של ה-container ונגדיל את התוכן של הרכיבים, נראה שהם לא נכנסים לתוך ה-container.

const styles = StyleSheet.create({
  container:{ 
    flex: 1,
    flexDirection: "row",
    alignItems: "flex-start",
    width: 300,
    borderWidth: 6,
    borderColor: "red"
  },
}) 

אם נוסיף flexShrink לתיבה השנייה, נראה איך היא מתאימה את עצמה לגודל ה-container.

<Box style={{ backgroundColor: "#8e9b00" }}>Box 1 - shrink</Box>
<Box style={{ backgroundColor: "#b65d1f", flexShrink: 1 }}>Box 2 - shrink</Box>

אם נוסיף flexShrink לשני הרכיבים, שניהם יתכווצו להתאמה. ערך ה-flexShrink קובע את היחס של הכיווץ בין הרכיבים.

Flex Grow

Flex Grow קובע כמה מקום רכיב יקח כשיש מקום פנוי ב-container. כברירת מחדל כל רכיב תופס את השטח של הילדים שלו ולא מתרחב גם אם יש מקום ריק.

<View style={styles.container}>
      <Box style={{ backgroundColor: "#8e9b00" }}>Box 1</Box>
      <Box style={{ backgroundColor: "#b65d1f" }}>Box 2</Box>
      <Box style={{ backgroundColor: "#1c4c56" }}>Box 3</Box>
      <Box style={{ backgroundColor: "#ab9156" }}>Box 4</Box>
      <Box style={{ backgroundColor: "#6b0803", flexGrow: 1 }}>Box 5</Box>
      <Box style={{ backgroundColor: "#1c4c56" }}>Box 6</Box>
      <Box style={{ backgroundColor: "#b95f21" }}>Box 7</Box>
</View>

אם נגדיר flexGrow לרכיבים נוספים, השטח הפנוי יתחלק בין הרכיבים המוגדרים. אם נגדיר את flexGrow למספר שונה מ-1, השטח הפנוי יתחלק באופן יחסי. אם רוצים שכל הרכיבים יתפסו את המקום הריק, אפשר להכניס את זה להגדרת ה-Box.

Relative and Absolute Layout

תכונת position מגדירה איך רכיב ממקום בתוך ה-container. ברירת המחדל היא relative. המיקום של הרכיב הוא יחסי לרצף הרכיבים וניתן לשחק איתו על ידי הגדרות top, right, bottom, left.

באפשרות absolut המיקום של הרכיב לא תלוי בשאר הרכיבים אלא מוחלט.

כדי לראות איך זה עובד נשנה את גודל התיבות שלנו לרוחב וגובה של 100. מכיוון שברירת המחדל היא relative נקרא את הקוביות אחת מתחת לשנייה ברצף התצוגה.

אם נזיז קוביה, זה יהיה יחסי למיקום שלה. שאר הרכיבים לא מושפעים.

<View style={styles.container}>
      <Box style={{ backgroundColor: "#8e9b00", top: 75, left: 75 }}>Box 1</Box>
      <Box style={{ backgroundColor: "#b65d1f" }}>Box 2</Box>
      <Box style={{ backgroundColor: "#1c4c56" }}>Box 3</Box>
      <Box style={{ backgroundColor: "#ab9156", top: 75, left: 75 }}>Box 4</Box>
      <Box style={{ backgroundColor: "#6b0803" }}>Box 5</Box>
      <Box style={{ backgroundColor: "#1c4c56" }}>Box 6</Box>
      <Box style={{ backgroundColor: "#b95f21" }}>Box 7</Box>
</View>

נשנה את המיקום של תיבה 4 להיות אבסולוטי.

<View style={styles.container}>
      <Box style={{ backgroundColor: "#8e9b00" }}>Box 1</Box>
      <Box style={{ backgroundColor: "#b65d1f" }}>Box 2</Box>
      <Box style={{ backgroundColor: "#1c4c56" }}>Box 3</Box>
      <Box 
        style={{ 
          backgroundColor: "#ab9156",
          position: "absolute",
          top: 100,
          left: 100
        }}>Box 4</Box>
      <Box style={{ backgroundColor: "#6b0803" }}>Box 5</Box>
      <Box style={{ backgroundColor: "#1c4c56" }}>Box 6</Box>
      <Box style={{ backgroundColor: "#b95f21" }}>Box 7</Box>
</View>

התיבה זזה והיא יצאה מרצף הרכיבים, כך שכל הרכיבים שהיו מתחתיה, עלו למעלה.

ניווט במאמר

מאמרים אחרונים

Weekly Tutorial