ListView在android开放中用的比较多,所以接下来就进行ListView的使用的讲解。

首先创建一个android项目,项目名为ListViewTest.

ListView的简单使用

修改布局文件,修改后代码如下:

view source print ? 01. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 02. xmlns:tools="http://schemas.android.com/tools" 03. android:layout_width="match_parent" 04. android:layout_height="match_parent" 05. > 06. 07. <ListView 08. android:id="@+id/list_view" 09. android:layout_width="match_parent" 10. android:layout_height="match_parent" 11. ></ListView> 12. 13. </LinearLayout>

修改MainActivity的代码:

view source print ? 01. packagecom.wj.listviewtest; 02. 03. importandroid.app.Activity; 04. importandroid.os.Bundle; 05. importandroid.view.Menu; 06. importandroid.widget.ArrayAdapter; 07. importandroid.widget.ListView; 08. 09. publicclassMainActivityextendsActivity { 10. 11. privateString [] data={"apple","banana","orange", 12. "watermelon","pear","grape","pineapple","strawberry", 13. "cherry","mango"}; 14. @Override 15. protectedvoidonCreate(Bundle savedInstanceState) { 16. super.onCreate(savedInstanceState); 17. setContentView(R.layout.activity_main); 18. //创建适配器 19. ArrayAdapter<String> adapter=newArrayAdapter<String>( 20. MainActivity.this,android.R.layout.simple_list_item_1, 21. data); 22. ListView listView=(ListView) findViewById(R.id.list_view); 23. listView.setAdapter(adapter); 24. } 25. 26. @Override 27. publicbooleanonCreateOptionsMenu(Menu menu) { 28. // Inflate the menu; this adds items to the action bar if it is present. 29. getMenuInflater().inflate(R.menu.main, menu); 30. returntrue; 31. } 32. 33. }

运行程序结果如下:

ListView是用于显示大量数据的,这些数据我们可以事先准备好,也可以从网上或者数据中中读取。

android.R.layout.simple_list_item_1是作为ListView子项布局的id,这是android内置的布局文件里面只有一个TextView,可用于简单地显示一段文本。

2.定制ListView的界面

首先准备一组图片,分别对应上面提供的水果。

接着定义一个实体类,作为ListView适配器的适配类型,新建Fruit类,代码如下:

view source print ? 01. packagecom.wj.listviewtest; 02. 03. publicclassFruit { 04. 05. privateString name;//水果名 06. privateintimageId;//水果图片的资源id 07. 08. //无参构造函数 09. publicFruit(){} 10. //有参构造函数 11. publicFruit(String name,intimageId){ 12. this.name=name; 13. this.imageId=imageId; 14. } 15. 16. publicString getName() { 17. returnname; 18. } 19. publicvoidsetName(String name) { 20. this.name = name; 21. } 22. publicintgetImageId() { 23. returnimageId; 24. } 25. publicvoidsetImageId(intimageId) { 26. this.imageId = imageId; 27. } 28. 29. }
Fruit类中只有2个字段,name表示水果的名字,imageId表示水果对应图片的资源id,然后需要为ListView的子项指定一个我们自定义的布局,在layout目录下面新建fruit_item.xml代码如下:

view source print ? 01. <?xml version="1.0"encoding="utf-8"?> 02. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 03. android:layout_width="match_parent" 04. android:layout_height="match_parent" 05. > 06. <ImageView 07. android:id="@+id/fruit_image" 08. android:layout_width="wrap_content" 09. android:layout_height="wrap_content" 10. /> 11. 12. <TextView 13. android:id="@+id/fruit_name" 14. android:layout_width="wrap_content" 15. android:layout_height="wrap_content" 16. android:layout_gravity="center" 17. android:layout_marginLeft="10dip" 18. /> 19. 20. </LinearLayout>

这个布局中我们定义了一个ImageView用于显示水果的图片,又定义了一个TextView用于显示水果的名称。

接着我们要创建一个自定义的适配器,这个适配器继承自ArrayAdapter,并将泛型指定为Fruit。新建一个类FruitAdapter代码如下:

view source print ? 01. packagecom.wj.listviewtest; 02. 03. importjava.util.List; 04. 05. importandroid.content.Context; 06. importandroid.view.LayoutInflater; 07. importandroid.view.View; 08. importandroid.view.ViewGroup; 09. importandroid.widget.ArrayAdapter; 10. importandroid.widget.ImageView; 11. importandroid.widget.TextView; 12. 13. publicclassFruitAdapterextendsArrayAdapter<Fruit> { 14. 15. privateintresourceId; 16. publicFruitAdapter(Context context,inttextViewResourceId, 17. List<Fruit> objects) { 18. super(context, textViewResourceId, objects); 19. // TODO Auto-generated constructor stub 20. /* 21. * 重写了父类的构造函数,用于将上下文,ListView子项布局的id和数据都传进来。 22. * */ 23. resourceId=textViewResourceId; 24. } 25. @Override 26. publicView getView(intposition, View convertView, ViewGroup parent) { 27. // TODO Auto-generated method stub 28. //return super.getView(position, convertView, parent); 29. /* 30. * 重写getView方法,这个方法在每个子项被滚动到屏幕内的时候会被调用,在getView方法中 31. * ,首先通过getItem方法得到当前项的Fruit实例,然后使用LayoutInflater来为这个子项加载 32. * 我们传入的布局,接着调用View的findViewById方法分别获取到ImageView和TextView的实例, 33. * 并分别调用他们的setImageResource和setText方法来设置显示的图片和文字,最后返回布局 34. * */ 35. Fruit fruit=getItem(position);//获取当前项的Fruit实例 36. //初始话ListView的子项布局 37. View view=LayoutInflater.from(getContext()).inflate(resourceId,null); 38. ImageView fruitImage=(ImageView) view.findViewById(R.id.fruit_image); 39. TextView fruitName=(TextView) view.findViewById(R.id.fruit_name); 40. fruitImage.setImageResource(fruit.getImageId()); 41. fruitName.setText(fruit.getName()); 42. returnview; 43. } 44. 45. 46. 47. 48. }
修改MainActivity的代码如下:

view source print ? 01. packagecom.wj.listviewtest; 02. 03. importjava.util.ArrayList; 04. importjava.util.List; 05. 06. importandroid.app.Activity; 07. importandroid.os.Bundle; 08. importandroid.view.Menu; 09. importandroid.widget.ArrayAdapter; 10. importandroid.widget.ListView; 11. 12. publicclassMainActivityextendsActivity { 13. 14. /*private String [] data={"apple","banana","orange", 15. "watermelon","pear","grape","pineapple","strawberry", 16. "cherry","mango"};*/ 17. privateList<Fruit> fruitList=newArrayList<Fruit>(); 18. @Override 19. protectedvoidonCreate(Bundle savedInstanceState) { 20. super.onCreate(savedInstanceState); 21. setContentView(R.layout.activity_main); 22. /*//创建适配器 23. ArrayAdapter<String> adapter=new ArrayAdapter<String>( 24. MainActivity.this,android.R.layout.simple_list_item_1, 25. data); 26. ListView listView=(ListView) findViewById(R.id.list_view); 27. listView.setAdapter(adapter);*/ 28. initFruits();//初始化水果 29. FruitAdapter adapter=newFruitAdapter(MainActivity.this, 30. R.layout.fruit_item, fruitList); 31. ListView listView=(ListView) findViewById(R.id.list_view); 32. //设置适配器 33. listView.setAdapter(adapter); 34. 35. } 36. 37. @Override 38. publicbooleanonCreateOptionsMenu(Menu menu) { 39. // Inflate the menu; this adds items to the action bar if it is present. 40. getMenuInflater().inflate(R.menu.main, menu); 41. returntrue; 42. } 43. 44. publicvoidinitFruits(){ 45. Fruit apple=newFruit("apple",R.drawable.apple_pic); 46. fruitList.add(apple); 47. Fruit banana=newFruit("banana",R.drawable.banana_pic); 48. fruitList.add(banana); 49. Fruit orange=newFruit("orange",R.drawable.orange_pic); 50. fruitList.add(orange); 51. Fruit watermelon=newFruit("watermelon",R.drawable.watermelon_pic); 52. fruitList.add(watermelon); 53. Fruit pear=newFruit("pear",R.drawable.pear_pic); 54. fruitList.add(pear); 55. Fruit grape=newFruit("grape",R.drawable.grape_pic); 56. fruitList.add(grape); 57. Fruit pineapple=newFruit("pineapple",R.drawable.pineapple_pic); 58. fruitList.add(pineapple); 59. Fruit strawberry=newFruit("strawberry",R.drawable.strawberry_pic); 60. fruitList.add(strawberry); 61. Fruit cherry=newFruit("cherry",R.drawable.cherry_pic); 62. fruitList.add(cherry); 63. Fruit mango=newFruit("mango",R.drawable.mango_pic); 64. fruitList.add(mango); 65. } 66. 67. 68. 69. }
运行程序,结果如下:

这是一个简单的界面,不过更加复杂的界面也可以通过修改fruit_item.xml文件来实现更加复杂的ListView。

下面我们来提示下ListView的运行效率。

目前我们的ListView的运行效率是很低的,因为在FruitAdapter的getView方法中每次都要将布局重写加载了一遍,当ListView快速滚动的时候这就会成为性能的瓶颈。仔细观察,getView方法中还有一个convertView参数,这个参数用于将之前加载好的布局进行缓存,以便之后可以进行重用,修改FruitAdapter中的代码,带入如下所示:

view source print ? 01. @Override 02. publicView getView(intposition, View convertView, ViewGroup parent) { 03. // TODO Auto-generated method stub 04. //return super.getView(position, convertView, parent); 05. /* 06. * 重写getView方法,这个方法在每个子项被滚动到屏幕内的时候会被调用,在getView方法中 07. * ,首先通过getItem方法得到当前项的Fruit实例,然后使用LayoutInflater来为这个子项加载 08. * 我们传入的布局,接着调用View的findViewById方法分别获取到ImageView和TextView的实例, 09. * 并分别调用他们的setImageResource和setText方法来设置显示的图片和文字,最后返回布局 10. * */ 11. Fruit fruit=getItem(position);//获取当前项的Fruit实例 12. View view; 13. /* 14. * 在getView()方法中进行判断,如果convertView为空,则使用LayoutInflater去加载布局, 15. * 如果不为空,则直接对convertView进行重用。这样可以大大提升ListView的效率,在快速滚动的时候 16. * 也可以表现更好的性能。 17. * */ 18. if(convertView==null){ 19. //初始话ListView的子项布局 20. view=LayoutInflater.from(getContext()).inflate(resourceId,null); 21. }else{ 22. view=convertView; 23. } 24. /*//初始话ListView的子项布局 25. View view=LayoutInflater.from(getContext()).inflate(resourceId, null);*/ 26. ImageView fruitImage=(ImageView) view.findViewById(R.id.fruit_image); 27. TextView fruitName=(TextView) view.findViewById(R.id.fruit_name); 28. fruitImage.setImageResource(fruit.getImageId()); 29. fruitName.setText(fruit.getName()); 30. returnview; 31. }
上面的代码进行了部分的优化,虽然现在已经不用在重复的去加载布局了,但是每次在getView方法中还是会调用View的view.findViewById()方法来获取一次控件的实例。我们可以借助一个ViewHolder来对这部分性能进行优化,修改FruitAdapter中的代码,如下所示:

view source print ? 01. packagecom.wj.listviewtest; 02. 03. importjava.util.List; 04. 05. importandroid.content.Context; 06. importandroid.view.LayoutInflater; 07. importandroid.view.View; 08. importandroid.view.ViewGroup; 09. importandroid.widget.ArrayAdapter; 10. importandroid.widget.ImageView; 11. importandroid.widget.TextView; 12. 13. publicclassFruitAdapterextendsArrayAdapter<Fruit> { 14. 15. privateintresourceId; 16. publicFruitAdapter(Context context,inttextViewResourceId, 17. List<Fruit> objects) { 18. super(context, textViewResourceId, objects); 19. // TODO Auto-generated constructor stub 20. /* 21. * 重写了父类的构造函数,用于将上下文,ListView子项布局的id和数据都传进来。 22. * */ 23. resourceId=textViewResourceId; 24. } 25. @Override 26. publicView getView(intposition, View convertView, ViewGroup parent) { 27. // TODO Auto-generated method stub 28. //return super.getView(position, convertView, parent); 29. /* 30. * 重写getView方法,这个方法在每个子项被滚动到屏幕内的时候会被调用,在getView方法中 31. * ,首先通过getItem方法得到当前项的Fruit实例,然后使用LayoutInflater来为这个子项加载 32. * 我们传入的布局,接着调用View的findViewById方法分别获取到ImageView和TextView的实例, 33. * 并分别调用他们的setImageResource和setText方法来设置显示的图片和文字,最后返回布局 34. * */ 35. Fruit fruit=getItem(position);//获取当前项的Fruit实例 36. View view; 37. ViewHolder viewHolder; 38. /* 39. * 在getView()方法中进行判断,如果convertView为空,则使用LayoutInflater去加载布局, 40. * 如果不为空,则直接对convertView进行重用。这样可以大大提升ListView的效率,在快速滚动的时候 41. * 也可以表现更好的性能。 42. * */ 43. if(convertView==null){ 44. //初始话ListView的子项布局 45. view=LayoutInflater.from(getContext()).inflate(resourceId,null); 46. viewHolder=newViewHolder(); 47. viewHolder.fruitImage=(ImageView) view.findViewById(R.id.fruit_image); 48. viewHolder.fruitName=(TextView) view.findViewById(R.id.fruit_name); 49. view.setTag(viewHolder);//将ViewHolder存储在View中 50. }else{ 51. view=convertView; 52. viewHolder=(ViewHolder) view.getTag();//重新获取ViewHolder 53. } 54. /*//初始话ListView的子项布局 55. View view=LayoutInflater.from(getContext()).inflate(resourceId, null);*/ 56. /*ImageView fruitImage=(ImageView) view.findViewById(R.id.fruit_image); 57. TextView fruitName=(TextView) view.findViewById(R.id.fruit_name);*/ 58. viewHolder.fruitImage.setImageResource(fruit.getImageId()); 59. viewHolder.fruitName.setText(fruit.getName()); 60. returnview; 61. } 62. 63. 64. classViewHolder{ 65. ImageView fruitImage; 66. TextView fruitName; 67. } 68. 69. }
通过上面两步优化后,ListView的运行效率已经不错了。

ListView的点击事件

修改代码如下:

view source print ? 01. packagecom.wj.listviewtest; 02. 03. importjava.util.ArrayList; 04. importjava.util.List; 05. 06. importandroid.app.Activity; 07. importandroid.os.Bundle; 08. importandroid.view.Menu; 09. importandroid.view.View; 10. importandroid.widget.AdapterView; 11. importandroid.widget.AdapterView.OnItemClickListener; 12. importandroid.widget.ArrayAdapter; 13. importandroid.widget.ListView; 14. importandroid.widget.Toast; 15. 16. publicclassMainActivityextendsActivity { 17. 18. /*private String [] data={"apple","banana","orange", 19. "watermelon","pear","grape","pineapple","strawberry", 20. "cherry","mango"};*/ 21. privateList<Fruit> fruitList=newArrayList<Fruit>(); 22. @Override 23. protectedvoidonCreate(Bundle savedInstanceState) { 24. super.onCreate(savedInstanceState); 25. setContentView(R.layout.activity_main); 26. /*//创建适配器 27. ArrayAdapter<String> adapter=new ArrayAdapter<String>( 28. MainActivity.this,android.R.layout.simple_list_item_1, 29. data); 30. ListView listView=(ListView) findViewById(R.id.list_view); 31. listView.setAdapter(adapter);*/ 32. initFruits();//初始化水果 33. FruitAdapter adapter=newFruitAdapter(MainActivity.this, 34. R.layout.fruit_item, fruitList); 35. ListView listView=(ListView) findViewById(R.id.list_view); 36. //设置适配器 37. listView.setAdapter(adapter); 38. /* 39. * setOnItemClickListener()方法来为ListView注册一个监听器,当用户点击了ListView 40. * 中的任何一个子项时就会回调nItemClick()方法,在这个方法中可以通过position参数判断出用户点击 41. * 的是哪一个子项,然后获取相应的水果,并通过Toast将水果的名字显示出来。 42. * */ 43. listView.setOnItemClickListener(newOnItemClickListener(){ 44. 45. @Override 46. publicvoidonItemClick(AdapterView<?> parent, View view,intposition, 47. longid) { 48. // TODO Auto-generated method stub 49. Fruit fruit=fruitList.get(position); 50. Toast.makeText(MainActivity.this, 51. fruit.getName(), Toast.LENGTH_SHORT).show(); 52. 53. } 54. 55. }); 56. } 57. 58. @Override 59. publicbooleanonCreateOptionsMenu(Menu menu) { 60. // Inflate the menu; this adds items to the action bar if it is present. 61. getMenuInflater().inflate(R.menu.main, menu); 62. returntrue; 63. } 64. 65. publicvoidinitFruits(){ 66. Fruit apple=newFruit("apple",R.drawable.apple_pic); 67. fruitList.add(apple); 68. Fruit banana=newFruit("banana",R.drawable.banana_pic); 69. fruitList.add(banana); 70. Fruit orange=newFruit("orange",R.drawable.orange_pic); 71. fruitList.add(orange); 72. Fruit watermelon=newFruit("watermelon",R.drawable.watermelon_pic); 73. fruitList.add(watermelon); 74. Fruit pear=newFruit("pear",R.drawable.pear_pic); 75. fruitList.add(pear); 76. Fruit grape=newFruit("grape",R.drawable.grape_pic); 77. fruitList.add(grape); 78. Fruit pineapple=newFruit("pineapple",R.drawable.pineapple_pic); 79. fruitList.add(pineapple); 80. Fruit strawberry=newFruit("strawberry",R.drawable.strawberry_pic); 81. fruitList.add(strawberry); 82. Fruit cherry=newFruit("cherry",R.drawable.cherry_pic); 83. fruitList.add(cherry); 84. Fruit mango=newFruit("mango",R.drawable.mango_pic); 85. fruitList.add(mango); 86. } 87. 88. 89. 90. }

运行结果如下;

好了ListView的使用就总结到这里了。

单位和尺寸

px是像素的意思,即屏幕中可以显示的最小单位,我们应用里任何可见的东西都是由一个个像素点组成的。

pt是磅数的意思,1磅等于1/72英寸,一般pt都会作为字体的单位来使用。

dp是密度无关的像素的意思,也被称作为dip,和px相比,它在不同密度的屏幕中的显示比例保持一致。

sp是可伸缩像素的意思,它采用了和dp同样的设计理念,解决了文字大小的适配问题。

android中的密度就是屏幕每英寸所包含的像素数,通常以dpi为单位。

根据android的规定,在160dpi的屏幕上,1dp等于1px,而在320dpi的屏幕上,1dp就等于2px。因此,使用dp来指定控件的宽和高,就可以保证控件在不同密度的屏幕中的显示比例保存一致。所以dp可以理解为显示比例(像素除以英寸)

在编写android程序的时候,尽量将控件或布局的大小指定成match_parent或wrap_content,如果必须要指定一个固定的值,则使用dp来作为单位,指定文字的大小的时候使用sp。

更多相关文章

  1. Android(安卓)TestView获取每一行文字的方法
  2. 挂断电话的实现(即类似于电话号码黑名单)
  3. 【资源】Android(安卓)Developer网站无法访问问题的解决之道
  4. android 自定义下拉刷新上拉加载控件(SwipeRefreshLayout + recyc
  5. ContentProvider实现数据共享1
  6. Android(安卓)GPIO 控制方案
  7. Android8.0 PackageManagerService相关 -- APK安装和install 的
  8. Android(安卓)输入法框弹出 背景上移或压缩问题
  9. ViewPager和ViewFlipperV冲突

随机推荐

  1. 通过Intent传递一些二进制数据的方法有哪
  2. Android编程心得-解决Eclipse导入工程出
  3. Android之Menu菜单
  4. android activity/service开机后自动运行
  5. Android(安卓)Studio导入Github项目时Plu
  6. Android(安卓)蓝牙 资料(转)
  7. Android(安卓)FrameWork——Touch事件派
  8. [Android] Dagger2 入门 1
  9. 笔记-系统源码常用的Content Provider
  10. android JNI NDK