最近在做一个项目,里面的通讯录功能有个需求:根据汉字姓名、拼音姓名、手机号码对通讯录中的联系人进行搜索,刚开始想到了使用SearchView,但是用了以后感觉该控件不够灵活,达不到UI设计的要求。所以就想到了自定义控件实现SearchView的功能,本文就带领大家一步步用EditText和ImageButton实现一个自定义的SearchView。
1.首先是自定义搜索框的布局文件 search_bar_contact.xml:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#eeeeee" > <ImageButton android:id="@+id/search_back_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:background="@null" android:contentDescription="@string/app_name" android:src="@drawable/back" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginRight="10dp" android:layout_toRightOf="@id/search_back_btn" android:background="@drawable/seabar_input" > <EditText android:id="@+id/query" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="4dp" android:background="@null" android:drawableLeft="@drawable/search_bar_icon_normal" android:hint="搜索" android:paddingBottom="3dp" android:paddingLeft="5dp" android:paddingTop="3dp" android:singleLine="true" android:textSize="16sp" /> <ImageButton android:id="@+id/search_clear" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:background="@android:color/transparent" android:contentDescription="@string/app_name" android:src="@drawable/clear" android:visibility="gone" /> </RelativeLayout> </RelativeLayout>
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFFFFF" > <include android:id="@+id/search_top" android:layout_width="match_parent" android:layout_height="wrap_content" layout="@layout/search_bar_contact" /> <TextView android:id="@+id/rule_line_tv" android:layout_width="match_parent" android:layout_height="0.5dp" android:layout_below="@id/search_top" android:background="@color/reserve_line" /> <ListView android:id="@+id/search_lv" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/rule_line_tv" android:background="@android:color/transparent" android:divider="@null" android:visibility="gone" > </ListView> <RelativeLayout android:id="@+id/empty_rl" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/rule_line_tv" android:layout_marginTop="50dp" android:background="@android:color/transparent" > <TextView android:id="@+id/title_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:text="@string/title_tv" android:textColor="@color/grayish" android:textSize="20sp" /> <TextView android:id="@+id/rule_line01_tv" android:layout_width="200dp" android:layout_height="0.5dp" android:layout_below="@id/title_tv" android:layout_centerHorizontal="true" android:layout_marginBottom="10dp" android:layout_marginTop="10dp" android:background="@color/reserve_line" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignLeft="@id/rule_line01_tv" android:layout_alignRight="@id/rule_line01_tv" android:layout_below="@id/rule_line01_tv" android:orientation="horizontal" > <TextView android:id="@+id/hanzi_tv" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="left" android:text="@string/hanzi_tv" android:textColor="@color/gray7" /> <TextView android:id="@+id/pinyin_tv" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="@string/pinyin_tv" android:textColor="@color/gray7" /> <TextView android:id="@+id/phone_tv" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="right" android:text="@string/phone_tv" android:textColor="@color/gray7" /> </LinearLayout> </RelativeLayout> </RelativeLayout>
package com.adapter.contact; import java.util.ArrayList; import com.bean.note.PersonBean; import com.l2cplat.l2cplat.R; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; public class SearchAdapter extends BaseAdapter { private ArrayList<PersonBean> myPersonBeans; private Context myContext; private LayoutInflater inflater; public SearchAdapter(Context context, ArrayList<PersonBean> personBeans) { this.myContext = context; this.myPersonBeans = personBeans; inflater = LayoutInflater.from(myContext); } @Override public int getCount() { return myPersonBeans.size(); } @Override public PersonBean getItem(int position) { return myPersonBeans.get(position); } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { PersonHolder holder = null; if (convertView == null) { holder = new PersonHolder(); convertView = inflater.inflate(R.layout.contact_item, null); holder.headerTv = (TextView) convertView.findViewById(R.id.header); holder.personIv = (ImageView) convertView .findViewById(R.id.contact_iv); holder.nameTv = (TextView) convertView .findViewById(R.id.contact_tv); convertView.setTag(holder); } else { holder = (PersonHolder) convertView.getTag(); } PersonBean personBean = getItem(position); holder.headerTv.setVisibility(View.GONE); if ("1".equals(personBean.getSex())) { holder.personIv.setImageResource(R.drawable.male_s); } else { holder.personIv.setImageResource(R.drawable.female_s); } holder.nameTv.setText(personBean.getName()); return convertView; } private class PersonHolder { TextView headerTv; ImageView personIv; TextView nameTv; } }
package com.contactlist; import java.util.ArrayList; import com.adapter.contact.SearchAdapter; import com.baidu_lbs.LocationApplication; import com.bean.note.PersonBean; import com.l2cplat.l2cplat.MainFragmentActivity; import com.l2cplat.l2cplat.R; import android.app.Activity; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Resources; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.text.Editable; import android.text.TextWatcher; import android.util.DisplayMetrics; import android.view.View; import android.view.View.OnClickListener; import android.view.Window; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.Toast; import android.widget.RelativeLayout.LayoutParams; public class SearchContact extends Activity implements OnClickListener, TextWatcher { private int screenH; private EditText searchEt; private ImageButton clearBtn; private ListView searchLv; private ImageButton backBtn; private RelativeLayout emptyRl; private LoadDataAsyncTask asyncTask; private MainFragmentActivity myActivity = null; private static ProgressDialog myDialog = null; private ArrayList<PersonBean> personBeans = null; private ArrayList<PersonBean> myPersonBeans = null; private SearchAdapter adapter; private String mobilePhone = ""; private String emailTo; private String personId = ""; private Resources r; private int index = 0; private int top = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.search_contact); getScreenPixels(); initWidget(); setWidget(); } @Override public void onStop() { super.onStop(); // 保存当前第一个可见的item的索引和偏移量 index = searchLv.getFirstVisiblePosition(); View v = searchLv.getChildAt(0); top = (v == null) ? 0 : v.getTop(); } private void initWidget() { myActivity = new MainFragmentActivity(); searchEt = (EditText) findViewById(R.id.query); clearBtn = (ImageButton) findViewById(R.id.search_clear); backBtn = (ImageButton) findViewById(R.id.search_back_btn); searchLv = (ListView) findViewById(R.id.search_lv); searchLv.setVerticalScrollBarEnabled(false); emptyRl = (RelativeLayout) findViewById(R.id.empty_rl); clearBtn.setOnClickListener(this); backBtn.setOnClickListener(this); // 根据输入框输入值的改变来过滤搜索 searchEt.addTextChangedListener(this); searchLv.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { personId = myPersonBeans.get(position).getId(); Intent intent = new Intent(SearchContact.this, ContactDetails.class); Bundle bundle = new Bundle(); bundle.putString("personId", personId); intent.putExtras(bundle); startActivity(intent); } }); searchLv.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { mobilePhone = myPersonBeans.get(position).getMobilePhone(); emailTo = myPersonBeans.get(position).getEmail(); System.out.println("--mobilePhone--:" + mobilePhone + "--emailTo--" + emailTo); if (mobilePhone != null && !"".equals(mobilePhone)) { AlertDialog.Builder builder = new AlertDialog.Builder( SearchContact.this); builder.setItems(setChoice(), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { switch (which) { case 0: Intent intent = new Intent( Intent.ACTION_CALL, Uri .parse("tel:" + mobilePhone)); startActivity(intent); break; case 1: Uri uri = Uri.parse("smsto://" + mobilePhone); Intent intent01 = new Intent( Intent.ACTION_SENDTO, uri); startActivity(intent01); break; case 2: Intent intent02 = new Intent( Intent.ACTION_SENDTO, Uri .parse("mailto:" + emailTo)); intent02.putExtra(Intent.EXTRA_SUBJECT, ""); intent02.putExtra(Intent.EXTRA_TEXT, ""); startActivity(intent02); break; } } }).create().show(); builder.setCancelable(true); builder.create().setCanceledOnTouchOutside(true); } else { Toast.makeText(SearchContact.this, "该联系人没有录入联系电话", Toast.LENGTH_SHORT).show(); } return true; } }); } /** * Loads a String array asset into a array. * * @return */ private String[] setChoice() { r = this.getResources(); return r.getStringArray(R.array.contact_type); } private void setWidget() { LayoutParams lpEmptyRl = (LayoutParams) emptyRl.getLayoutParams(); lpEmptyRl.setMargins(0, (int) (screenH * 10.0 / 80), 0, 0); emptyRl.setLayoutParams(lpEmptyRl); } private void getScreenPixels() { DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); screenH = metrics.heightPixels; } @Override public void onClick(View v) { switch (v.getId()) { case R.id.search_clear: searchEt.getText().clear(); break; case R.id.search_back_btn: finish(); break; } } @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) { index = 0; top = 0; if (s != null && !"".equals(s.toString())) { emptyRl.setVisibility(View.GONE); searchLv.setVisibility(View.VISIBLE); clearBtn.setVisibility(View.VISIBLE); asyncTask = new LoadDataAsyncTask(); asyncTask.execute(s.toString()); } else { emptyRl.setVisibility(View.VISIBLE); searchLv.setVisibility(View.GONE); clearBtn.setVisibility(View.GONE); } } private class LoadDataAsyncTask extends AsyncTask<String, Integer, Integer> { /** * 开始执行异步线程 */ @Override protected void onPreExecute() { super.onPreExecute(); myDialog = myActivity.showProgressDialog("数据加载中...", SearchContact.this); } /** * 这里的String参数对应AsyncTask中的第一个参数 这里的String返回值对应AsyncTask的第三个参数 * 该方法并不运行在UI线程当中,主要用于异步操作,所以在该方法中不能对UI的空间进行设置和修改 * 但是可以调用publishProgress方法触发onProgressUpdate对UI进行操作 */ @Override protected Integer doInBackground(String... params) { int result = -1; myPersonBeans = new ArrayList<PersonBean>(); personBeans = LocationApplication.getInstance().getContactList(); if (personBeans != null) { for (int i = 0; i < personBeans.size(); i++) { PersonBean personBean = personBeans.get(i); if (personBean.getName().contains(params[0]) || personBean.getPinyin().contains(params[0]) || personBean.getMobilePhone().contains(params[0])) { myPersonBeans.add(personBean); } } result = 1; } return result; } /** * 这里的Integer参数对应AsyncTask中的第二个参数 在doInBackground方法中,每次调用publishProgress * 方法都会触发onProgressUpdate执行 onProgressUpdate是在UI线程中执行,所以可以对UI空间进行操作 */ @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); } /** * 这里的String参数对应AsyncTask中的第三个参数(也就是接收doInBackground的返回值) * 在doInBackground方法执行结束后再运行,并且运行在UI线程中 可以对UI空间进行设置 */ @Override protected void onPostExecute(Integer result) { super.onPostExecute(result); if (result == 1) { if (myPersonBeans != null) { adapter = new SearchAdapter(SearchContact.this, myPersonBeans); searchLv.setAdapter(adapter); // 根据上次保存的index和偏移量恢复上次的位置 searchLv.setSelectionFromTop(index, top); } } myDialog.dismiss(); } } }