16/9/2013 - برمجة Android - إضافة خاصيّة البحث إلى قوائم ListView




مرحباً بالجميع، درس اليوم بسيط و يفترض معرفة مُسبقة بكيفية بناء القوائم بإستخدام ListView، كتبت مُسبقاً درسين شرحت فيهما كيفية بناء قوائم ListView يُمكنك مراجعتهما إن شئت و هما "بناء قائمة ListView بسيطة في واجهة المستخدم الرسومية" و "بناء قوائم ListView مُتقدمه"، سأعتمد في شرحي لهذا الدرس على القوائم البسيطة.

المطلوب
عندما تبدأ القائمة التي نعرضها للمستخدم بالتضخّم فمن المُجدي إعطاء المُستخدم إمكانية البحث في هذه القائمة ليصل إلى العنصر المطلوب بشكل أسرع، فغالباً ما تأتي البرامج (مثلاً مدير جهات الإتصال) التي تحتوي على قوائم كبيره بصندوق نص يكتب به المُستخدم للبحث عن عنصر مُعيّن و في أثناء كتابته فإنّ العناصر التي تظهر في قائمة تتغير وفقاً لما يكتب المستخدم في صندوق النص، هذا ما سنفعله بالضبط في هذا الدرس.

سنبني قائمة بسيطة تحتوي على عدد من العناصر و أَفترض هنا معرفتك الجيدة بهذا الجزء، إن لم تكن تعرفه يُمكنك مراجعة الوصلات التي وضعتها في أوّل التدوينة، بعد ذلك سنُضيف خاصية البحث لصندوق نص يكتب به المُستخدم ويتم عرض العناصر في القائمة وفقاً لما كتبه المستخدم، واجهة برنامجنا ستكون مُشابهه للتالي :



البدء بالعمل
أولاً نُصمم الواجهة الرئيسيه، فكما ترى وفقاً للصورة في الأعلى فنحن بحاجة إلى مُربّع نص EditText و بالطبع بحاجة لوضع قائمتنا ListView، لندع أسماء الأدوات كما هي بدون تغيير و ننتقل الآن إلى الملف البرمجي لكتابة الشيفره والتي تُعتبر غالبيتها العُظمى مُكرره من الدرس الأول حول بناء قائمة بسيطة.

نأخذ الأداتان (القائمة و مُربّع النص) برمجياً لأننا سنتعامل معهما في الشيفرة.


		ListView listView = (ListView) findViewById( R.id.listView1 );
EditText txtSearch = (EditText) findViewById( R.id.editText1 );


نُنشئ مُحوّل (Adapter) من نوع ArrayAdapter لنضع به بياناتنا، و نضع به قائمة من البيانات، ثُم نُخبر قائمتنا الموجودة في واجهة المُستخدم إنّ هذا المُحوّل يَخصها و يجب عليها إستخدامه لعرض البيانات.

		final ArrayAdapter dataAdapter = new ArrayAdapter( this, android.R.layout.simple_list_item_1 );

dataAdapter.add( "GNOME" );
dataAdapter.add( "KDE" );
dataAdapter.add( "Cinnamon" );
dataAdapter.add( "Xfce" );

// ... //

listView.setAdapter( dataAdapter );


لحد الآن لا يوجد شيء جديد، قُمنا ببناء قائمة بسيطة ووضعنا بها بعض البيانات كما فعلنا سابقاً.

نأتي الآن للجزئية الأهم في هذا الدرس وهي عملية البحث، الفئة EditText والتي نستخدمها لبناء مربعات النص في الواجهات الرسومية تُقدّم لنا دالة إسمها addTextChangedListener من خلالها يُمكننا تَعريف مُستمع (Listener) يتم مناداته في كل مرّه يُغيّر المُستخدم النص داخل مُربّع النص، عندما تتم هذه العملية كُل ما نحتاجه هو فلترة البيانات الموجودة في قائمتنا وفقاً لما كتبه المُستخدم، تقوم الشيفره التاليه بالمطلوب :

		txtSearch.addTextChangedListener( new TextWatcher() 
{

@Override
public void afterTextChanged(Editable s)
{
}

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

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


لاحظ إننا إستخدمنا الدالة addTextChangedListener و التي تحدثنا عنها مُنذ قليل مع مربع النص الذي قُمنا بوضعه في واجهتنا، هذه الدالة تستقبل بارامتر من نوع TextWatcher، و TextWatcher عباره عن واجهة (Interface) يجب تعريفها من خلال فئة معينه حتى تكون صالحة للإستخدام، و هذا ما قمنا به في الشيفره بالأعلى.

الدالة التي تُهمنا من الثلاث دوال التي تُقدمها لنا الواجهة TextWatcher هي onTextChanged و كما يوحي لك إسمها فإنها تُنادى عندما يقع تغيير فعلي على النص.

الخطوة الأخيره بسيطة جداً، فكل ما قمنا به هو أخذ الفلتر الخاص بمُحوّلنا و نادينا الدالة filter مُمرين إليها النص الذي سيتم فلتره البيانات وفقاً له. بالطبع هذا النص موجود في المُتغير s ويحتوي على ما قام المُستخدم بكتابته بعد تغييره للنص الموجود داخل مُربع النص.

هذا كُل شيء :)، الشيفرة الكاملة :

package com.example.androidtutorials;

import android.app.Activity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.Menu;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple_list_view);

// ... //

ListView listView = (ListView) findViewById( R.id.listView1 );
EditText txtSearch = (EditText) findViewById( R.id.editText1 );

// ... //

final ArrayAdapter dataAdapter = new ArrayAdapter( this, android.R.layout.simple_list_item_1 );

dataAdapter.add( "GNOME" );
dataAdapter.add( "KDE" );
dataAdapter.add( "Cinnamon" );
dataAdapter.add( "Xfce" );

// ... //

listView.setAdapter( dataAdapter );

// ... //

txtSearch.addTextChangedListener( new TextWatcher()
{

@Override
public void afterTextChanged(Editable s)
{
}

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

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

@Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.simple_list_view, menu);
return true;
}

}