在上一篇博文中写到了ListView的基础用法。
现在大家根据上一篇博文已经可以呈现出一个列表了,但是在实际使用列表的过程中经常会在列表中用到一些按钮、选择框、下拉菜单等功能并获取用户所选择的值。这样的需求在上一篇的用法中已经无法满足,所以博主今天用ListView中嵌套spinner下拉选择列表并获取spinner中的值为例。希望可以给大家一些类似的启发。
先上效果图
在列表中可以选择良好、不良、待修、修理四个选项,点击提交返回结果(四个选项分别对应0、1、2、3)
下面是点击提交后,日志答应的结果。可以看到已经成功获取到了选择的内容
接下来,废话不多说上干货
要做列表的思路当然还是adpter+item.xml,但是因为这个例子用到了spinner这一组件,由于spinner的特性:直接使用spinner组件无法自行规定字体大小、格式等等属性,只能使用默认的,使用起来很难受。所以在做列表适配器前,我们先做一个spinner的适配器。
//Spinner适配器
public class SpotCheckSpinnerAdapter extends BaseAdapter {
private Context mContext;
private String[] values;
public SpotCheckSpinnerAdapter(Context context){
this.mContext = context;
Resources res = mContext.getResources();
this.values = res.getStringArray(R.array.checklist_values);//构建spinner中的值
}
@Override
public int getCount() {
return values.length;
}
@Override
public Object getItem(int position) {
return values[position];
}
@Override
public long getItemId(int position) {
return 0;
}
//缓存选项内容
private class ViewHolder {
TextView spinner_value;
}
public View getView(int position, View converView, ViewGroup parent){
ViewHolder holder;
if (converView == null){
converView = View.inflate( mContext,R.layout.spinner_value,null );
holder = new ViewHolder();
holder.spinner_value = (TextView) converView.findViewById( .spinner_value );
converView.setTag( holder );
}else {
holder = (ViewHolder) converView.getTag();
}
String value = values[position];
holder.spinner_value.setText( value );
return converView;
}
}
说一下这里ViewHolder的作用,每次进入页面都要执行getView,所以等列表的长度超过一页时会出现当页面滑动时,有一部分内容消失,当这部分内容再次进入页面时会getView,这就导致了数据错位等现象。使用ViewHolder把所有已经选择的内容存起来当再次用到时取出,这样就避免了数据错位的问题。
spinner中的值由R.array.checklist_values确定
该文件目录为
代码如下:
<resources>
<string-array name="checklist_values">
<item>良好</item>
<item>不良</item>
<item>待修</item>
<item>修理</item>
</string-array>
</resources>
这样spinner适配器就做好了。接下来要在列表适配器中加入spinner适配器
还是先写列表item.xml,很简单不做解释,直接上代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http:///apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="10dp"
android:paddingRight="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="40dp"
android:textSize="20dp"
android:id="@+id/checkinfo_item_name"
android:gravity="center_vertical"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="40dp"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点检完成:"
android:gravity="center_vertical"
android:textSize="20dp" />
<Spinner
android:layout_width="125dp"
android:layout_height="wrap_content"
android:id="@+id/checkinfo_item_value"/>
</LinearLayout>
</LinearLayout>
构建列表适配器
public class SpotCheckDetailItemAdapter extends BaseAdapter {
private Context mContext;
private String[] checkListName;
private Map<String,Integer> allValues;//用于存储spinner 内容
public SpotCheckDetailItemAdapter(Context context,String[] checkListName){
this.mContext = context;
this.checkListName = checkListName;
allValues = new HashMap<String, Integer>();
putAllValues();
}
//把数据存储入allValues
private void putAllValues() {
for (String str:checkListName){
allValues.put(str,0);
}
}
public void setAllValues(Map<String,Integer>allValues){
this.allValues = allValues;
}
@Override
public int getCount() {
return checkListName.length;
}
@Override
public Object getItem(int position) {
return checkListName[position];
}
@Override
public long getItemId(int i) {
return 0;
}
private class ViewHolder{
TextView checkinfo_item_name;
Spinner checkinfo_item_value;
}
public View getView(int position, View converView, ViewGroup parent){
ViewHolder holder;
if (converView == null){
converView = View.inflate(mContext,R.layout.spotcheckdetail_item,null);
holder = new ViewHolder();
holder.checkinfo_item_name = (TextView) converView.findViewById( .checkinfo_item_name );
holder.checkinfo_item_value = (Spinner) converView.findViewById( .checkinfo_item_value );
SpotCheckSpinnerAdapter adapter = new SpotCheckSpinnerAdapter( mContext );//spnner适配器实例
holder.checkinfo_item_value.setAdapter( adapter );
holder.checkinfo_item_value.setOnItemSelectedListener(new ItemClickSelectListener( holder.checkinfo_item_value));
converView.setTag( holder );//将holder存在converView中
}else {
holder = (ViewHolder) converView.getTag();//重新获取Viewholder
}
String checkedName = checkListName[position];
holder.checkinfo_item_name.setText( checkedName );
holder.checkinfo_item_value.setPrompt( checkedName );
int spinnerOptionPosition = allValues.get( checkedName );//获取spnner的值
holder.checkinfo_item_value.setSelection(spinnerOptionPosition);//重新加载spnner内容
return converView;
}
private class ItemClickSelectListener implements AdapterView.OnItemSelectedListener {
Spinner checkinfo_item_value;
public ItemClickSelectListener(Spinner checkinfo_item_value) {
this.checkinfo_item_value = checkinfo_item_value;
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
allValues.put( checkinfo_item_value.getPrompt().toString(),position );//记录spinner的选择内容
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
}
public Map<String,Integer> getSelectValues() {
return allValues;
}
}
列表适配器中把spinner中的值存储在HashMap中,通过getSelectValues()方法返回结果。其他我认为重要的部分都加了注释,应该可以理解了。
最后一步就是在activity中调用这个适配器了
activity_spot_check_detail.xml
<LinearLayout
xmlns:android="http:///apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/list_spotcheckdetail">
</ListView>
</LinearLayout>
spot_check_commit_button.xml
<LinearLayout
xmlns:android="http:///apk/res/android"
android:layout_width="match_parent"
android:layout_height="80dp"
android:gravity = "center"
android:paddingRight="10dp"
android:paddingLeft="10dp">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/button_commit"
android:text="提交"
android:textSize="20dp"/>
</LinearLayout>
这里把列表和提交按钮写在两个xml中,为的是当列表超出一页时做到同步滚动。如果直接把按钮放在列表的下方会出现按钮固定不动的问题。
最后一步,胜利在望
public class SpotCheckDetailActivity extends AppCompatActivity {
private String[] item = {"设备标牌","压力表","安全阀","密封性"};
private ListView spotCheckDetaiList;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_spot_check_detail);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null){
actionBar.hide();
}
//点检项列表
spotCheckDetaiList = (ListView) findViewById( .list_spotcheckdetail);
//适配器实例化
final SpotCheckDetailItemAdapter adapter = new SpotCheckDetailItemAdapter( this,item);
//底部提交按钮布局加载
View view_bottom = View.inflate( SpotCheckDetailActivity.this,R.layout.spot_check_commit_button,null );
spotCheckDetaiList.addFooterView( view_bottom );//把按钮布局添加到listView的下方
Button commit = (Button) findViewById( .button_commit );
commit.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.d( "MainActivity", String.valueOf( adapter.getSelectValues() ) );
}
} );
//建立适配器
spotCheckDetaiList.setAdapter( adapter );
}
}
到这里就和上一篇讲的列表的基本用法一样了。大功告成!
大家可以看到列表的使用重点是适配器的构建,基本上所有列表的操作都要在适配器中完成。