ฉันจะใช้ databinding เพื่อรวมสตริงจากทรัพยากรกับตัวแปรไดนามิกใน XML ได้อย่างไร


125

ฉันมี TextView ซึ่งมีสตริงแบบฮาร์ดโค้ดและฉันมีตัวแปรไดนามิกที่ฉันต้องการใส่ไว้ท้ายสตริงนี้ นี่คือรหัสของฉัน:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:layout_marginLeft="16dp"
    android:layout_marginRight="16dp">
    <TextView
        android:id="@+id/PeopleName"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/Generic_Text"+"@{ Profile.name }" />


</LinearLayout>

android:text="@string/Generic_Text"+"@{ Profile.name }"ฉันมีปัญหากับ Generic_Textรัฐ "ชื่อของฉันคือ" แล้วProfile.nameเป็นแบบไดนามิกและเห็นได้ชัดว่ามีการเปลี่ยนแปลงจากโปรไฟล์ไปยังโปรไฟล์ ฉันต้องการมันเพื่อให้การส่งออก TextView ทั้งชื่อของฉันคือ {} ความช่วยเหลือใด ๆ จะดีมาก


คุณใช้ databinding หรือไม่?
malmling

ใช่ฉันใช้ databinding
Ignacio Perez

กรุณาเพิ่มรหัส java ปัจจุบันของคุณด้วย
malmling

คำตอบ:


162

คุณสามารถทำได้:

android:text= "@{String.format(@string/Generic_Text, Profile.name)}"

หากคุณใช้การจัดรูปแบบสตริงสำหรับGeneric_Textสตริงของคุณ อดีต %sในตอนท้าย


ขอบคุณมากที่ฉันใส่มันเข้าไปและมันทำงานได้อย่างถูกต้อง
Ignacio Perez

5
นี่ไม่ควรเป็นคำตอบที่ยอมรับเพราะจริงๆแล้วสิ่งนี้ไม่ได้ใช้คุณสมบัติการผูกข้อมูลเพื่อปรับแต่งข้อความ
Darwind

1
เห็นด้วยกับ @Darwind โปรดดูคำตอบของฉันสำหรับการใช้งานกับ Binding Adapters
juanagui

@IgorGanapolsky คำตอบนี้มีอายุมากกว่า 3 ปีแล้ว แต่เคยทำงานมาก่อน - คุณจำได้ไหมว่ามีอะไรผิดพลาดเมื่อคุณลอง?
C0D3LIC1OU5

320

คุณสามารถทำได้ง่ายขึ้น:

android:text= "@{@string/generic_text(profile.name)}"

สตริงของคุณควรเป็นดังนี้:

<string name="generic_text">My Name is %s</string>

แก้ไข:

  1. แน่นอนคุณสามารถใช้ตัวแปรได้มากเท่าที่คุณต้องการ:

    android:text= "@{@string/generic_text(profile.firstName, profile.secondName)}"
    
    <string name="generic_text">My Name is %1$s %2$s</string>
  2. ใช้งานได้เพียงเพราะได้รับการออกแบบในการผูกข้อมูล เพิ่มเติมในเอกสาร: https://developer.android.com/topic/libraries/data-binding/expressions#resources


1
แต่จะแสดงMy Name is nullว่าข้อมูลยังไม่พร้อมหรือไม่ (เช่นไม่ได้โหลดจากเครือข่าย)
user924

1
ในกรณีนี้ให้ตรวจสอบดูก่อน android:text= "@{profile == null ? @string/loading : @string/generic_text(profile.firstName, profile.secondName)}"
Roman_D

นี่เป็นประโยชน์!
akash89

คำตอบที่ดีที่สุด :)
Heriberto Rivera

55

หลายวิธีในการต่อสตริง

1. การใช้ทรัพยากรสตริง ( แนะนำเนื่องจากการแปลเป็นภาษาท้องถิ่น )

android:text= "@{@string/generic_name(user.name)}"

เพียงแค่สร้างทรัพยากรสตริงเช่นนี้

<string name="generic_name">Hello %s</string>

2. เชื่อมต่อรหัสยาก

android:text="@{`Hello ` + user.name}"/>

สิ่งนี้มีประโยชน์เมื่อคุณต้องการต่อท้ายรหัสแบบแข็งเช่น + สำหรับหมายเลขโทรศัพท์

3. ใช้Stringวิธี concat

android:text="@{user.firstName.concat(@string/space).concat(user.lastName)}"

นี่spaceเป็นนิติบุคคล HTML strings.xmlซึ่งจะอยู่ภายใน เนื่องจากXMLไม่ยอมรับเอนทิตี Html หรืออักขระพิเศษโดยตรง (เชื่อมโยงเอนทิตี Html)

<string name="space">\u0020</string>

4. การใช้ String.format()

android:text= "@{String.format(@string/Hello, user.name)}"

คุณต้องนำเข้าคลาส String ในเลย์เอาต์ในประเภทนี้

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <import type="String" />
    </data>
    <TextView
        android:text= "@{String.format(@string/Hello, user.name)}"
        ... >
    </TextView>
</layout>

5. เชื่อมต่อสองสตริงด้วยทรัพยากรสตริง

android:text="@{@string/generic_name(user.firstName,user.lastName)}"

ในกรณีนี้ให้ใส่ทรัพยากรสตริงเข้า strings.xml

<string name="generic_name">%1$s, %2$s</string>

อาจมีวิธีอื่น ๆ อีกมากมายเลือกวิธีที่คุณต้องการ


5

ใช้Binding Adapterอะแดปเตอร์เข้าเล่ม

ตัวอย่างนี้เขียนด้วย Kotlin และพิจารณาว่าตัวแปรที่ถูกผูกไว้สามารถเป็นโมฆะ:

@BindingAdapter("my_name")
fun TextView.setMyName(name: String?) {
    this.text =
        if (name.isNullOrEmpty()) "" else "${this.context.getString(R.string.Generic_Text)} $name"
}

จากนั้นใช้อะแด็ปเตอร์การผูกใน XML ของคุณแทนandroid:textคุณสมบัติ

app:my_name="@{Profile.name}"

เคยมีปัญหามากมายในการเรียกฟังก์ชันที่นำเข้าในการเชื่อมคำตอบนี้ใช้ได้ดีกับฉันและช่วยให้ฉันสามารถนำส่วนขยายกลับมาใช้ใหม่ได้ ขอบคุณ!
Danny Buonocore

เนื่องจากการจัดการขั้นพื้นฐานมีให้แล้วตามStringคลาสจากxmlนั้นโซลูชันนี้จึงใช้ได้ดีสำหรับการปรับแต่งสตริงขั้นสูงตามความต้องการของคุณเท่านั้น อย่างไรก็ตามมันไม่ถูกต้อง
sud007

3

อัปเดต 2019, Android studio เป็น 3.4, Android Gradle Plugin เป็น 3.4

ไม่ต้องนำเข้าอีกต่อไป

<import type="java.lang.String" />" 

สำหรับการดำเนินการสตริง โปรดตรวจสอบคำตอบนี้


1

ในกรณีที่คุณไม่สามารถเปลี่ยนสตริงทรัพยากรให้มี%sในตอนท้าย (เช่นเนื่องจากถูกใช้ที่อื่นโดยไม่มีคำต่อท้าย):

android:text="@{@string/Generic_Text.concat(Profile.name)}"

ถ้าProfile.nameไม่สามารถเป็นโมฆะได้ก็เพียงพอแล้ว อย่างไรก็ตามหากnullเกิดขึ้นก็จะผิดพลาด คุณต้องเพิ่มเลเยอร์อื่น:

android:text="@{@string/Generic_Text.concat(Objects.toString(Profile.name))}"

(ซึ่งต้องใช้<import type="java.util.Objects"/>ในการทำงาน)

อีกครั้ง: งานพิเศษทั้งหมดนี้จะคุ้มค่าก็ต่อเมื่อคุณมีสตริงทรัพยากรที่ใช้ที่อื่น เหตุผลประการที่สองคือเมื่อคุณต้องการจัดการnullเป็น "สตริงว่าง" แทนที่จะเป็นลิเทอรัล "null"


2
หากทรัพยากรสตริงถูกใช้ที่อื่นทำไมไม่ลองสร้างทรัพยากรใหม่ล่ะ
Jarett Millard

0

ในกรณีที่คุณต้องการพิมพ์ข้อความใน XML คุณสามารถใช้`` quotation.

android:text="@{`Device Name`}"

ที่อื่นที่คุณต้องการเชื่อมต่อกับสตริงหรือตัวแปรคุณสามารถใช้ได้

android:text="@{`Device Name`.concat(android.os.Build.MANUFACTURER)}"

ถ้าคุณต้องการConcat string resourceแทนตัวแปรที่ทำได้

android:text="@{@string/app_name.concat(`Device Name`)}"

0

แค่ใช้+ตัวดำเนินการก็เหมาะกับฉัน:

android:text= "@{@string/Generic_Text +' '+ Profile.name)}"

String.xml จะเป็น:

<string name="Generic_Text">Hello</string>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.