在Android里,直接提供的Spinner控件虽然可以实现下拉菜单的效果,但其效果并不理想,很多时候我们需要类似手机QQ那样既可以在文本框中直接输入编辑文字,可以在下拉菜单中选中或者删除菜单选项,并且下拉菜单并不是以遮罩整个手机屏幕方式,而是以浮动在屏幕上的效果出现。下面呢,就来实现一下这些效果。
此次主要以EdiText、PopupWindow、ListView及Adapter来实现这种下拉效果。具体实现步骤就不一步步详细介绍了,直接贴完整代码吧,注释比较详细,相信都能看得懂。
//主界面Activity代码:
public class SelectActivity extends Activity implements Callback { //PopupWindow对象 private PopupWindow selectPopupWindow= null; //自定义Adapter private OptionsAdapter optionsAdapter = null; //下拉框选项数据源 private ArrayList<String> datas = new ArrayList<String>();; //下拉框依附组件 private LinearLayout parent; //下拉框依附组件宽度,也将作为下拉框的宽度 private int pwidth; //文本框 private EditText et; //下拉箭头图片组件 private ImageView image; //恢复数据源按钮 private Button button; //展示所有下拉选项的ListView private ListView listView = null; //用来处理选中或者删除下拉项消息 private Handler handler; //是否初始化完成标志 private boolean flag = false; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.select); } /** * 没有在onCreate方法中调用initWedget(),而是在onWindowFocusChanged方法中调用, * 是因为initWedget()中需要获取PopupWindow浮动下拉框依附的组件宽度,在onCreate方法中是无法获取到该宽度的 */ @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); while(!flag){ initWedget(); flag = true; } } /** * 初始化界面控件 */ private void initWedget(){ //初始化Handler,用来处理消息 handler = new Handler(SelectActivity.this); //初始化界面组件 parent = (LinearLayout)findViewById(R.id.parent); et = (EditText)findViewById(R.id.edittext); image = (ImageView)findViewById(R.id.btn_select); //获取下拉框依附的组件宽度 int width = parent.getWidth(); pwidth = width; //设置点击下拉箭头图片事件,点击弹出PopupWindow浮动下拉框 image.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(flag){ //显示PopupWindow窗口 popupWindwShowing(); } } }); //初始化PopupWindow initPopuWindow(); button = (Button)findViewById(R.id.refresh); //设置点击事件,恢复下拉框列表数据,没有什么作用,纯粹是为了方便多看几次效果而设置 button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { initDatas(); optionsAdapter.notifyDataSetChanged(); } }); } /** * 初始化填充Adapter所用List数据 */ private void initDatas(){ datas.clear(); datas.add("北京"); datas.add("上海"); datas.add("广州"); datas.add("深圳"); datas.add("重庆"); datas.add("青岛"); datas.add("石家庄"); } /** * 初始化PopupWindow */ private void initPopuWindow(){ initDatas(); //PopupWindow浮动下拉框布局 View loginwindow = (View)this.getLayoutInflater().inflate(R.layout.options, null); listView = (ListView) loginwindow.findViewById(R.id.list); //设置自定义Adapter optionsAdapter = new OptionsAdapter(this, handler,datas); listView.setAdapter(optionsAdapter); selectPopupWindow = new PopupWindow(loginwindow, pwidth,LayoutParams.WRAP_CONTENT, true); selectPopupWindow.setOutsideTouchable(true); //这一句是为了实现弹出PopupWindow后,当点击屏幕其他部分及Back键时PopupWindow会消失, //没有这一句则效果不能出来,但并不会影响背景 //本人能力极其有限,不明白其原因,还望高手、知情者指点一下 selectPopupWindow.setBackgroundDrawable(new BitmapDrawable()); } /** * 显示PopupWindow窗口 * * @param popupwindow */ public void popupWindwShowing() { //将selectPopupWindow作为parent的下拉框显示,并指定selectPopupWindow在Y方向上向上偏移3pix, //这是为了防止下拉框与文本框之间产生缝隙,影响界面美化 //(是否会产生缝隙,及产生缝隙的大小,可能会根据机型、Android系统版本不同而异吧,不太清楚) selectPopupWindow.showAsDropDown(parent,0,-3); } /** * PopupWindow消失 */ public void dismiss(){ selectPopupWindow.dismiss(); } /** * 处理Hander消息 */ @Override public boolean handleMessage(Message message) { Bundle data = message.getData(); switch(message.what){ case 1: //选中下拉项,下拉框消失 int selIndex = data.getInt("selIndex"); et.setText(datas.get(selIndex)); dismiss(); break; case 2: //移除下拉项数据 int delIndex = data.getInt("delIndex"); datas.remove(delIndex); //刷新下拉列表 optionsAdapter.notifyDataSetChanged(); break; } return false; } }
自定义适配器Adapter代码:
public class OptionsAdapter extends BaseAdapter { private ArrayList<String> list = new ArrayList<String>(); private Activity activity = null; private Handler handler; /** * 自定义构造方法 * @param activity * @param handler * @param list */ public OptionsAdapter(Activity activity,Handler handler,ArrayList<String> list){ this.activity = activity; this.handler = handler; this.list = list; } @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if (convertView == null) { holder = new ViewHolder(); //下拉项布局 convertView = LayoutInflater.from(activity).inflate(R.layout.option_item, null); holder.textView = (TextView) convertView.findViewById(R.id.item_text); holder.imageView = (ImageView) convertView.findViewById(R.id.delImage); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.textView.setText(list.get(position)); //为下拉框选项文字部分设置事件,最终效果是点击将其文字填充到文本框 holder.textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Message msg = new Message(); Bundle data = new Bundle(); //设置选中索引 data.putInt("selIndex", position); msg.setData(data); msg.what = 1; //发出消息 handler.sendMessage(msg); } }); //为下拉框选项删除图标部分设置事件,最终效果是点击将该选项删除 holder.imageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Message msg = new Message(); Bundle data = new Bundle(); //设置删除索引 data.putInt("delIndex", position); msg.setData(data); msg.what = 2; //发出消息 handler.sendMessage(msg); } }); return convertView; } } class ViewHolder { TextView textView; ImageView imageView; }
主界面布局select.xml文件:
<?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" android:background="#EEEED1" > <LinearLayout android:id="@+id/parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:orientation="horizontal"
android:layout_marginTop="50dp" android:layout_marginLeft="30dp"> <EditText android:id="@+id/edittext" android:layout_width="200dp" android:singleLine="true" android:layout_height="40dp" android:background="@drawable/bg1" android:paddingLeft="3dp"/> <ImageView android:id="@+id/btn_select" android:layout_width="30dp" android:layout_height="40dp" android:src="@drawable/img1" android:scaleType="fitXY"/> </LinearLayout> <Button android:id="@+id/refresh" android:layout_width="wrap_content" android:layout_height="45dp" android:text="恢复" android:textColor="#000000" android:textSize="20sp"
android:layout_marginTop="30dp" android:layout_marginLeft="30dp"/> </LinearLayout>
PopupWindow浮动下拉框布局options.xml文件:
<?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="wrap_content" android:gravity="center_horizontal" > <ListView android:id="@+id/list" android:layout_width="fill_parent" android:layout_height="wrap_content" android:cacheColorHint="#00000000"> </ListView> </LinearLayout>
下拉选项布局option_item.xml文件:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#235654" > <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center_vertical" android:minHeight="40dp" > <ImageView android:id="@+id/delImage" android:layout_width="20dp"
android:layout_height="wrap_content" android:src="@drawable/del" android:textSize="18sp" android:layout_alignParentRight="true" android:layout_marginRight="10dp"/> <TextView android:id="@+id/item_text" android:layout_height="wrap_content" android:layout_width="fill_parent" android:layout_toLeftOf="@id/delImage" android:paddingLeft="5dp" android:layout_alignParentLeft="true"></TextView> </RelativeLayout> </LinearLayout>
到此代码及布局文件基本都贴完了。哦,对了,我是在Android 2.2 测试运行的。
本人对Android学习、了解十分有限,而且各种文件、变量、方法等等命名也很不规范,所以代码肯定有很多不足之处,还请各位海涵!当然,更希望各位能不吝赐教,本人将满怀荣幸与感激!
原帖地址:http://blog.csdn.net/zw_yuyan/article/details/7734736