วิธีอัปเดต ListView บน Android แบบไดนามิก [ปิด]


159

บน Android ฉันจะListViewกรองตามการป้อนข้อมูลของผู้ใช้ได้อย่างไรรายการที่แสดงมีการอัปเดตตามTextViewค่าแบบไดนามิกหรือไม่

ฉันกำลังมองหาบางสิ่งเช่นนี้:

-------------------------
| Text View             |
-------------------------
| List item             |
| List item             |
| List item             |
| List item             |
|                       |
|                       |
|                       |
|                       |
-------------------------

7
ฉันเสนอชื่อเพื่อเปิดใหม่ ผมได้ปรับปรุงข้อความที่จะทำให้เรื่องนี้มากขึ้นของคำถามและก็เห็นได้ชัดว่าเป็นทรัพยากรที่มีคุณค่าเช่นชุมชนคำตอบยังคงมาใน
Hamy

โปรดเปิดคำถามอีกครั้ง มันมีประโยชน์ชัดเจน
SilentNot

คำตอบ:


286

ก่อนอื่นคุณต้องสร้างเค้าโครง XML ที่มีทั้ง EditText และ ListView

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <!-- Pretty hint text, and maxLines -->
    <EditText android:id="@+building_list/search_box" 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:hint="type to filter"
        android:inputType="text"
        android:maxLines="1"/>

    <!-- Set height to 0, and let the weight param expand it -->
    <!-- Note the use of the default ID! This lets us use a 
         ListActivity still! -->
    <ListView android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="0dip"
        android:layout_weight="1" 
         /> 

</LinearLayout>

สิ่งนี้จะจัดวางทุกอย่างออกมาอย่างเหมาะสมพร้อมกับ EditText ด้านบน ListView ถัดไปสร้าง ListActivity ตามปกติ แต่เพิ่มการsetContentView()โทรในonCreate()วิธีการเพื่อให้เราใช้เค้าโครงที่ประกาศล่าสุดของเรา จำไว้ว่าเรา ID'ed เป็นพิเศษด้วยListView android:id="@android:id/list"สิ่งนี้ทำให้ผู้ListActivityใช้ทราบว่าListViewเราต้องการใช้รูปแบบใดในการประกาศของเรา

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.filterable_listview);

        setListAdapter(new ArrayAdapter<String>(this,
                       android.R.layout.simple_list_item_1, 
                       getStringArrayList());
    }

การเรียกใช้แอปควรแสดงที่ผ่านมาของคุณListViewโดยมีช่องด้านบน เพื่อที่จะทำให้กล่องนั้นทำอะไรบางอย่างเราจำเป็นต้องนำเข้าจากมันและทำให้ตัวกรองนั้นเข้าในรายการ ในขณะที่ผู้คนจำนวนมากพยายามทำสิ่งนี้ด้วยตนเองคลาสส่วนใหญ่ ListView Adapterมาพร้อมกับFilterวัตถุที่สามารถใช้เพื่อทำการกรองโดยอัตโนมัติ เราก็ต้องป้อนข้อมูลจากท่อที่เข้ามาในEditText Filterปรากฎว่าเป็นเรื่องง่าย หากต้องการทดสอบอย่างรวดเร็วให้เพิ่มบรรทัดนี้ในการonCreate()โทรของคุณ

adapter.getFilter().filter(s);

โปรดสังเกตว่าคุณจะต้องบันทึกListAdapterตัวแปรของคุณเพื่อให้งานนี้ - ฉันได้บันทึกArrayAdapter<String>จากก่อนหน้านี้เป็นตัวแปรที่เรียกว่า 'อะแดปเตอร์'

EditTextขั้นตอนต่อไปคือการได้รับข้อมูลจากที่ จริง ๆ แล้วใช้ความคิดเล็กน้อย คุณสามารถเพิ่มที่คุณOnKeyListener() EditTextอย่างไรก็ตามผู้ฟังนี้ได้รับเหตุการณ์สำคัญบางอย่างเท่านั้น ตัวอย่างเช่นหากผู้ใช้ป้อน 'wyw' ข้อความคาดการณ์อาจจะแนะนำ 'ตา' จนกว่าผู้ใช้จะเลือก 'wyw' หรือ 'eye' คุณOnKeyListenerจะไม่ได้รับเหตุการณ์สำคัญ บางคนอาจชอบวิธีนี้ แต่ฉันคิดว่ามันน่าหงุดหงิด ฉันต้องการทุกเหตุการณ์สำคัญดังนั้นฉันจึงมีตัวเลือกในการกรองหรือไม่กรอง TextWatcherการแก้ปัญหาคือ เพียงสร้างและเพิ่ม a TextWatcherไปยังEditTextและส่งListAdapter Filterคำขอตัวกรองทุกครั้งที่ข้อความเปลี่ยนแปลง อย่าลืมลบTextWatcherในOnDestroy()! นี่คือทางออกสุดท้าย:

private EditText filterText = null;
ArrayAdapter<String> adapter = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.filterable_listview);

    filterText = (EditText) findViewById(R.id.search_box);
    filterText.addTextChangedListener(filterTextWatcher);

    setListAdapter(new ArrayAdapter<String>(this,
                   android.R.layout.simple_list_item_1, 
                   getStringArrayList());
}

private TextWatcher filterTextWatcher = new TextWatcher() {

    public void afterTextChanged(Editable s) {
    }

    public void beforeTextChanged(CharSequence s, int start, int count,
            int after) {
    }

    public void onTextChanged(CharSequence s, int start, int before,
            int count) {
        adapter.getFilter().filter(s);
    }

};

@Override
protected void onDestroy() {
    super.onDestroy();
    filterText.removeTextChangedListener(filterTextWatcher);
}

7
มีวิธีที่ตรงไปตรงมาในการกรอง ListView ใน "ประกอบด้วย" แทนที่จะเป็น "เริ่มต้นด้วย" แฟชั่นเหมือนวิธีการแก้ปัญหานี้หรือไม่?
Viktor Brešan

12
Viktor - หากคำที่คุณสนใจคั่นด้วยช่องว่างคำนั้นจะดำเนินการโดยอัตโนมัติ ไม่อย่างนั้นจริงๆ อาจเป็นวิธีที่ง่ายที่สุดในการ subclass อะแดปเตอร์โดยการขยายและแทนที่วิธี getFilter เพื่อส่งกลับวัตถุตัวกรองที่คุณกำหนด ดูgithub.com/android/platform_frameworks_base/blob/master/core/…เพื่อทำความเข้าใจวิธีการทำงานของ ArrayFilter เริ่มต้น - การคัดลอก 95% ของรหัสนี้และการเปลี่ยนบรรทัด 479 และ 486
Hamy

2
Hamy เขียนดีมาก! ฉันมีคำถาม: ฉันได้ดำเนินการนี้และหลังจากตัวอักษรแต่ละตัวที่ฉันพิมพ์ ListView หายไปสองสามวินาทีแล้วกลับมากรอง คุณเคยประสบกับสิ่งนี้หรือไม่? สัญชาตญาณของฉันคือเพราะฉันมี 600+ รายการในรายการที่มีฟังก์ชั่น toString () ไม่สำคัญ
lowellk

2
ในโหมดแนวนอนบนหน้าจอที่เล็กกว่าแป้นพิมพ์ EditText + จะถ่ายทั้งหน้าจอและไม่สามารถมองเห็น ListView ได้! ทางออกใด ๆ
Martin Konicek

4
มันจำเป็นจริงๆเหรอ? > อย่าลืมลบ TextWatcher ใน OnDestroy ()
Jojo

10

การรันโปรแกรมจะทำให้เกิดแรงปิด

ฉันกวาดแถว:

หุ่นยนต์: id = "@ + building_list / search_box"

กับ

หุ่นยนต์: id = "@ + ID / search_box"

นั่นอาจเป็นปัญหาหรือไม่ '@ + building_list' มีไว้เพื่ออะไร


Johe เมื่อคุณพูดว่า R.id.something บางสิ่งมีอยู่ใน id เพราะคุณพูดว่า android: id = "@ + id / search_box" ถ้าคุณบอกว่า android: id = "@ + building_list / search_box" จากนั้นในรหัสคุณสามารถโทรหา findViewById (R.building_list.search_box); อะไรคือข้อยกเว้นระดับสูงสุดที่คุณได้รับ รหัสนี้ถูกคัดลอกโดยไม่มีการรวบรวมการทดสอบดังนั้นฉันน่าจะเหลือข้อผิดพลาดอย่างน้อยหนึ่งข้อในที่นั้น
Hamy

สวัสดี Hamy คุณอ้างอิง "@ + building_list / search_box" ในรหัสด้วย "filterText = (EditText) findViewById (R.id.search_box);" นั่นเป็นเหตุผลที่ฉันสงสัย
j7nn7k

1
forceclose เกิดขึ้นเมื่อเริ่มพิมพ์ส่วนหนึ่งของข้อผิดพลาด: ERROR / AndroidRuntime (188): java.lang.NullPointerException 02-11 07: 30: 29.828: ERROR / AndroidRuntime (188): ที่ xxx.com.ListFilter $ 1 onTextChanged (ListFilter.java:46) 02-11 07: 30: 29.828: ข้อผิดพลาด / AndroidRuntime (188): ที่ android.widget.TextView.sendOnTextChanged (TextView.java:6102) 02-11 07: 30: 29.828: ERROR / AndroidRuntime (188): ที่ android.widget.TextView.handleTextChanged (TextView.java:6143) 02-11 07: 30: 29.828: ข้อผิดพลาด / AndroidRuntime (188): ที่ android.widget.TextView $ ChangeWatcher.onTextChanged : 6286)
j7nn7k

Johe อ๊ะดูเหมือนว่าฉันกำลังพยายามแก้ไขรหัสเพื่อกำจัด @ + building_list (เพราะเป็นจุดที่สับสน) แต่ฉันไม่ได้จับมันทุกที่ ขอบคุณสำหรับทิป! เพียงแค่เปลี่ยนเป็น @ + id ควรแก้ไข
Hamy

4

ฉันมีปัญหากับการกรองผลลัพธ์นั้นถูกกรองแล้ว แต่ไม่ได้รับการกู้คืน !

ดังนั้นก่อนการกรอง (กิจกรรมเริ่ม) ฉันสร้างการสำรองข้อมูลรายการ .. (เพียงรายการอื่นที่มีข้อมูลเดียวกัน)

ในการกรองตัวกรองและรายการตัวเชื่อมต่อจะเชื่อมต่อกับรายการหลัก

แต่ตัวกรองเองใช้ข้อมูลจากรายการที่สำรองข้อมูล

ทำให้มั่นใจได้ในกรณีของฉันว่ารายการนั้นได้รับการอัปเดตทันทีและแม้กระทั่งการลบคำค้นหาตัวอักษรรายการก็จะได้รับการกู้คืนสำเร็จในทุกกรณี :)

ขอบคุณสำหรับการแก้ปัญหานี้ต่อไป

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