我要总结一下关于ListView(用于垂直显示的列表控件的问题,这是我创建android控件中遇到的最难的一个,同时老师给的代码一堆坑,只能不断自己搜资料解决问题,花了一堆时间才大致理清ListView,累的不行。
运行结果图:
贴上源码:
这是activity_main.xml的代码:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.test43.MainActivity" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> <ListView android:id="@+id/android:list" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_marginBottom="22dp" android:drawSelectorOnTop="false" android:scrollbars="vertical" > </ListView> </RelativeLayout>
这是List使用的布局文件user.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:orientation="horizontal" android:paddingLeft="10dip" android:paddingTop="10dip" android:paddingRight="10dip"> <TextView android:id="@+id/user_name" android:layout_width="250dip" android:layout_height="wrap_content" android:singleLine="true" android:textSize="10pt" android:gravity="left"/> <TextView android:id="@+id/user_ip" android:layout_width="50dip" android:layout_height="wrap_content" android:singleLine="true" android:textSize="10pt" android:gravity="center"/> </LinearLayout>
这是MainActivity.java的代码:
package com.example.test43; import java.util.ArrayList; import java.util.HashMap; import android.app.Activity; import android.app.ListActivity; import android.os.Bundle; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.ListView; import android.widget.SimpleAdapter; public class MainActivity extends ListActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //数据源部分 ArrayList<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>(); HashMap<String, String> map1 = new HashMap<String, String>(); HashMap<String, String> map2 = new HashMap<String, String>(); HashMap<String, String> map3 = new HashMap<String, String>(); map1.put("user_name", "张三"); map1.put("user_ip", "192.168.0.1"); map2.put("user_name", "李四"); map2.put("user_ip", "192.168.0.1"); map3.put("user_name", "王五"); map3.put("user_ip", "192.168.0.1"); list.add(map1); list.add(map2); list.add(map3); ListView listView=(ListView)findViewById(android.R.id.list); registerForContextMenu(listView); //注册上下文菜单 SimpleAdapter listAdapter = new SimpleAdapter(this, list, R.layout.user, new String[]{"user_name","user_ip"}, new int[]{R.id.user_name,R.id.user_ip}); //新建适配器并添加数据源到适配器 setListAdapter(listAdapter); //视图加载适配器,将SimpleAdapter设置给当前的ListActivity } //添加点击事件监听,获取选中项的值 @Override protected void onListItemClick(ListView l, View v, int position, long id) { // TODO Auto-generated method stub super.onListItemClick(l, v, position, id); System.out.println("id--------------"+id); System.out.println("position--------"+position); } public void onCreateContextMenu(ContextMenu menu,View v,ContextMenuInfo menuInfo){ menu.setHeaderTitle("选项"); menu.add(0, 1, 1, "删除"); menu.add(0, 2, 3, "编辑"); super.onCreateContextMenu(menu, v, menuInfo);} //菜单单击响应 @Override public boolean onContextItemSelected(MenuItem item){ return true;} @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
总结:
1.java当中有个ListView的事件监听器的问题:
我们所定义的Activity 要继承ListActivity,它是Activity的子类
原因是:onListItemClick方法是ListActivity才有的方法,在Activity中是无效的
解决方法是:方法一、继承ListActivity就可直接使用 protected void onListItemClick(ListView l, View v, int position, long id){ }就有了添加事件监听器的相关操作。
方法二、如果你非要继承Activity,代码就要改成:仍然有两种方法给ListView来setOnItemClickListener
方法1.让你的Activity实现OnItemClickListener接口(Implement OnItemClickListener to your Activity),并将onListItemClick()方法变为onItemClick()方法
代码示例:
public class MyActivity extends Activity implements OnItemClickListener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
}
}
方法2.将onListItemClick方法换成mListView.setOnItemClickListener
代码示例:
mListView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
}
});
参考链接:The method onListItemClick(ListView, View, int, long) of type MainActivity must override or implement a supertype method(来自Stack Overflow)
2.ListView使用了适配器SimpleAdapter
适配器(Adapter)一般是为ListView提供数据的转换,当然GridView[网格视图]、Spinner[下拉列表]、Gallery[画廊]、ViewPage等都需要使用适配器来为其设置数据源。Android项目中一般使用BaseAdapter、SimpleAdapter和ArrayAdapter三种适配器。
适配器是把数据变成符合界面风格的形式,并且通过ListView显示出来,也就是说适配器是数据和界面之间的桥梁。适配器在数据库中的数据(后台)和显示页面(前端)中充当一个转换器的角色,数据库中的数据(如数组,链表,数据库,集合等)通过适配器变成手机页面能够正常显示的数据。可以看作是界面数据绑定的一种理解。假设把数据、适配器和ListView(页面)比喻成一个MVC模式的话,那么适配器(Adapter)在这中间就充当了Controller的角色。
参考链接:1.适配器功能的图片理解
2.Android应用项目中BaseAdapter、SimpleAdapter和ArrayAdapter中的三种适配器
3.SimpleAdapter 的用法及点击事件中如何获取选中项的值
3.关于数据源的问题
适配器(Adapter)是给ListView界面绑定数据的,而这数据源的编写方法也有多种。
(1)直接写在protected void onCreate(Bundle savedInstanceState) {}中,如我们本例中的一样
(2)单独写一个数据源的getdata()方法,返回数据源list(新建自定义List<Map<String,Object>> dataList,并通过方法返回到适配器中)
代码示例:
package com.example.administrator.mydivlistview; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.TextView; import android.widget.Toast; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener{ private ListView listview; private SimpleAdapter sim_adapter; private TextView text; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.layout); text=(TextView) findViewById(R.id.text); listview = (ListView) findViewById(R.id.listview); sim_adapter = new SimpleAdapter(this, getdata(), R.layout.item, new String[]{"pic", "text"}, new int[]{R.id.pic, R.id.text}); listview.setAdapter(sim_adapter); listview.setOnItemClickListener(this); } private List<Map<String, Object>> getdata() { List<Map<String, Object>> list = new ArrayList<Map<String, Object>>(); Map<String, Object> map = new HashMap<String, Object>(); map.put("pic", R.drawable.apple_pic); map.put("text", "apple"); list.add(map); map = new HashMap<String, Object>(); map.put("pic", R.drawable.pear_pic); map.put("text", "pear"); list.add(map); map = new HashMap<String, Object>(); map.put("pic", R.drawable.watermelon_pic); map.put("text", "watermelon"); list.add(map); map = new HashMap<String, Object>(); map.put("pic", R.drawable.cherry_pic); map.put("text", "cherry"); list.add(map); map = new HashMap<String, Object>(); map.put("pic", R.drawable.strawberry_pic); map.put("text", "strawberry"); list.add(map); map = new HashMap<String, Object>(); map.put("pic", R.drawable.grape_pic); map.put("text", "grape"); list.add(map); map = new HashMap<String, Object>(); map.put("pic", R.drawable.orange_pic); map.put("text", "orange"); list.add(map); map = new HashMap<String, Object>(); map.put("pic", R.drawable.mango_pic); map.put("text", "mango"); list.add(map); map = new HashMap<String, Object>(); map.put("pic", R.drawable.pineapple_pic); map.put("text", "pineapple"); list.add(map); map = new HashMap<String, Object>(); map.put("pic", R.drawable.banana_pic); map.put("text", "banana"); list.add(map); return list; } @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { /*adapterView是指当前的listview; *view是当前listview中的item的view的布局,就是可用这个view获取里面控件id后操作控件 * i是当前item在listview中适配器的位置 * l是当前item在listview里第几行的位置 */ //获得选中项中的HashMap对象 HashMap<String,String> map=(HashMap<String,String>)adapterView.getItemAtPosition(i); String Text=map.get("text"); Toast.makeText(MainActivity.this,Text,Toast.LENGTH_SHORT).show(); } }4.因为使用了上下文,所以有涉及上下文的方法
项目的文件结构:
创建ListView过程中遇到的问题:
1、在AVD上打开app时,会提示"unfortunately ,项目名 has stopped"
解决办法:我遇到的情况是刚好在logcat下面显示了错误信息:"Your content must have a ListView whose id attribute is android.R.id.list",然后就去解决这个问题。通过搜索资料得知:应将main.xml中的<ListView>标签中的ListView的ID由android:id="@+id/list"(通过控件生成ListView时自动生成的语句)改为android:id="@id/android:list"。这时main.java中的ListView listView=(ListView)findViewById(R.id.list);语句就会报错,需将参数改为android.R.id.list即可。
2、工程内容没有错误,但是工程图标却有红叉 或者运行时显示:Your project contain errors,please fix them before running your application
(1)我的情况是控制台(console)提示: [2018-04-12 21:28:49 - Dex Loader] Failed to load D:\Program Files\study\Android SDK\android-sdk-windows\build-tools\27.0.3\lib\dx.jar
[2018-04-12 21:28:49 - test49] Unknown error: Unable to build: the file dx.jar was not loaded from the SDK folder!
问题产生的原因是:Android SDK Build-tools的版本已经高于Android SDK Platform-tools版本了
解决办法是:方法一:找到你的sdk安装位置(我的是:D:\Program Files\study\Android SDK\android-sdk-windows\build-tools),找到build-tools下面你安装的build-tools版本,选择一个以往的版本,然后在安卓工程中打开project-properties文件,在里面添上一句: sdk.buildtools=25.0.0。该方法的参考链接是:解决Unknown error: Unable to build: the file dx.jar was not loaded from the SDK folder!
方法二:在你安装sdk的目录下找到你安装的build-tools(我的是D:\Program Files\study\Android SDK\android-sdk-windows\build-tools),将老版本build-tool的lib文件夹下的dx.jar(我的是\25.0.0\lib\dx.jar)替换新版本的build-tool的dx.jar。该方法的参考链接:关于解决Eclipse报错显示Unable to build: the file dx.jar was not loaded from the SDK folder