Android ListView 代码1

ListView效果

ListView允许用户通过手机上下滑动的方式将屏幕外的数据滚动到屏幕内,同时屏幕上的数据则会滚动出屏幕。

一、ListView的简单用法

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        ></ListView>
 </LinearLayout>

MainActivity

public class MainActivity extends Activity {
    private String[] datas={"Apple" ,"Banana","Orange","Watermelon","Pear","Grape","Pineapple","Strawberry","Cherry","Mango","Apple"       ,"Banana","Orange","Watermelon","Pear","Grape","Pineapple","Strawberry","Cherry","Mango"};
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ArrayAdapter<String>adpter=new ArrayAdapter<String>(MainActivity.this,android.R.layout.simple_list_item_1,datas);//当前上下文、ListView子项布局的Id,要适配的数据
        //其中android.R.layout.simple_list_item_1是Android内置的布局文件,里面只有一个TextView可用于简单地显示一段文本。
        ListView listview=(ListView)findViewById(R.id.list_view);
        listview.setAdapter(fruitAdapter);
    }
}

ListView用来展示大量数据,我们先将数据准备好,比如这里的datas数组。不过数据无法直接传递给ListView,需要借助适配器来完成。ArrayAdapter就是Android提供的一个适配器的实现类,它可以通过泛型来指定要适配的数据类型,然后在构造函数中把要适配的数据传入。

二、定制ListView的界面

目标

实现水果名称旁边都有一个图样

步骤

1.定义一个实体类作为ListView适配器的适配对象。

Ftuit类

public class Fruit {
    private String name;
    private int imageId;
    public Fruit(String name,int imageId){
        this.name=name;
        this.imageId=imageId;
    }
    public int getImageId() {
        return imageId;
    }
    public String getName() {
        return name;
    }
}

2.为ListView的子项指定我们的自定义布局

fruit_item.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <ImageView
        android:id="@+id/fruit_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/fruit_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="10dp"/>
</LinearLayout>

3.创建自定义适配器,这个适配器继承自ArrayAdapter,并将泛型指定为Fruit类

FruitAdapter类

public class FruitAdapter extends ArrayAdapter<Fruit> {
    private int resourceId;
    //重写父类构造方法,用于将上下文、ListView子项布局的id和数据传递进来
    public FruitAdapter(Context context,int textViewResourceId,List<Fruit> objects){
        super(context,textViewResourceId,objects);
        resourceId=textViewResourceId;
    }
    //这个方法在每个子项被滚动到屏幕内时会被调用
    @Override
    public View getView(int position,  View convertView, ViewGroup parent) {
        Fruit fruit=getItem(position);//获取当前项的fruit实例
        View view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);//使用LayoutInflater来为这个子项加载我们传入的布局
        ImageView fruitImage=(ImageView)view.findViewById(R.id.fruit_image);
        TextView fruitname=(TextView)view.findViewById(R.id.fruit_name);
        fruitImage.setImageResource(fruit.getImageId());
        fruitname.setText(fruit.getName());
        return view;
    }
}

LayoutInflater的inflate()方法接收三个参数,第三个指定成false表示我们在父布局中声明的layout属性生效,但不会为这个View添加父布局,因为View一旦有了父布局之后,它就不能再添加到ListView中了。

4.调用View的findViewById()获取ImageView和TextView的实例,设置图片和文字

MainActivity

public class MainActivity extends Activity {

    private List<Fruit>fruitList=new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initFruits();//初始化水果数据
        FruitAdapter fruitAdapter=new FruitAdapter(MainActivity.this,R.layout.fruit_item,fruitList);
        ListView listview=(ListView)findViewById(R.id.list_view);
        listview.setAdapter(fruitAdapter);
    }
    private void initFruits(){
        for(int i=0;i<2;i++){
            Fruit apple=new Fruit("Apple",R.drawable.apple);
            fruitList.add(apple);
            Fruit Banana=new Fruit("Banana",R.drawable.banana);
            fruitList.add(Banana);
            Fruit Orange=new Fruit("Orange",R.drawable.orange);
            fruitList.add(Orange);
            Fruit Watermelon=new Fruit("Watermelon",R.drawable.watermelon);
            fruitList.add(Watermelon);
            Fruit Pear=new Fruit("Pear",R.drawable.pear);
            fruitList.add(Pear);
            Fruit Grape=new Fruit("Grape",R.drawable.grape);
            fruitList.add(Grape);
            Fruit Pineapple=new Fruit("Pineapple",R.drawable.pineapple);
            fruitList.add(Pineapple);
            Fruit Strawberry=new Fruit("Strawberry",R.drawable.strawberry);
            fruitList.add(Strawberry);
            Fruit Cherry=new Fruit("Cherry",R.drawable.cherry);
            fruitList.add(Cherry);
            Fruit Mango=new Fruit("Mango",R.drawable.mango);
            fruitList.add(Mango);

        }
    }
}

运行时,先创建FruitAdapter适配器,将上下文和子项ID(R.layout.fruit_item)和数据传入,当每个子项被滑动到屏幕内时,调用getView()方法,通过LayoutInflater获得View,再通过view的findViewById()将水果的图片和名称传入。
接下来获得activity_main.xml中的ListView,将创建好的适配器传入。

三、ListView的性能提升

ListView效率很低,在FruitAdapter的getView()方法中,每次都将布局重新加载一遍,当ListView快速滚动时,这就会成为性能的瓶颈
仔细观察会发现,getView()中有一个convertView参数,这个参数用于缓存之前加载好的布局,以便之后的重用。

修改FruitAdapter中的代码1:使用convertView加载缓存布局

public class FruitAdapter extends ArrayAdapter<Fruit> {
    ...
    @Override
    public View getView(int position,  View convertView, ViewGroup parent) {
        Fruit fruit=getItem(position);//获取当前项的fruit实例
        View view;
        if(convertView==null){
            view=LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
        }else{
            view=convertView;
        }
        ImageView fruitImage=(ImageView)view.findViewById(R.id.fruit_image);
        TextView fruitname=(TextView)view.findViewById(R.id.fruit_name);
        fruitImage.setImageResource(fruit.getImageId());
        fruitname.setText(fruit.getName());
        return view;
    }
}

修改FruitAdapter中的代码2:使用ViewHolder类保存控件(通过view的setTag()方法,将ViewHolder对象存储在View中)

public class FruitAdapter extends ArrayAdapter<Fruit> {
   ...
    @Override
    public View getView(int position,  View convertView, ViewGroup parent) {
        Fruit fruit=getItem(position);//获取当前项的fruit实例
        //View view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
        View view;
        ViewHolder viewHolder;
        if(convertView==null){
            view=LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
            viewHolder=new ViewHolder();
            viewHolder.fruitImage=view.findViewById(R.id.fruit_image);
            viewHolder.fruitname=view.findViewById(R.id.fruit_name);
            view.setTag(viewHolder);//将viewHolder存储在View中
        }else{
            view=convertView;
            viewHolder=(ViewHolder)view.getTag();//重新获取ViewHolder
        } 
        viewHolder.fruitImage.setImageResource(fruit.getImageId());
        viewHolder.fruitname.setText(fruit.getName());
        return view;
    }
    class ViewHolder{
        ImageView fruitImage;
        TextView fruitname;
    }
}

四、ListView的点击事件

修改MainActivity中的代码

public class MainActivity extends Activity {

    private List<Fruit>fruitList=new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ActionBar actionBar=getActionBar();
        if(actionBar!=null){
            actionBar.hide();
        }
        initFruits();//初始化水果数据
        FruitAdapter fruitAdapter=new FruitAdapter(MainActivity.this,R.layout.fruit_item,fruitList);
        ListView listview=(ListView)findViewById(R.id.list_view);
        listview.setAdapter(fruitAdapter);

         listview.setOnItemClickListener(new AdapterView.OnItemClickListener(){
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int positon, long id) {
                Fruit fruit=fruitList.get(positon);
                Toast.makeText(MainActivity.this, fruit.getName(), Toast.LENGTH_SHORT).show();
            }
        });
    }
    private void initFruits(){
        for(int i=0;i<2;i++){
            Fruit apple=new Fruit("Apple",R.drawable.apple);
            fruitList.add(apple);
            Fruit Banana=new Fruit("Banana",R.drawable.banana);
            fruitList.add(Banana);
            Fruit Orange=new Fruit("Orange",R.drawable.orange);
            fruitList.add(Orange);
            Fruit Watermelon=new Fruit("Watermelon",R.drawable.watermelon);
            fruitList.add(Watermelon);
            Fruit Pear=new Fruit("Pear",R.drawable.pear);
            fruitList.add(Pear);
            Fruit Grape=new Fruit("Grape",R.drawable.grape);
            fruitList.add(Grape);
            Fruit Pineapple=new Fruit("Pineapple",R.drawable.pineapple);
            fruitList.add(Pineapple);
            Fruit Strawberry=new Fruit("Strawberry",R.drawable.strawberry);
            fruitList.add(Strawberry);
            Fruit Cherry=new Fruit("Cherry",R.drawable.cherry);
            fruitList.add(Cherry);
            Fruit Mango=new Fruit("Mango",R.drawable.mango);
            fruitList.add(Mango);

        }
    }
}

我们使用setOnItemClickListenser()方法为ListView注册监听器,当点击ListView任何一个子项时,就会回调onItemClick()方法。position参数可以判断用户点击的是哪一个子项,对应着数组的下标,然后就能获取到相应的数据。

posted @ 2020-04-28 18:17  小帆敲代码  阅读(327)  评论(0编辑  收藏  举报