Android学习 (十二) 常用布局之不简单的ListView

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;
    }


}

总结:
没遇到什么大的问题,主要就是要注意图片的格式,还有就是需要一步步把每一步的意义搞清楚。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值