הגדרת שדות טקסט

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

מומלץ להשתמש בשדות טקסט מבוססי-מצב, כי הם מספקים גישה מלאה ואמינה יותר לניהול המצב של TextField. בטבלה הבאה מפורטים ההבדלים בין סוגי שדות הטקסט האלה, ומוצגים היתרונות העיקריים של שדות טקסט מבוססי-מצב:

תכונה

שדות טקסט מבוססי-ערך

שדות טקסט מבוססי-מצב

הטבה שמבוססת על מדינה

ניהול מצב

עדכון המצב של שדה הטקסט באמצעות הקריאה החוזרת onValueChange. באחריותכם לעדכן את value במדינה שלכם על סמך השינויים שדווחו על ידי onValueChange.

משתמש במפורש באובייקט TextFieldState כדי לנהל את מצב קלט הטקסט (ערך, בחירה והרכבה). אפשר לזכור את המצב הזה ולשתף אותו.

  • הוסר ה-callback‏ onValueChange, ולכן אי אפשר להוסיף התנהגויות אסינכרוניות.
  • המצב נשמר גם אחרי הרכבה מחדש, הגדרה וסיום התהליך.

טרנספורמציה חזותית

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

משתמשים ב-InputTransformation כדי לשנות את הקלט של המשתמש לפני שהוא נשמר במצב, וב-OutputTransformation כדי לעצב את התוכן של שדה הטקסט בלי לשנות את נתוני המצב הבסיסיים.

  • אין יותר צורך לספק את מיפוי ההיסט בין הטקסט הגולמי המקורי לבין הטקסט שעבר טרנספורמציה באמצעות OutputTransformation.

מגבלות על מספר השורות

הפונקציה מקבלת את הערכים singleLine: Boolean, maxLines: Int ו-minLines: Int כדי לשלוט במספר השורות.

משתמשים ב-lineLimits: TextFieldLineLimits כדי להגדיר את מספר השורות המינימלי והמקסימלי שהטקסט יכול לתפוס בשדה.

  • כדי למנוע אי בהירות בהגדרת מגבלות על שורות, נוסף פרמטר lineLimits מסוג TextFieldLineLimits.

שדה טקסט מאובטח

לא רלוונטי

SecureTextField הוא קומפוזבילי שמבוסס על שדות טקסט מבוססי-מצב לכתיבת שדה סיסמה.

  • הוא מאפשר לכם לבצע אופטימיזציה של האבטחה מתחת לפני השטח, ומגיע עם ממשק משתמש מוגדר מראש עם textObfuscationMode.

בדף הזה מוסבר איך להטמיע את TextField, איך להגדיר את הסגנון של הקלט TextField ואיך להגדיר אפשרויות אחרות של TextField, כמו אפשרויות של מקלדת ושינוי ויזואלי של קלט המשתמש.

בחירת הטמעה של TextField

יש שתי רמות של הטמעה של TextField:

  1. TextField היא ההטמעה של Material Design. מומלץ לבחור בהטמעה הזו כי היא תואמת להנחיות של Material Design:
  2. BasicTextField מאפשר למשתמשים לערוך טקסט באמצעות מקלדת חומרה או מקלדת תוכנה, אבל לא מספק קישוטים כמו רמז או placeholder.

TextField(
    state = rememberTextFieldState(initialText = "Hello"),
    label = { Text("Label") }
)

שדה טקסט שניתן לעריכה שמכיל את המילה

OutlinedTextField(
    state = rememberTextFieldState(),
    label = { Text("Label") }
)

שדה טקסט שניתן לעריכה, עם גבול ותווית סגולים.

סגנון TextField

TextField ו-BasicTextField חולקים הרבה פרמטרים משותפים להתאמה אישית. הרשימה המלאה של TextField זמינה בקוד המקור של TextField. זוהי רשימה חלקית של כמה מהפרמטרים השימושיים:

  • textStyle
  • lineLimits

TextField(
    state = rememberTextFieldState("Hello\nWorld\nInvisible"),
    lineLimits = TextFieldLineLimits.MultiLine(maxHeightInLines = 2),
    placeholder = { Text("") },
    textStyle = TextStyle(color = Color.Blue, fontWeight = FontWeight.Bold),
    label = { Text("Enter text") },
    modifier = Modifier.padding(20.dp)
)

שדה טקסט עם כמה שורות, שכולל שתי שורות שניתנות לעריכה וגם את התווית

מומלץ להשתמש ב-TextField במקום ב-BasicTextField כשרוצים להשתמש בעיצוב של Material TextField או OutlinedTextField. עם זאת, צריך להשתמש ב-BasicTextField כשיוצרים עיצובים שלא צריכים את הקישוטים ממפרט Material.

הגדרת מגבלות על שורות

TextField composables תומכים בגלילה לאורך ציר אחד. התנהגות הגלילה נקבעת על ידי הפרמטר lineLimits. כשמגדירים TextField לשורה אחת, הגלילה היא אופקית, וכשמגדירים TextField לכמה שורות, הגלילה היא אנכית.

משתמשים ב-TextFieldLineLimits כדי לבחור את הגדרת הקו המתאימה ל-TextField:

TextField(
    state = rememberTextFieldState(),
    lineLimits = TextFieldLineLimits.SingleLine
)

שדה טקסט של שורה אחת עם הטקסט

ההגדרות של SingleLine כוללות את המאפיינים הבאים:

  • הטקסט אף פעם לא נשבר לשורה חדשה, ואי אפשר להוסיף שורות חדשות.
  • ל-TextField יש תמיד גובה קבוע.
  • אם הטקסט חורג מהגבולות, הוא יגולל אופקית.

TextField(
    state = rememberTextFieldState("Hello\nWorld\nHello\nWorld"),
    lineLimits = TextFieldLineLimits.MultiLine(1, 4)
)

שדה טקסט עם כמה שורות והטקסט

ההגדרות של MultiLine כוללות את המאפיינים הבאים:

  • הפונקציה מקבלת שני פרמטרים: minHeightInLines ו-maxHeightInLines.
  • שדה הטקסט הוא בגובה minHeightInLines לפחות.
  • אם הטקסט ארוך מדי, הוא יועבר לשורה הבאה.
  • אם הטקסט דורש יותר שורות, השדה גדל עד לגובה של maxHeightInLines, ומתבצעת גלילה אנכית.

שינוי סגנון הקלט באמצעות Brush API

אפשר להשתמש ב-Brush API כדי להחיל סגנונות מתקדמים יותר על TextField. בקטע הבא מוסבר איך להשתמש במברשת כדי להוסיף שיפוע צבעוני לקלט TextField.

מידע נוסף על שימוש ב-Brush API לעיצוב טקסט זמין במאמר הפעלה של עיצוב מתקדם באמצעות Brush API.

הטמעה של מעברי צבע באמצעות TextStyle

כדי להטמיע מעבר צבעים בזמן ההקלדה בתוך TextField, צריך להגדיר את המברשת הרצויה כ-TextStyle עבור TextField. בדוגמה הזו, אנחנו משתמשים במברשת מובנית עם linearGradient כדי לראות את אפקט מעבר הצבעים של הקשת כשמקלידים טקסט ב-TextField.

val brush = remember {
    Brush.linearGradient(
        colors = listOf(Color.Red, Color.Yellow, Color.Green, Color.Blue, Color.Magenta)
    )
}
TextField(
    state = rememberTextFieldState(), textStyle = TextStyle(brush = brush)
)

טקסט שמוקלד בשדה טקסט, עם אפקט של מעבר צבעים בצבעי הקשת.
איור 1. אפקט של מעבר צבעים בצבעי הקשת לתוכן TextField.

ניהול המצב של שדה טקסט

TextField משתמש במחזיק מצב ייעודי שנקרא TextFieldState בשביל התוכן והבחירה שלו. ‫TextFieldState מיועד להעברה לכל מקום שמתאים בארכיטקטורה שלכם. יש 2 מאפיינים עיקריים שמופיעים ב-TextFieldState:

  • initialText: התוכן של TextField.
  • initialSelection: מציין את המיקום של הסמן או הבחירה.

ההבדל בין TextFieldState לבין גישות אחרות, כמו הקריאה החוזרת (callback) onValueChange, הוא ש-TextFieldState מכיל את כל זרימת הקלט. זה כולל שימוש במבני נתונים נכונים לגיבוי, סינון ועיצוב של נתונים מוטבעים, וגם סנכרון של כל העריכות שמגיעות ממקורות שונים.

אפשר להשתמש ב-TextFieldState() כדי להעביר את מצב הרכיב למיקום גבוה יותר בהיררכיה ב-TextField. לשם כך, מומלץ להשתמש בפונקציה rememberTextFieldState(). ‫rememberTextFieldState() יוצר את מופע TextFieldState בקומפוזיציה, מוודא שאובייקט המצב נשמר ומספק פונקציונליות מובנית של שמירה ושחזור:

val usernameState = rememberTextFieldState()
TextField(
    state = usernameState,
    lineLimits = TextFieldLineLimits.SingleLine,
    placeholder = { Text("Enter Username") }
)

rememberTextFieldState יכול להיות פרמטר ריק או ערך התחלתי שמועבר כדי לייצג את ערך הטקסט בהפעלה. אם מועבר ערך אחר בהרכבה מחדש עוקבת, ערך המצב לא מתעדכן. כדי לעדכן את המצב אחרי שהוא אותחל, צריך להפעיל שיטות עריכה ב-TextFieldState.

TextField(
    state = rememberTextFieldState(initialText = "Username"),
    lineLimits = TextFieldLineLimits.SingleLine,
)

שדה טקסט עם הטקסט 'שם משתמש' שמופיע בתוכו.
איור 2.TextField עם 'שם משתמש' כטקסט הראשוני.

שינוי הטקסט באמצעות TextFieldBuffer

TextFieldBuffer הוא קונטיינר טקסט שניתן לעריכה, בדומה לStringBuilder. הוא מכיל גם את תוכן הטקסט וגם מידע על הבחירה.

לרוב נתקלים ב-TextFieldBuffer כהיקף של מקבל בפונקציות כמו TextFieldState.edit, InputTransformation.transformInput או OutputTransformation.transformOutput. בפונקציות האלה, אפשר לקרוא או לעדכן את TextFieldBuffer לפי הצורך. לאחר מכן, השינויים האלה מועברים ל-TextFieldState או לצינור העיבוד במקרה של OutputTransformation.

אפשר להשתמש בפונקציות עריכה רגילות כמו append, insert, replace או delete כדי לשנות את התוכן של המאגר. כדי לשנות את מצב הבחירה, אפשר להגדיר ישירות את המשתנה selection: TextRange או להשתמש בפונקציות עזר כמו placeCursorAtEnd או selectAll. הבחירה עצמה מיוצגת על ידי TextRange, כאשר אינדקס ההתחלה כלול ואינדקס הסיום לא כלול. הערך TextRange עם ערכי התחלה וסיום זהים, כמו (3, 3), מציין מיקום של סמן ללא תווים שנבחרו.

val phoneNumberState = rememberTextFieldState("1234567890")

TextField(
    state = phoneNumberState,
    keyboardOptions = KeyboardOptions(
        keyboardType = KeyboardType.Phone
    ),
    inputTransformation = InputTransformation.maxLength(10).then {
        if (!asCharSequence().isDigitsOnly()) {
            revertAllChanges()
        }
    },
    outputTransformation = OutputTransformation {
        if (length > 0) insert(0, "(")
        if (length > 4) insert(4, ")")
        if (length > 8) insert(8, "-")
    }
)

עריכת טקסט ב-TextFieldState

יש כמה שיטות שמאפשרות לערוך את המצב ישירות דרך משתנה המצב:

  • edit: מאפשר לערוך את תוכן המצב ומספק TextFieldBufferפונקציות כדי שתוכלו להשתמש בשיטות כמו insert,‏ replace,‏ append ועוד.

    // Initial textFieldState text passed in is "I love Android"
    // textFieldState.text : I love Android
    // textFieldState.selection: TextRange(14, 14)
    textFieldState.edit { insert(14, "!") }
    // textFieldState.text : I love Android!
    // textFieldState.selection: TextRange(15, 15)
    textFieldState.edit { replace(7, 14, "Compose") }
    // textFieldState.text : I love Compose!
    // textFieldState.selection: TextRange(15, 15)
    textFieldState.edit { append("!!!") }
    // textFieldState.text : I love Compose!!!!
    // textFieldState.selection: TextRange(18, 18)
    textFieldState.edit { selectAll() }
    // textFieldState.text : I love Compose!!!!
    // textFieldState.selection: TextRange(0, 18)

  • setTextAndPlaceCursorAtEnd: מנקה את הטקסט הנוכחי, מחליף אותו בטקסט שצוין ומציב את הסמן בסוף.

    textFieldState.setTextAndPlaceCursorAtEnd("I really love Android")
    // textFieldState.text : I really love Android
    // textFieldState.selection : TextRange(21, 21)

  • clearText: מחיקת כל הטקסט.

    textFieldState.clearText()
    // textFieldState.text :
    // textFieldState.selection : TextRange(0, 0)

למידע על פונקציות אחרות של TextFieldState, אפשר לעיין במאמר הסבר על TextFieldState.

שינוי קלט של משתמשים

בקטעים הבאים מוסבר איך לשנות את הקלט של המשתמש. המרת קלט מאפשרת לסנן TextField קלט בזמן שהמשתמש מקליד, ואילו המרת פלט מעצבת את הקלט של המשתמש לפני שהוא מוצג על המסך.

סינון קלט משתמשים באמצעות טרנספורמציות של קלט

המרת קלט מאפשרת לסנן קלט מהמשתמש. לדוגמה, אם TextField מקבל מספר טלפון אמריקאי, אתם רוצים לקבל רק 10 ספרות. התוצאות של InputTransformation נשמרות בTextFieldState.

יש מסננים מובנים לתרחישי שימוש נפוצים ב-InputTransformation. כדי להגביל את האורך, צריך להתקשר למספר InputTransformation.maxLength():

TextField(
    state = rememberTextFieldState(),
    lineLimits = TextFieldLineLimits.SingleLine,
    inputTransformation = InputTransformation.maxLength(10)
)

טרנספורמציות של קלט מותאם אישית

InputTransformation הוא ממשק פונקציה יחידה. כשמטמיעים את InputTransformation המותאם אישית, צריך לבטל את ההגדרה של TextFieldBuffer.transformInput:

class CustomInputTransformation : InputTransformation {
    override fun TextFieldBuffer.transformInput() {
    }
}

כדי להוסיף מספר טלפון, מוסיפים המרה מותאמת אישית של קלט שמאפשרת להקליד רק ספרות ב-TextField:

class DigitOnlyInputTransformation : InputTransformation {
    override fun TextFieldBuffer.transformInput() {
        if (!asCharSequence().isDigitsOnly()) {
            revertAllChanges()
        }
    }
}

טרנספורמציות של קלט בשרשרת

כדי להוסיף כמה מסננים לקלט הטקסט, משתמשים בפונקציית ההרחבה then כדי לשרשר כמה פונקציות InputTransformation. המסננים מופעלים ברצף. מומלץ להחיל קודם את המסננים הסלקטיביים ביותר כדי להימנע משינויים מיותרים בנתונים שבסופו של דבר יסוננו.

TextField(
    state = rememberTextFieldState(),
    inputTransformation = InputTransformation.maxLength(6)
        .then(CustomInputTransformation()),
)

אחרי שמוסיפים טרנספורמציות של קלט, הקלט TextField יכול להכיל עד 10 ספרות.

עיצוב הקלט לפני שהוא מוצג

OutputTransformations מאפשרים לכם לעצב את קלט המשתמש לפני שהוא מוצג במסך. בניגוד ל-InputTransformation, העיצוב שנעשה באמצעות התג OutputTransformation לא נשמר ב-TextFieldState. בהמשך לדוגמה הקודמת של מספר הטלפון, צריך להוסיף סוגריים ומקפים במקומות המתאימים:

מספר טלפון אמריקאי בפורמט הנכון, עם סוגריים, מקפים ומספרים מתאימים.
איור 3. מספר טלפון אמריקאי בפורמט הנכון עם האינדקסים המתאימים.

זו הדרך המעודכנת לטפל בVisualTransformationים בTextFieldים מבוססי-ערך. ההבדל העיקרי הוא שלא צריך לחשב את מיפויי ההיסט שלהם.

OutputTransformation הוא ממשק עם שיטה מופשטת אחת. כדי להטמיע OutputTransformation מותאם אישית, צריך לבטל את השיטה transformOutput:

class CustomOutputTransformation : OutputTransformation {
    override fun TextFieldBuffer.transformOutput() {
    }
}

כדי לעצב מספר טלפון, מוסיפים סוגר פותח באינדקס 0, סוגר סוגר באינדקס 4 ומקף באינדקס 8 ל-OutputTransformation:

class PhoneNumberOutputTransformation : OutputTransformation {
    override fun TextFieldBuffer.transformOutput() {
        if (length > 0) insert(0, "(")
        if (length > 4) insert(4, ")")
        if (length > 8) insert(8, "-")
    }
}

בשלב הבא, מוסיפים את OutputTransformation אל TextField:

TextField(
    state = rememberTextFieldState(),
    outputTransformation = PhoneNumberOutputTransformation()
)

איך הטרנספורמציות פועלות יחד

התרשים הבא מציג את התהליך מקלט טקסט ועד לשינוי שלו לפלט:

הדמיה של תהליך השינוי של קלט טקסט לפני שהוא הופך לפלט טקסט.
איור 4. דיאגרמה שמראה איך קלט טקסט עובר טרנספורמציות לפני שהוא הופך לפלט טקסט.
  1. הקלט מתקבל ממקור הקלט.
  2. הקלט מסונן באמצעות InputTransformation, ששמור ב-TextFieldState.
  3. הקלט מועבר דרך OutputTransformation כדי לעצב אותו.
  4. הקלט מוצג בפורמט TextField.

הגדרת אפשרויות מקלדת

TextField מאפשרת להגדיר אפשרויות של תצורות מקלדת, כמו פריסת המקלדת, או להפעיל את התיקון האוטומטי אם המקלדת תומכת בו. יכול להיות שחלק מהאפשרויות לא יהיו זמינות אם המקלדת הווירטואלית לא תהיה תואמת לאפשרויות שמופיעות כאן. רשימת האפשרויות הנתמכות במקלדת:

  • capitalization
  • autoCorrect
  • keyboardType
  • imeAction

המחלקת KeyboardOptions כוללת עכשיו פרמטר בוליאני חדש, showKeyboardOnFocus, שמשמש באופן ספציפי לרכיבי TextField שמשולבים עם TextFieldState. האפשרות הזו קובעת את ההתנהגות של המקלדת הווירטואלית כשאלמנט TextField מקבל מיקוד באמצעים אחרים מלבד אינטראקציה ישירה של המשתמש (לדוגמה, באופן פרוגרמטי).

אם הערך של KeyboardOptions.showKeyboardOnFocus הוא true, המקלדת הווירטואלית לא מופיעה אוטומטית אם TextField מקבל פוקוס באופן עקיף. במקרים כאלה, המשתמש צריך להקיש באופן מפורש על TextField כדי שהמקלדת תופיע.

הגדרת לוגיקת אינטראקציה עם המקלדת

כפתור הפעולה במקלדת התוכנה של Android מאפשר תגובות אינטראקטיביות באפליקציה. מידע נוסף על הגדרת לחצן הפעולה זמין בקטע הגדרת אפשרויות המקלדת.

כפתור פעולה במקלדת וירטואלית (סמל של סימן וי) מוקף בעיגול אדום.
איור 5. כפתור הפעולה במקלדת הווירטואלית.

כדי להגדיר מה קורה כשמשתמש מקיש על לחצן הפעולה הזה, משתמשים בפרמטר onKeyboardAction. הפרמטר הזה מקבל ממשק פונקציונלי אופציונלי בשם KeyboardActionHandler. הממשק KeyboardActionHandler מכיל שיטה יחידה, onKeyboardAction(performDefaultAction: () -> Unit). אם תספקו הטמעה של שיטת onKeyboardAction הזו, תוכלו להוסיף לוגיקה מותאמת אישית שתופעל כשמשתמש ילחץ על לחצן הפעולה במקלדת.

לכמה סוגים של פעולות סטנדרטיות במקלדת יש התנהגויות ברירת מחדל מובנות. לדוגמה, אם בוחרים באפשרות ImeAction.Next או ImeAction.Previous כסוג הפעולה, המיקוד עובר כברירת מחדל לשדה הקלט הבא או הקודם, בהתאמה. באופן דומה, לחצן פעולה שמוגדר לImeAction.Done בדרך כלל מסתיר את המקלדת הווירטואלית. הפונקציות האלה מופעלות כברירת מחדל באופן אוטומטי, ולא צריך לספק KeyboardActionHandler.

בנוסף לפעולות ברירת המחדל האלה, אפשר גם להטמיע התנהגות מותאמת אישית. כשמספקים את KeyboardActionHandler, ה-method onKeyboardAction שלו מקבל פונקציה performDefaultAction. אפשר להפעיל את הפונקציה performDefaultAction() הזו בכל שלב בלוגיקה המותאמת אישית כדי להפעיל גם את התנהגות ברירת המחדל הרגילה שמשויכת לפעולת ה-IME הנוכחית.

TextField(
    state = textFieldViewModel.usernameState,
    keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
    onKeyboardAction = { performDefaultAction ->
        textFieldViewModel.validateUsername()
        performDefaultAction()
    }
)

קטע הקוד הזה ממחיש תרחיש נפוץ לדוגמה במסך הרשמה שכולל שדה של שם משתמש. בשדה הזה, ImeAction.Next נבחר עבור לחצן הפעולה במקלדת. הבחירה הזו מאפשרת ניווט מהיר וחלק לשדה הסיסמה הבא.

בנוסף לניווט הרגיל הזה, יש דרישה להפעיל תהליך אימות ברקע של שם המשתמש בזמן שהמשתמש ממשיך להזין את הסיסמה. כדי לוודא שההתנהגות של מעבר המיקוד שמוגדרת כברירת מחדל ב-ImeAction.Next נשמרת לצד לוגיקת האימות המותאמת אישית הזו, מופעלת הפונקציה performDefaultAction(). התקשרות אל performDefaultAction() מפעילה באופן מרומז את מערכת ניהול המיקוד הבסיסית כדי להעביר את המיקוד אל רכיב ממשק המשתמש המתאים הבא, וכך לשמור על זרימת הניווט הצפויה.

יצירת שדה סיסמה מאובטח

SecureTextField הוא קומפוזבילי שמבוסס על שדות טקסט מבוססי-מצב, ומשמש לכתיבת שדה סיסמה. מומלץ להשתמש ב-SecureTextField כדי ליצור שדות טקסט של סיסמאות, כי הוא מסתיר את קלט התווים כברירת מחדל ומשבית את פעולות החיתוך וההעתקה.

ל-SecureTextField יש textObfuscationMode שקובע איך המשתמש רואה את הקלט של התווים. textObfuscationMode כולל את האפשרויות הבאות:

  • Hidden: מסתיר את כל הקלט. התנהגות ברירת המחדל בפלטפורמות למחשבים.

    שדה טקסט מאובטח שבו התווים המוקלדים מוסתרים.

  • Visible: הצגת כל הקלט.

    שדה טקסט מאובטח שבו התווים שמוקלדים גלויים.

  • RevealLastTyped: מסתיר את כל הקלט חוץ מהתו האחרון. התנהגות ברירת המחדל במכשירים ניידים.

    שדה טקסט מאובטח שבו רק התו האחרון שהוקלד נחשף לזמן קצר.

מקורות מידע נוספים