1.ListView 的最基本应用
ListView是安卓里面相当长用的控件,可以实现数据在屏幕上划入和划出,显示更多的信息。
创建方式和其他控件也是一样的,直接在布局文件里面:
<ListView
android:id="@+id/list_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</ListView>
数据是不能直接传送进ListView的,需要一个适配器Adapter来作为一个载体,相当于是一个沟通的桥梁。
这是我理解的过程:
比如,我想在ListView中添加一组字符串内容:
public class MainActivity extends Activity {
//定义一个字符串类型的数组,把水果的信息存放在数组里面
private String[] data = {"Apple","Banana","Orange","Watermelon","Pear","Grape","Pineapple","Strawberry","Cheery","Mango"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
//新建一个String类型的ArrayAdapter,有三个参数,分别是当前上下文
//ListView子项布局的id,imple_expandable_list_item_1是安卓内置的一个布局文件,只有TextView控件,显示文字,最后data是传入适配器的数据
ArrayAdapter <String> adapter = new ArrayAdapter<String>(MainActivity.this,android.R.layout.simple_expandable_list_item_1,data);
//找到布局文件里面定义的listView
ListView listView = (ListView)findViewById(R.id.list_view);
//把适配器里面的数据传入listView
listView.setAdapter(adapter);
}
}
2.ListView制作自定义布局
注意:
在drainable中加入图片时,我总是遇到报错,最后换成png格式的就没问题了。我不是很清楚是不是必须使用png格式,但这个没错。
这里贴上我自己画的思路图:
1)自定义一个实体类,作为ListView适配器的适配类型,这里适配器的类型就会是Fruit.
package com.example.gucheng.listviewtest;
public class Fruit {
private String name;
private int imageId;
//构造函数
public Fruit(String name,int imageId) {
this.name = name;
this.imageId = imageId;
}
//name表示水果的名字
public String getName(){
return name;
}
//imageId表示对应的水果图片
public int getImageId(){
return imageId;
}
}
2)为ListView指定一个我们自定义的布局,用来显示ListView子项的布局(每一栏就是一个子项)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
//这里排列为水平排列方向
android:orientation="horizontal"
android:background="#dcdcdc">
//表示一个子项横排有一张图片和一段文字
<ImageView
android:id="@+id/fruit_image"
//可以自定义宽度和高度
android:layout_width="80dp"
android:layout_height="80dp" />
<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="10dp"/>
</LinearLayout>
这个就是自定义子项的效果:
3)创建一个自定义类型的适配器,注意继承的父类,这里继承自ArrayAdapter,里面各个步骤的功能已经写在注释里面了。
package com.example.gucheng.listviewtest;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
import static android.R.attr.resource;
/**
* Created by gucheng on 16/11/15.
*/
public class FruitAdapter extends ArrayAdapter<Fruit> {
private int resourceId;
//FruitAdapter的构造函数,当前上下文,子项布局的ID,数据
//类型和名字是因为在main_activity.java的定义中,有一个List<Fruit> fruitList用来存储水果信息
//这里参数中有一个List <Fruit> objects,定义的一个Fruit类型的List,名字叫objects,就是用来传入水果的信息
public FruitAdapter(Context context, int textViewResourceId, List<Fruit> objects) {
super(context, textViewResourceId,objects);
resourceId = textViewResourceId;
}
@Override
//getView在每个子项滚到屏幕的时候调用
public View getView(int position, View contentView, ViewGroup parent){
//先通过getItem()获取当前项的Fruit实例,就是获得当前滚入屏幕的子项,ListView中一行信息就是一个子项
Fruit fruit = getItem(position);
//为当前的滚入屏幕的子项加载我们自定义的布局
View view = LayoutInflater.from(getContext()).inflate(resourceId,null);
//通过id找到自定义布局文件里面的imageView和textView
ImageView fruitIamge = (ImageView) view.findViewById(R.id.fruit_image);
TextView fruitName = (TextView)view.findViewById(R.id.fruit_name);
//把当前实例的信息加载到listView中
fruitIamge.setImageResource(fruit.getImageId());
fruitName.setText(fruit.getName());
// 返回view
return view;
}
}
4)修改MainActivity.java代码,实现功能,图片是提前放在drawable文件夹中的,格式要求是png。
public class MainActivity extends AppCompatActivity{
//被注释的这一段是单纯的显示文字ListView的
// //定义一个字符串类型的数组,把水果的信息存放在数组里面
// private String[] data = {"Apple","Banana","Orange","Watermelon","Pear","Grape","Pineapple","Strawberry","Cheery","Mango"};
//
// @Override
// protected void onCreate(Bundle savedInstanceState) {
// super.onCreate(savedInstanceState);
// setContentView(R.layout.main_activity);
//
// //新建一个String类型的ArrayAdapter,有三个参数,分别是当前上下文
// //ListView子项布局的id,imple_expandable_list_item_1是安卓内置的一个布局文件,只有TextView控件,显示文字,最后data是传入适配器的数据
// ArrayAdapter <String> adapter = new ArrayAdapter<String>(MainActivity.this,android.R.layout.simple_expandable_list_item_1,data);
//
// //找到布局文件里面定义的listView
// ListView listView = (ListView)findViewById(R.id.list_view);
// //把适配器里面的数据传入listView
// listView.setAdapter(adapter);
// }
//创建一个List实例化对象来存储水果信息
private List<Fruit> fruitList = new ArrayList<Fruit>();
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
//初始化水果信息
initFruit();
FruitAdapter adapter = new FruitAdapter(MainActivity.this,R.layout.fruit_item,fruitList);
ListView listView = (ListView)findViewById(R.id.list_view);
listView.setAdapter(adapter);
}
//给Fruit类的构造函数初始化,并且把信息存到fruitList中
private void initFruit(){
//把水果名字和图片放到Fruit的apple实例中,在存放到fruitList中
Fruit banana = new Fruit("Banana",R.drawable.boyd1);
fruitList.add(banana);
Fruit cherry = new Fruit("Cherry",R.drawable.boyd2);
fruitList.add(cherry);
Fruit grape = new Fruit("Grape",R.drawable.boyd3);
fruitList.add(grape);
Fruit mango = new Fruit("Mango",R.drawable.boyd4);
fruitList.add(mango);
Fruit orange = new Fruit("Orange",R.drawable.boyd5);
fruitList.add(orange);
Fruit pinapple = new Fruit("pinapple",R.drawable.girld1);
fruitList.add(pinapple);
Fruit strwberry = new Fruit("Strwberry",R.drawable.girld2);
fruitList.add(strwberry);
Fruit watermelon = new Fruit("Watermelon",R.drawable.girld3);
fruitList.add(watermelon);
Fruit girl4 = new Fruit("Girl4",R.drawable.girld4);
fruitList.add(girl4);
Fruit girl5 = new Fruit("Girl5",R.drawable.girld5);
fruitList.add(girl5);
}
}
这是最后的效果:
3.ListView运行效率的优化
1)利用convertView来优化子项布局的多次加载
View view;//新建一个View的对象view
if(contentView == null){
//如果convertView为空,则加载这个布局
view = LayoutInflater.from(getContext()).inflate(resourceId,null);
}
else{
view = contentView;
}
2)自己新建一个内置类ViewHolder,把控件的实例存储在缓存中,减少控件加载的次数
@Override
public View getView(int position, View contentView, ViewGroup parent){
//先通过getItem()获取当前项的Fruit实例,就是获得当前滚入屏幕的子项,ListView中一行信息就是一个子项
Fruit fruit = getItem(position);
//现在对代码进行优化
//通过convertView把加载过的布局放在缓存里,提高运行效率
View view;//新建一个View的对象view
ViewHolder viewHolder;
//否则,直接对convertView进行重用
if(contentView == null){
//如果convertView为空,则加载这个布局
view = LayoutInflater.from(getContext()).inflate(resourceId,null);
viewHolder = new ViewHolder();
viewHolder.fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
viewHolder.fruitName = (TextView) view.findViewById(R.id.fruit_name);
//将viewHolder存储在view中
view.setTag(viewHolder);
}
else{
view = contentView;
//重新获取viewHolder
viewHolder = (ViewHolder)view.getTag();
//fruit是之前Fruit实例化的一个对象,getImageId是Fruit类里面的一个方法
}
viewHolder.fruitImage.setImageResource(fruit.getImageId());
viewHolder.fruitName.setText(fruit.getName());
return view;
}
//新建的内置class ViewHolder
class ViewHolder{
ImageView fruitImage;
TextView fruitName;
}
}
总结:
没遇到什么大的问题,主要就是要注意图片的格式,还有就是需要一步步把每一步的意义搞清楚。