Android控件之ListView

Android控件-----ListView

1.ListView的用法

ListView是安卓最常用和最难用的控件之一,它允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内,同时屏幕上原有的数据则会滚动出屏幕。比如查看QQ聊天记录,阅读新闻等等。

1.1.ListView的简单用法

ListView是用于展示大量数据的,这些数据可以直接定义在数组中,可以是从网上下载的,也可以是从数据库读取的。但是,数组中的数据不能直接传递给ListView,需要借助适配器来完成。在这里我们使用ArrayAdapter,它可以通过泛型来指定要适配的数据类型,然后在构造函数中把要适配的数据传入。

(1)首先建立一个ListViewTest项目,选择Empty Activity选项。

在布局activity_main.xml中加入ListView控件,指定id,设置宽度和高度,这里都设置为match_parent。

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

(2)在MainActivity中定义数组,构建适配器。

指定适配器ArrayAdapter的泛型为,在其构造函数中传入当前上下文,ListView子项布局的id,以及要适配的数据。注意,这里我们使用的是android.R.layout.simple_list_item_1作为ListView子项布局的id,这是Android内置的布局文件,里面只有一个TextView,用于简单的显示一段文本。最后调用ListView的setAdapter()方法,将构造好的适配器对象传递进去,建立ListView和数据之间的关联。

 private String[] arr = {"鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1,arr);
        ListView listView = (ListView) findViewById(R.id.list_view);
        listView.setAdapter(adapter);
    }

在这里插入图片描述

1.2.自定义ListView

(1)定义类作为ListView适配器的适配类型

新建类中定义了两个字段,name表示十二生肖的名字,imageId表示十二生肖对应图片的资源id。

public class Zodiac {
   private String name;
   private int imageId;
   public Zodiac(String name,int imageId) {
       this.name = name;
       this.imageId = imageId;
   }
   public String getName() {
       return name;
   }
   public int getImageId() {
       return imageId;
   }
}
(2)重写子布局

在layout目录下新建zodiac_item.xml。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/zodiac_image"
        android:layout_width="150dp"
        android:layout_height="150dp"/>

    <TextView
        android:id="@+id/zodiac_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="10dp"/>

</LinearLayout>
(3)创建自定义适配器

自定义的适配器继承ArrayAdapter,并将泛型指定为Zodiac。重写了父类的构造函数,用于将上下文,ListView子项布局的id和数据传递进来,同时记录子项布局的id。还重写了getView()方法,这个方法在每个子项被滚动到屏幕内的时候被调用。首先通过getItem()方法得到当前项的Zodiac实例,然后使用LayoutInflater来为这个子项加载我们传入的布局。getContext()方法是得到当前布局的环境。
inflate(resourceId, parent, false)这里inflate方法接收三个参数,子项布局的id,父布局,(attachToRoot)false(表示只让我们在父布局中声明的layout属性生效,但不会为这个View添加父布局,因为一旦View有了父布局之后,它就不能再添加到ListView中了(暂且记住,等到View理解深刻就OK了))。

public class ZodiacAdapter extends ArrayAdapter<Zodiac> {
    private int resourceId;
    public ZodiacAdapter(Context context, int textViewResourceId, List<Zodiac> objects) {
        super(context,textViewResourceId,objects);
        resourceId = textViewResourceId;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Zodiac zodiac = getItem(position);//获取当前项的Zodiac实例
        View view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
        ImageView zodiacImage = (ImageView) view.findViewById(R.id.zodiac_image);
        TextView zodiacName = (TextView) view.findViewById(R.id.zodiac_name);
        zodiacImage.setImageResource(zodiac.getImageId());
        zodiacName.setText(zodiac.getName());
        return view;
    }
}
(4)在主活动中创建对象,将适配器传递给ListView

为了让他更丰富,我们准备一些图片。在res目录下新建一个drawable-xhdpi目录,将准备好的图片复制在该目录下。

public class MainActivity extends AppCompatActivity {
  private List<Zodiac> zodiacList = new ArrayList<>();
  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      initZodiac();
      ZodiacAdapter adapter = new ZodiacAdapter(MainActivity.this,R.layout.zodiac_item,zodiacList);
      ListView listView = (ListView) findViewById(R.id.list_view);
      listView.setAdapter(adapter);
  }

  private void initZodiac() {
      Zodiac rat = new Zodiac("鼠",R.drawable.rat);
      zodiacList.add(rat);
      Zodiac cow = new Zodiac("牛",R.drawable.cow);
      zodiacList.add(cow);
      Zodiac tiger = new Zodiac("虎",R.drawable.tiger);
      zodiacList.add(tiger);
      Zodiac rabbit = new Zodiac("兔",R.drawable.rabbit);
      zodiacList.add(rabbit);
      Zodiac dragon = new Zodiac("龙",R.drawable.dragon);
      zodiacList.add(dragon);
      Zodiac snake = new Zodiac("蛇",R.drawable.snake);
      zodiacList.add(snake);
      Zodiac horse = new Zodiac("马",R.drawable.horse);
      zodiacList.add(horse);
      Zodiac sheep = new Zodiac("羊",R.drawable.sheep);
      zodiacList.add(sheep);
      Zodiac monkey = new Zodiac("猴",R.drawable.monkey);
      zodiacList.add(monkey);
      Zodiac chicken = new Zodiac("鸡",R.drawable.chicken);
      zodiacList.add(chicken);
      Zodiac dog = new Zodiac("狗",R.drawable.dog);
      zodiacList.add(dog);
      Zodiac pig = new Zodiac("猪",R.drawable.pig);
      zodiacList.add(pig);
  }
} 

在这里插入图片描述

2.提升ListView的运行效率

(1)目前ListView的运行效率很低,因为在ZodiacAdapter 的getView()方法中,每个子项被滚动到屏幕内的时候就会被调用,即每次都会将布局重新加载一遍,当ListView快速滚动时,这就会成为性能的瓶颈。因此我们使用getView()方法中的另一个参数convertView,这个参数用于将之前加载好的布局进行缓冲,以便于之后可以进行重用。

  @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Zodiac zodiac = getItem(position);
        View view;
        if (convertView == null) {
            view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
        } else{
            view = convertView;
        }
        ImageView zodiacImage = (ImageView) view.findViewById(R.id.zodiac_image);
        TextView zodiacName = (TextView) view.findViewById(R.id.zodiac_name);
        zodiacImage.setImageResource(zodiac.getImageId());
        zodiacName.setText(zodiac.getName());
        return view;
    }

(2)每次使用getView()方法时,都会调用View的findViewById()方法来获取控件的实例。所以可以借助ViewHolder来对这部分性能进行优化。新增一个内部类ViewHolder,对控件的实例进行缓存。

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Zodiac zodiac = getItem(position);
        View view;
        ViewHolder viewHolder;
        if (convertView == null) {
            view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
            viewHolder = new ViewHolder();
            viewHolder.zodiacImage = (ImageView) view.findViewById(R.id.zodiac_image);
            viewHolder.zodiacName = (TextView) view.findViewById(R.id.zodiac_name);
            view.setTag(viewHolder); //将ViewHolder存储在View中
        } else{
            view = convertView;
            //重新获取ViewHolder
            viewHolder = (ViewHolder) view.getTag(); 
        }
        viewHolder.zodiacImage.setImageResource(zodiac.getImageId());
        viewHolder.zodiacName.setText(zodiac.getName());
        return view;
    }
    class ViewHolder {
        ImageView zodiacImage;
        TextView zodiacName;
    }

3.ListView的点击事件

使用setOnItemClickListener()方法为ListView注册一个监听器,当用户点击了ListView中的任何一个子项时,就会回调onItemClick()方法。在这个方法中可以通过position参数判断出用户点击的是哪一个子项,然后获取到相应的动物,并通过Toast将动物的名字显示出来。

public class MainActivity extends AppCompatActivity {
    private List<Zodiac> zodiacList = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initZodiac();
        ZodiacAdapter adapter = new ZodiacAdapter(MainActivity.this,R.layout.zodiac_item,zodiacList);
        ListView listView = (ListView) findViewById(R.id.list_view);
        listView.setAdapter(adapter);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Zodiac zodiac = zodiacList.get(position);
               Toast.makeText(MainActivity.this,zodiac.getName(),Toast.LENGTH_SHORT).show();
            }
        });
    }
    ...
}

点击猴子项:
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值