Android自定义下拉列表——PopupWindow+List
2017-11-15 本文已影响3247人
zj_King
最近在项目中使用android原生的Spinner发现其显示效果没有想象中的好,于是就动手写了一个popuwindow的弹出框下拉列表,在popuwindow中主要使用了ListView自带的单选和多选模式。
listview中使用自带的选择框有两种方式,第一种方式:
ListView lv = (ListView) findViewById(R.id.list_view);
lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
第二中方式:就是在listview布局中直接加,建议使用第二种
android:choiceMode="singleChoice"
先书写一个带listview的布局,popuwindow_spinner布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@mipmap/spinner_pop_bg">
<TextView
android:id="@+id/pop_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="6dp"
android:gravity="center"
android:textSize="@dimen/title_size"/>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/grey_line"/>
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="#00000000"
android:choiceMode="singleChoice"
>
</ListView>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/grey_line"/>
<TextView
android:id="@+id/pop_cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="6dp"
android:text="@string/cancel"
android:textColor="@color/orange"
android:gravity="center"
android:textSize="@dimen/title_size"/>
</LinearLayout>
其实在popuwindow中使用listview和在Activity中使用相同,具体实现代码如下(具体使用看注释):
public class SpinnerPopuwindow extends PopupWindow{
private View conentView;
private ListView listView;
private SpinnerPopAdapter adapter;
private Activity context;
private TextView pop_title;
private TextView pop_cancel;
/**
* @param context 上下文
* @param string 获取到未打开列表时显示的值
* @param list 需要显示的列表的集合
* @param itemsOnClick listview在activity中的点击监听事件
*/
@SuppressLint("InflateParams")
public SpinnerPopuwindow(final Activity context, final String string, final List<String> list, AdapterView.OnItemClickListener itemsOnClick) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.context =context;
conentView = inflater.inflate(R.layout.popuwindow_spinner, null);
// 设置SelectPicPopupWindow的View
this.setContentView(conentView);
// 设置SelectPicPopupWindow弹出窗体的宽
this.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
// this.setWidth(view.getWidth());
// 设置SelectPicPopupWindow弹出窗体的高
this.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
// 设置SelectPicPopupWindow弹出窗体可点击
this.setFocusable(true);
// 刷新状态
this.update();
this.setOutsideTouchable(false);
// 实例化一个ColorDrawable颜色为半透明
ColorDrawable dw = new ColorDrawable(0000000000);
// 点back键和其他地方使其消失,设置了这个才能触发OnDismisslistener ,设置其他控件变化等操作
this.setBackgroundDrawable(dw);
this.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss() {
darkenBackground(1f);
}
});
//解决软键盘挡住弹窗问题
this.setSoftInputMode(PopupWindow.INPUT_METHOD_NEEDED);
this.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
// 设置SelectPicPopupWindow弹出窗体动画效果
// this.setAnimationStyle(R.style.AnimationPreview);
adapter = new SpinnerPopAdapter(context,list);
listView = (ListView) conentView.findViewById(R.id.listView);
listView.setOnItemClickListener(itemsOnClick);
listView.setAdapter(adapter);
// setAdapter是异步进行的,为了使弹窗能即时刷新,所以使用post+Runnable
listView.post(new Runnable() {
@Override
public void run() {
//主要是为了比对未打开列表时显示的值和列表中的值进行默认选中
for(int j = 0;j<list.size();j++){
if(string.equals(list.get(j).toString())){
listView.setItemChecked(j, true);//listview自带的方法
}else {
listView.setItemChecked(j, false);
}
}
}
});
pop_title = (TextView) conentView.findViewById(R.id.pop_title);
pop_cancel = (TextView) conentView.findViewById(R.id.pop_cancel);
pop_cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
darkenBackground(1f);
}
});
}
//给下拉列表的设置标题,增加复用性
public void setTitleText(String str){
pop_title.setText(str);
}
//获取选中列表中的数据所对应的position
public int getText(){
return listView.getCheckedItemPosition();
}
/**
* 显示popupWindow
*
* @param parent
*/
public void showPopupWindow(View parent) {
if (!this.isShowing()) {
// 以下拉方式显示popupwindow
// this.showAsDropDown(parent);
// this.showAsDropDown(parent,0,10);
this.showAtLocation(parent, Gravity.BOTTOM|Gravity.CENTER, 0, 0);
darkenBackground(0.9f);//弹出时让页面背景回复给原来的颜色降低透明度,让背景看起来变成灰色
}
}
/**
* 关闭popupWindow
*/
public void dismissPopupWindow() {
this.dismiss();
darkenBackground(1f);//关闭时让页面背景回复为原来的颜色
}
/**
* 改变背景颜色,主要是在PopupWindow弹出时背景变化,通过透明度设置
*/
private void darkenBackground(Float bgcolor){
WindowManager.LayoutParams lp = context.getWindow().getAttributes();
lp.alpha = bgcolor;
context.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
context.getWindow().setAttributes(lp);
}
}
SpinnerPopAdapter书写方式是最基本的适配器写法:
public class SpinnerPopAdapter extends BaseAdapter {
private List<String> content;
private Context context;
private LayoutInflater mInflater;
public SpinnerPopAdapter(Context context,List<String> content){
this.context = context;
this.content = content;
mInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return content == null ? 0 : content.size();
}
@Override
public Object getItem(int position) {
return content.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if(convertView == null){
convertView = mInflater.inflate(R.layout.popuwindow_spinner_item,null);
viewHolder = new ViewHolder();
viewHolder.tv_spinner = (TextView) convertView.findViewById(R.id.tv_spinner);
viewHolder.check = (CheckableLayout) convertView.findViewById(R.id.check);
convertView.setTag(viewHolder);
}else {
viewHolder = (ViewHolder) convertView.getTag();
}
String spinnerText = content.get(position);
viewHolder.tv_spinner.setText(spinnerText);
return convertView;
}
public static class ViewHolder{
TextView tv_spinner;
public CheckableLayout check;
}
}
adapter中布局,其中要记得自定义选中布局CheckableLayout继承自RelativeLayout并实现Checkable,网上例子很多我就不在这儿写了,popuwindow_spinner_item布局:
<?xml version="1.0" encoding="utf-8"?>
<com.goldenlink.credit.view.CheckableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp"
android:duplicateParentState="true"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="30dp"
android:gravity="center"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:duplicateParentState="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="20dp"
android:src="@drawable/singlechoice_selector"/>
</com.goldenlink.credit.view.CheckableLayout>
最主要的是在Activity中的使用
public class NewTaskActivity extends Activity implements View.OnClickListener{
public static final String TAG = "NewTaskActivity";
private ImageView goback;
private LinearLayout task_type;
private TextView tv_type;
private SpinnerPopuwindow mSpinnerPopuwindow;
/** 模拟的假数据 */
private List<String> testData;
private String type;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_newtask);
initView();
}
public void initView(){
goback = (ImageView) findViewById(R.id.goback);
goback.setOnClickListener(this);
task_type = (LinearLayout) findViewById(R.id.task_type);
task_type.setOnClickListener(this);
tv_type = (TextView) findViewById(R.id.tv_type);
TestData();
}
/**
* 模拟假数据
*/
private void TestData() {
testData = new ArrayList<>();
for (int i = 0; i < 3; i++) {
String str = new String("数据" + i);
testData.add(str);
}
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.goback:
this.finish();
break;
case R.id.task_type:
type = tv_type.getText().toString();
mSpinnerPopuwindow = new SpinnerPopuwindow(this,type,testData,itemsOnClick);
mSpinnerPopuwindow.showPopupWindow(task_type);
mSpinnerPopuwindow.setTitleText("类型");//给下拉列表设置标题
break;
}
}
//SchedulePopuwindow为弹出窗口实现监听类
private AdapterView.OnItemClickListener itemsOnClick = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String value = testData.get(mSpinnerPopuwindow.getText());
tv_type.setText(value);
mSpinnerPopuwindow.dismissPopupWindow();
}
};
}
Activity中的布局,activity_newtask布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="@dimen/title_height"
android:background="@mipmap/title_bg" >
<ImageView
android:id="@+id/goback"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_centerInParent="true"
android:layout_marginLeft="10dp"
android:src="@mipmap/goback" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/new_task"
android:textColor="@color/white"
android:textSize="@dimen/title_size" />
</RelativeLayout>
<LinearLayout
android:id="@+id/ll_type"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:layout_gravity="center"
android:background="@color/white"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp"
android:textSize="16sp"
android:text="类型"/>
<LinearLayout
android:id="@+id/task_type"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="8dp"
android:text="请选择类型"
android:textSize="14sp"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center|right"
android:padding="8dp"
android:src="@mipmap/spinner"
/>
</LinearLayout>
</LinearLayout>
</LinearLayout>