Android开发笔记(四十四)动态UI事件

常用的几个事件

动画事件

动画事件主要用于Animation控件,可监控动画开始、结束、重播等行为。相关类名与方法说明如下:
监听器类名 : AnimationListener
设置监听器的方法 : setAnimationListener
监听器需要重写的方法 : 
onAnimationStart : 动画开始播放时调用。
onAnimationEnd : 动画结束播放时调用,该方法用得较多。
onAnimationRepeat : 动画重新播放时调用。


动画事件的具体实现代码可参考《 Android开发笔记(二十一)横幅轮播页Banner》。


翻页事件

翻页事件,主要用于ViewPager控件,可监控翻页状态变化、滚动、选定等行为。相关类名与方法说明如下:
监听器类名 : OnPageChangeListener
设置监听器的方法 : setOnPageChangeListener
监听器需要重写的方法 : 
onPageScrollStateChanged : 翻页状态改变时调用,状态参数取值说明为:0表示静止,1表示正在滑动,2表示滑动完毕。在翻页过程中,状态值变化依次为:正在滑动->滑动完毕->静止。
onPageScrolled : 在翻页过程中调用。该方法的三个参数取值说明为:第一个参数表示当前页面的序号;第二个参数表示当前页面偏移的百分比,最小值为0,最大值为1;第三个参数表示当前页面的偏移距离,单位px。
onPageSelected : 在页面选择时调用,该方法用得较多。位置参数表示当前页面的序号。


翻页事件的具体实现代码可参考《 Android开发笔记(二十一)横幅轮播页Banner》。


文本变化事件

文本变化事件,主要用于EditText控件,包括继承自EditText的AutoCompleteTextView控件,可监控文本变化前、变化中、变化后等行为。相关类名与方法说明如下:
监听器类名 : TextWatcher
设置监听器的方法 : addTextChangedListener
监听器需要重写的方法 : 
beforeTextChanged : 在文本变化前调用。
onTextChanged : 在文本变化中调用。
afterTextChanged : 在文本变化后调用,该方法用得较多。

文本变化事件的具体实现代码可参考《 Android开发笔记(三十六)展示类控件》。



基于AutoCompleteTextView的搜索控件

动画事件和翻页事件在前面章节有过示例了,这里就示范一下文本变化事件的使用。在博文《 Android开发笔记(二十)顶部导航栏ActionBar》里面,博主提到ActionBar自带的搜索框SearchView,但是SearchView存在几点不足:
1、搜索按钮只能显示图标,不能显示中文;
2、搜索框只能放在顶部的ActionBar里面,不能放置于页面的其它位置;
3、用户输入搜索文本时,SearchView无法给出近似的关键词列表提示;
因为SearchView的这些先天不足,所以实际开发中很少直接使用SearchView。为解决以上问题,我们需要自己写个搜索控件,下面便是基于AutoCompleteTextView的一个实现。


首先熟悉下AutoCompleteTextView新增的几个属性:
completionHint : 指定下拉列表底部的提示文字 
completionThreshold : 指定至少输入多少个字符才会显示提示
dropDownHorizontalOffset : 指定下拉列表与文本框之间的水平偏移
dropDownVerticalOffset : 指定下拉列表与文本框之间的垂直偏移
dropDownHeight : 指定下拉列表的高度
dropDownWidth : 指定下拉列表的宽度
singleLine : 指定列表中的每个元素是否单行显示,true表示单行显示,false表示多行显示
在代码中对应的方法是:
setCompletionHint : 设置下拉列表底部的提示文字 
setThreshold : 设置至少输入多少个字符才会显示提示
setDropDownHorizontalOffset : 设置下拉列表与文本框之间的水平偏移
setDropDownVerticalOffset : 设置下拉列表与文本框之间的垂直偏移
setDropDownHeight : 设置下拉列表的高度
setDropDownWidth : 设置下拉列表的宽度
setSingleLine : 设置列表中的每个元素是否单行显示


示例代码主要实现了三个功能:
1、在文本框一开始获得焦点时,自动弹出历史搜索关键词下拉列表;
2、点击下拉列表的某项,文本框自动填入该项的关键词文本;
3、点击搜索按钮,主页面通过回调获得搜索关键词,从而能够做进一步的处理;


下面是AutoCompleteTextView方式的效果图


下面是AutoSearchView搜索控件的示例代码:
import com.example.exmsearch.R;

import android.annotation.SuppressLint;
import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
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;
import android.widget.LinearLayout;

public class AutoSearchView extends LinearLayout 
	implements OnClickListener, OnFocusChangeListener, TextWatcher {
	
	private final static String TAG = "AutoSearchView";
	private Context mContext;
	private LayoutInflater mInflater;
	private View mView;
	
	private SearchClickListener mListener = null;
	private ArrayAdapter<String> mAdapter = null;
	private String mKey;
	private AutoCompleteTextView ac_text;
	private Button btn_auto_search;
	
	public AutoSearchView(Context context) {
		this(context, null);
	}

	public AutoSearchView(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext = context;
		mInflater = LayoutInflater.from(mContext);
	}
	
	public void setOnSearchListener(SearchClickListener listener) {
		mListener = listener;
	}
	
	public SearchClickListener getOnSearchListener() {
		return mListener;
	}

	public void setAdapter(ArrayAdapter<String> adapter) {
		mAdapter = adapter;
	}
	
	public ArrayAdapter<String> getAdapter() {
		return mAdapter;
	}

	@SuppressLint("InflateParams")
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		
		mView = mInflater.inflate(R.layout.view_search_auto, null);
		addView(mView);
		
		ac_text = (AutoCompleteTextView) mView.findViewById(R.id.ac_text);
		ac_text.setAdapter(mAdapter);
		ac_text.setOnFocusChangeListener(this);
		ac_text.addTextChangedListener(this);
		
		btn_auto_search = (Button) mView.findViewById(R.id.btn_auto_search);
		btn_auto_search.setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		if (v.getId() == R.id.btn_auto_search) {
			mListener.onSearchClick(mKey);
		}
	}

	@Override
	public void onFocusChange(View v, boolean hasFocus) {
		if (v instanceof AutoCompleteTextView) {
			if (hasFocus) {
				((AutoCompleteTextView)v).showDropDown();
			}
		}
	}

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

	@Override
	public void onTextChanged(CharSequence s, int start, int before, int count) {
	}

	@Override
	public void afterTextChanged(Editable s) {
		Log.d(TAG, "afterTextChanged s="+s);
		mKey = s.toString();
	}
}

下面是主页面的调用代码:
import com.example.exmsearch.widget.AutoSearchView;
import com.example.exmsearch.widget.SearchClickListener;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.TextView;

public class AutoSearchActivity extends Activity implements SearchClickListener {

	private final static String TAG = "AutoSearchActivity";
	private AutoSearchView asv_text;
	private TextView tv_auto;
	
	private String[] hintArray = {"ab", "abc", "abcde", "abHtp", "aaeet", "aab"};
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_auto);

		tv_auto = (TextView) findViewById(R.id.tv_auto);
		asv_text = (AutoSearchView) findViewById(R.id.asv_text);
		asv_text.setOnSearchListener(this);
		
		ArrayAdapter<String> adapter = new ArrayAdapter<String>(
				this, R.layout.list_auto, hintArray);
		asv_text.setAdapter(adapter);
	}

	@Override
	public void onSearchClick(String key) {
		tv_auto.setText("您输入的搜索关键字是:"+key);
	}

}


基于EditText+ListView的搜索控件

AutoCompleteTextView方式已经较好的实现了大部分搜索功能,可是还不能完全满足电商APP的业务需求。比如弹出商品关键词列表时,往往还希望在每行后面显示该关键词对应的商品数量,从而让用户更有目的地选择合适的商品。基于此,博主在下面又给出了基于EditText+ListView的实现方式,该方式除了在列表中显示关键词与数量外,还增加了一个叉号按钮用来立即清空文本框。


下面是EditText+ListView方式的效果图


下面是CustomSearchView搜索控件的示例代码:
import java.util.ArrayList;

import android.annotation.SuppressLint;
import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;

import com.example.exmsearch.R;

public class CustomSearchView extends LinearLayout implements OnClickListener, TextWatcher {

	private final static String TAG = "CustomSearchView";
	private Context mContext;
	private LayoutInflater mInflater;
	private View mView;

	private SearchClickListener mListener = null;
	private ArrayList<String> mSearchArray = null;
	private String mKey;
	private EditText et_text;
	private Button btn_custom_search;
	private Button btn_clear;
	private ListView lv_custom;
	
	public CustomSearchView(Context context) {
		this(context, null);
	}

	public CustomSearchView(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext = context;
		mInflater = LayoutInflater.from(mContext);
	}

	public void setOnSearchListener(SearchClickListener listener) {
		mListener = listener;
	}
	
	public SearchClickListener getOnSearchListener() {
		return mListener;
	}

	public void setSearchArray(ArrayList<String> keyArray) {
		mSearchArray = keyArray;
	}
	
	public ArrayList<String> getSearchArray() {
		return mSearchArray;
	}

	@SuppressLint("InflateParams")
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		
		mView = mInflater.inflate(R.layout.view_search_custom, null);
		addView(mView);

		et_text = (EditText) mView.findViewById(R.id.et_text);
		et_text.addTextChangedListener(this);
		btn_custom_search = (Button) mView.findViewById(R.id.btn_custom_search);
		btn_custom_search.setOnClickListener(this);
		btn_clear = (Button) mView.findViewById(R.id.btn_clear);
		btn_clear.setOnClickListener(this);
		lv_custom = (ListView) mView.findViewById(R.id.lv_custom);
	}

	private void refresh(boolean bShowList) {
		lv_custom.setVisibility((bShowList==true)?View.VISIBLE:View.GONE);
		et_text.setText(mKey);
		et_text.setFocusable(true);
		et_text.setSelection(mKey.length());
		removeAllViews();
		addView(mView);
	}

	@Override
	public void onClick(View v) {
		if (v.getId() == R.id.btn_custom_search) {
			mListener.onSearchClick(mKey);
		} else if (v.getId() == R.id.btn_clear) {
			mKey = "";
			refresh(false);
		}
	}

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

	@Override
	public void onTextChanged(CharSequence s, int start, int before, int count) {
	}

	@Override
	public void afterTextChanged(Editable s) {
		if (mSearchArray != null && s.toString().equals(mKey)!=true) {
			mKey = s.toString();
			ArrayList<String> keyArray = new ArrayList<String>();
			for (String item : mSearchArray) {
				if (item.indexOf(mKey) == 0) {
					keyArray.add(item);
				}
			}
			if (keyArray.size() > 0) {
				SearchListAdapter adapter = new SearchListAdapter(mContext, keyArray);
				lv_custom.setAdapter(adapter);
				lv_custom.setOnItemClickListener(adapter);
				refresh(true);
			} else {
				refresh(false);
			}
		} else {
			mKey = s.toString();
		}
	}
	
	public class SearchListAdapter extends BaseAdapter implements OnItemClickListener {

		private ArrayList<String> mKeyArray = new ArrayList<String>();

		public SearchListAdapter(Context context, ArrayList<String> keyArray) {
			mKeyArray = keyArray;
		}

		@Override
		public int getCount() {
			return mKeyArray.size();
		}

		@Override
		public Object getItem(int arg0) {
			return mKeyArray.get(arg0);
		}

		@Override
		public long getItemId(int arg0) {
			return arg0;
		}

		@Override
		public View getView(final int position, View convertView, ViewGroup parent) {
			ViewHolder holder = null;
			if (convertView == null) {
				holder = new ViewHolder();
				convertView = mInflater.inflate(R.layout.list_custom, null);
				holder.tv_key = (TextView) convertView.findViewById(R.id.tv_key);
				holder.tv_count = (TextView) convertView.findViewById(R.id.tv_count);
				convertView.setTag(holder);
			} else {
				holder = (ViewHolder) convertView.getTag();
			}

			String keyItem = mKeyArray.get(position);
			holder.tv_key.setText(keyItem.split(",")[0]);
			holder.tv_count.setText(keyItem.split(",")[1]+"个结果");
			return convertView;
		}

		public final class ViewHolder {
			public TextView tv_key;
			public TextView tv_count;
		}

		@Override
		public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
			mKey = mKeyArray.get(position).split(",")[0];
			refresh(false);
		}
	}
	
}

下面是主页面的调用代码:
import java.util.ArrayList;

import com.example.exmsearch.widget.CustomSearchView;
import com.example.exmsearch.widget.SearchClickListener;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class CustomSearchActivity extends Activity implements SearchClickListener {

	private final static String TAG = "CustomSearchActivity";
	private CustomSearchView csv_text;
	private TextView tv_custom;

	private String[] hintArray = {"ab", "abc", "abcde", "abHtp", "aaeet", "aab"};
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_custom);

		tv_custom = (TextView) findViewById(R.id.tv_custom);
		csv_text = (CustomSearchView) findViewById(R.id.csv_text);
		csv_text.setOnSearchListener(this);
		
		ArrayList<String> searchArray = new ArrayList<String>();
		for (int i=0; i<hintArray.length; i++) {
			String item = hintArray[i]+","+(10-i);
			searchArray.add(item);
		}
		csv_text.setSearchArray(searchArray);
	}

	@Override
	public void onSearchClick(String key) {
		tv_custom.setText("您输入的搜索关键字是:"+key);
	}

}



点击下载本文用到的自定义搜索框的工程代码



点此查看Android开发笔记的完整目录



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值