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

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

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

תכונה

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

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

הטבה מבוססת-מדינה

ניהול המצב

עדכון המצב של שדה הטקסט באמצעות פונקציית ה-callback 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:
    • עיצוב ברירת המחדל הוא filled
    • OutlinedTextField היא הגרסה עם הסגנון outlined
  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 כשהעיצוב דורש את החומר TextField או OutlinedTextField. עם זאת, צריך להשתמש ב-BasicTextField כשמפתחים עיצובים שלא צריכים את הקישוט של מפרט Material.

הגדרת מגבלות על קווים

רכיבי TextField ניתנים להחלפה ותומכים בגלילה בציר אחד. התנהגות הגלילה נקבעת לפי הפרמטר 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)
)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

val phoneNumberState = rememberTextFieldState()

LaunchedEffect(phoneNumberState) {
    phoneNumberState.edit { // TextFieldBuffer scope
        append("123456789")
    }
}

TextField(
    state = phoneNumberState,
    inputTransformation = InputTransformation { // TextFieldBuffer scope
        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 ועוד.

    val usernameState = rememberTextFieldState("I love Android")
    // textFieldState.text : I love Android
    // textFieldState.selection: TextRange(14, 14)
    usernameState.edit { insert(14, "!") }
    // textFieldState.text : I love Android!
    // textFieldState.selection: TextRange(15, 15)
    usernameState.edit { replace(7, 14, "Compose") }
    // textFieldState.text : I love Compose!
    // textFieldState.selection: TextRange(15, 15)
    usernameState.edit { append("!!!") }
    // textFieldState.text : I love Compose!!!!
    // textFieldState.selection: TextRange(18, 18)
    usernameState.edit { selectAll() }
    // textFieldState.text : I love Compose!!!!
    // textFieldState.selection: TextRange(0, 18)

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

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

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

    usernameState.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 (!TextUtils.isDigitsOnly(asCharSequence())) {
            revertAllChanges()
        }
    }
}

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

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

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

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

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

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

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

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

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

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

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

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, השיטה 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: הסתרת כל הקלט מלבד התו האחרון. התנהגות ברירת המחדל במכשירים ניידים.

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