اليوم سنتعرف على عنصر واجهة المستخدم للبحث في أندرويد (Android SearchView) وسنقوم بتطوير تطبيق يقوم بتصفية قائمة عناصر ListView بناءً على النص المُستعلَم عنه. سنستخدم DataBinding لربط التخطيطات في الأنشطة والمُحولات (Adapters). إذا لم تقم بقراءة مقال حول DataBinding، يُرجى الرجوع إلى هذا الدليل أولاً لفهم أفضل.
عنصر واجهة المستخدم للبحث في أندرويد (Android SearchView)
أندرويد يتيح لنا استخدام وظيفة البحث في تطبيقنا عن طريق عرض عنصر واجهة المستخدم للبحث (SearchView) إما في شريط الأدوات (ToolBar/ActionBar) أو بإدراجه في تخطيط. يتم تعريف عنصر واجهة المستخدم للبحث في ملف تعريف الـ XML كما هو موضح أدناه.
<android.support.v7.widget.SearchView
android:id="@+id/search"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
هناك العديد من أشكال البحث في أندرويد مثل البحث الصوتي والاقتراحات وما إلى ذلك. في هذا الدليل، سنستخدم واجهتي SearchView.OnQueryTextListener و Filterable. واجهة Filterable تقوم بتصفية النص المستعلم عنه على قائمة عناصر ListView وتعرض الصفوف الناتجة من ذلك. واجهة OnQueryTextListener يمكنها اكتشاف حدثين.
- يُطلق الحدث onQueryTextChange عندما يقوم المستخدم بكتابة كل حرف في حقل النص
- يُطلق الحدث onQueryTextSubmit عندما يتم الضغط على زر البحث
مثال على Android SearchView
الصورة أدناه تظهر مشروع مثالي لـ Android SearchView. يتكون المشروع من نشاط ومحول لـ ListView.
كود مثال Android SearchView
يتم تقديم activity_main.xml أدناه. يتكون من ListView مع SearchView في الأعلى. activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="https://schemas.android.com/apk/res/android">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<android.support.v7.widget.SearchView
android:id="@+id/search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true" />
<ListView
android:id="@+id/list_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/search" />
</RelativeLayout>
</layout>
تم تقديم MainActivity.java أدناه.
package com.journaldev.searchview;
import android.databinding.DataBindingUtil;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.SearchView;
import com.journaldev.searchview.databinding.ActivityMainBinding;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
ActivityMainBinding activityMainBinding;
ListAdapter adapter;
List<String> arrayList= new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
arrayList.add("January");
arrayList.add("February");
arrayList.add("March");
arrayList.add("April");
arrayList.add("May");
arrayList.add("June");
arrayList.add("July");
arrayList.add("August");
arrayList.add("September");
arrayList.add("October");
arrayList.add("November");
arrayList.add("December");
adapter= new ListAdapter(arrayList);
activityMainBinding.listView.setAdapter(adapter);
activityMainBinding.search.setActivated(true);
activityMainBinding.search.setQueryHint("Type your keyword here");
activityMainBinding.search.onActionViewExpanded();
activityMainBinding.search.setIconified(false);
activityMainBinding.search.clearFocus();
activityMainBinding.search.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
return false;
}
});
}
}
في الكود أعلاه، نقوم بتمرير ArrayList من الأشهر إلى محول القائمة. نحن نستدعي طريقة التصفية المعرفة في فئة المحول في كل مرة يتغير فيها نص الاستعلام عن البحث. تبدو فئة ListAdapter.java مثل هذا.
package com.journaldev.searchview;
import android.content.Context;
import android.databinding.DataBindingUtil;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import com.journaldev.searchview.databinding.RowItemBinding;
import java.util.ArrayList;
import java.util.List;
public class ListAdapter extends BaseAdapter implements Filterable {
List<String> mData;
List<String> mStringFilterList;
ValueFilter valueFilter;
private LayoutInflater inflater;
public ListAdapter(List<String> cancel_type) {
mData=cancel_type;
mStringFilterList = cancel_type;
}
@Override
public int getCount() {
return mData.size();
}
@Override
public String getItem(int position) {
return mData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, final ViewGroup parent) {
if (inflater == null) {
inflater = (LayoutInflater) parent.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
RowItemBinding rowItemBinding = DataBindingUtil.inflate(inflater, R.layout.row_item, parent, false);
rowItemBinding.stringName.setText(mData.get(position));
return rowItemBinding.getRoot();
}
@Override
public Filter getFilter() {
if (valueFilter == null) {
valueFilter = new ValueFilter();
}
return valueFilter;
}
private class ValueFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint != null && constraint.length() > 0) {
List<String> filterList = new ArrayList<>();
for (int i = 0; i < mStringFilterList.size(); i++) {
if ((mStringFilterList.get(i).toUpperCase()).contains(constraint.toString().toUpperCase())) {
filterList.add(mStringFilterList.get(i));
}
}
results.count = filterList.size();
results.values = filterList;
} else {
results.count = mStringFilterList.size();
results.values = mStringFilterList;
}
return results;
}
@Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
mData = (List<String>) results.values;
notifyDataSetChanged();
}
}
}
كما يمكن رؤية في الكود أعلاه، نقوم بأداء عملية التصفية باستخدام فئة داخلية ValueFilter
التي تمتد من الفئة Filter. يقوم بتصفية القائمة عن طريق التحقق مما إذا كان نص استعلام البحث مطابقًا للسلاسل المعطاة في ArrayList. تم تقديم تخطيط XML لصف القائمة أدناه. row_item.xml
<layout xmlns:android="https://schemas.android.com/apk/res/android">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/stringName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:padding="@dimen/activity_horizontal_margin"
android:textAllCaps="false"
android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>
</layout>
مخرج تطبيق بحث Android View في العمل معروض أدناه. يتطلب SearchView المعروض أعلاه منا الضغط على أيقونة البحث لتنشيط حقل النص. أيضًا، لا يحتوي على أي نص تلميح/مكان. أضف الكود التالي في MainActivity لتمكين SearchView بشكل افتراضي وعرض تلميح.
activityMainBinding.search.setActivated(true);
activityMainBinding.search.setQueryHint("Type your keyword here");
activityMainBinding.search.onActionViewExpanded();
activityMainBinding.search.setIconified(false);
activityMainBinding.search.clearFocus();
بعد تخصيص SearchView كما هو مذكور أعلاه، يبدو مظهره كما يلي. يأتي هذا النهاية لبرنامج تعليمي حول Android SearchView. سنقوم بالتعمق في الميزات المتقدمة لـ SearchView في برنامج تعليمي لاحق. يمكنك تحميل مشروع Android SearchView من الرابط المعطى أدناه.
Source:
https://www.digitalocean.com/community/tutorials/android-searchview-example-tutorial