1. 程式人生 > >用AutoCompleteTextView實現歷史記錄提示

用AutoCompleteTextView實現歷史記錄提示


       這畫面不陌生吧,百度的提示,他的詞庫並不是歷史記錄,是搜尋引擎收集的當前最常搜尋的內容。假如我們也要在android的應用實現如上功能怎麼做呢?
方法很簡單,android已經幫我們寫好了api ,這裡就用到了AutoCompleteTextView元件。
       網上有不少教程,那個提示框字符集都是事先寫好的,例如用一個String[] 陣列去包含了這些資料,但是,我們也可以吧使用者輸入的作為歷史記錄儲存
       下面先上我寫的程式碼:

import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;

public class Read_historyActivity extends Activity implements
		OnClickListener {
	private AutoCompleteTextView autoTv;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		autoTv = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView1);
		initAutoComplete("history",autoTv);
		Button search = (Button) findViewById(R.id.button1);
		search.setOnClickListener(this);
	}
	@Override
	public void onClick(View v) {
		// 這裡可以設定:當搜尋成功時,才執行儲存操作
		saveHistory("history",autoTv);
	}

	/**
	 * 初始化AutoCompleteTextView,最多顯示5項提示,使
	 * AutoCompleteTextView在一開始獲得焦點時自動提示
	 * @param field 儲存在sharedPreference中的欄位名
	 * @param auto 要操作的AutoCompleteTextView
	 */
	private void initAutoComplete(String field,AutoCompleteTextView auto) {
		SharedPreferences sp = getSharedPreferences("network_url", 0);
		String longhistory = sp.getString("history", "nothing");
		String[]  hisArrays = longhistory.split(",");
		ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
				android.R.layout.simple_dropdown_item_1line, hisArrays);
		//只保留最近的50條的記錄
		if(hisArrays.length > 50){
			String[] newArrays = new String[50];
			System.arraycopy(hisArrays, 0, newArrays, 0, 50);
			adapter = new ArrayAdapter<String>(this,
					android.R.layout.simple_dropdown_item_1line, newArrays);
		}
		auto.setAdapter(adapter);
		auto.setDropDownHeight(350);
		auto.setThreshold(1);
		auto.setCompletionHint("最近的5條記錄");
		auto.setOnFocusChangeListener(new OnFocusChangeListener() {
			@Override
			public void onFocusChange(View v, boolean hasFocus) {
				AutoCompleteTextView view = (AutoCompleteTextView) v;
				if (hasFocus) {
						view.showDropDown();
				}
			}
		});
	}



	/**
	 * 把指定AutoCompleteTextView中內容儲存到sharedPreference中指定的字元段
	 * @param field  儲存在sharedPreference中的欄位名
	 * @param auto  要操作的AutoCompleteTextView
	 */
	private void saveHistory(String field,AutoCompleteTextView auto) {
		String text = auto.getText().toString();
		SharedPreferences sp = getSharedPreferences("network_url", 0);
		String longhistory = sp.getString(field, "nothing");
		if (!longhistory.contains(text + ",")) {
			StringBuilder sb = new StringBuilder(longhistory);
			sb.insert(0, text + ",");
			sp.edit().putString("history", sb.toString()).commit();
		}
	}
}
              上面的程式碼我實現了autocomplettextview的從sharepreference中讀取歷史記錄並顯示的功能,當沒有任何輸入時,提示最新的5項歷史記錄(這裡可以加個條件,當有歷史記錄時才顯示)
              補上佈局的程式碼
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent">
	<TextView android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:text="@string/hello" />
	<LinearLayout android:layout_width="0px"
		android:layout_height="0px" android:focusable="true"
		android:focusableInTouchMode="true"></LinearLayout>
	<AutoCompleteTextView
		android:hint="請輸入文字進行搜尋" android:layout_height="wrap_content"
		android:layout_width="match_parent"
		android:id="@+id/autoCompleteTextView1">
	</AutoCompleteTextView>
	<Button android:text="搜尋" android:id="@+id/button1"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"></Button>
</LinearLayout>
          當之有一個edittext或者auto的時候,進入畫面時是預設得到焦點的,要想去除焦點,可以在auto之前加一個o畫素的layout,並設定他先得到焦點。

效果圖如下


下面出現的是原始碼內容 

               需要注意的是,我這裡用到的AutoCompleteTextView的幾個方法
               1. setAdapter()方法:這裡要傳遞的adapter引數必須是繼承ListAdapter和Filterable的,其中arrayAdapter和simpleAdapter都能滿足要求,我們常用arrayAdapter,因為他不需要像simpleAdapte那樣設定他的顯示位置和textview元件。
               要想掌握它,就必須檢視他的原始碼,我們可以看看arrayadapter是如何實現
              凡是繼承了Filterable的adapter都必須重寫getFilter介面方法
    public Filter getFilter() {
        if (mFilter == null) {
            mFilter = new ArrayFilter();
        }
        return mFilter;
    }
          這個filter 就是實現過濾方法的物件,同樣,我們可以檢視他的原始碼是如何實現的
           
 /**
     * <p>An array filter constrains the content of the array adapter with
     * a prefix. Each item that does not start with the supplied prefix
     * is removed from the list.</p>
     */
    private class ArrayFilter extends Filter {
        @Override
        protected FilterResults performFiltering(CharSequence prefix) {
            FilterResults results = new FilterResults();

            if (mOriginalValues == null) {
                synchronized (mLock) {
                    mOriginalValues = new ArrayList<T>(mObjects);
                }
            }

            if (prefix == null || prefix.length() == 0) {
                synchronized (mLock) {
                    ArrayList<T> list = new ArrayList<T>(mOriginalValues);
                    results.values = list;
                    results.count = list.size();
                }
            } else {
                String prefixString = prefix.toString().toLowerCase();

                final ArrayList<T> values = mOriginalValues;
                final int count = values.size();

                final ArrayList<T> newValues = new ArrayList<T>(count);

                for (int i = 0; i < count; i++) {
                    final T value = values.get(i);
                    final String valueText = value.toString().toLowerCase();

                    // First match against the whole, non-splitted value
                    if (valueText.startsWith(prefixString)) {
                        newValues.add(value);
                    } else {
                        final String[] words = valueText.split(" ");
                        final int wordCount = words.length;

                        for (int k = 0; k < wordCount; k++) {
                            if (words[k].startsWith(prefixString)) {
                                newValues.add(value);
                                break;
                            }
                        }
                    }
                }

                results.values = newValues;
                results.count = newValues.size();
            }

            return results;
        }
          這是arrayAdapter自定義的一個私有內部類,所謂私有,就意味著你不能通過繼承去修改這種過濾方法,同樣你也不能直接得到他過濾後結果集results。假如你想使用新的過濾方法,你必須重寫getfilter()方法,返回的filter物件是你要新建的filter物件(在裡面包含performFiltering()方法重新構造你要的過濾方法)
          
         2.setDropDownHeight方法 ,用來設定提示下拉框的高度,注意,這只是限制了提示下拉框的高度,提示資料集的個數並沒有變化
         3.setThreshold方法,設定從輸入第幾個字元起出現提示
         4.setCompletionHint方法,設定提示框最下面顯示的文字
         5.setOnFocusChangeListener方法,裡面包含OnFocusChangeListener監聽器,設定焦點改變事件
         6.showdropdown方法,讓下拉框彈出來
         

        我沒有用到的一些方法列舉
1.clearListSelection,去除selector樣式,只是暫時的去除,當用戶再輸入時又重新出現
2.dismissDropDown,關閉下拉提示框
3.enoughToFilter,這是一個是否滿足過濾條件的方法,sdk建議我們可以重寫這個方法
4. getAdapter,得到一個可過濾的列表介面卡
5.getDropDownAnchor,得到下拉框的錨計的view的id
6.getDropDownBackground,得到下拉框的背景色
7.setDropDownBackgroundDrawable,設定下拉框的背景色
8.setDropDownBackgroundResource,設定下拉框的背景資源
9.setDropDownVerticalOffset,設定下拉表垂直偏移量,即是list裡包含的資料項數目
10.getDropDownVerticalOffset ,得到下拉表垂直偏移量
11..setDropDownHorizontalOffset,設定水平偏移量
12.setDropDownAnimationStyle,設定下拉框的彈出動畫
13.getThreshold,得到過濾字元個數
14.setOnItemClickListener,設定下拉框點選事件
15.getListSelection,得到下拉框選中為位置
16.getOnItemClickListener。得到單項點選事件
17.getOnItemSelectedListener得到單項選中事件
18.getAdapter,得到那個設定的介面卡

一些隱藏方法和構造我沒有列舉了,具體可以參考api文件 
可下載我的寫的demo: http://download.csdn.net/detail/iamkila/4042528

轉載我的檔案請註明出處 http://blog.csdn.net/iamkila?viewmode=contents