• Android开发系列之ListView用法


      ListView是我们开发过程中最常用的控件之一,由于手机屏幕空间都比较有限度,能够一次性在屏幕上显示的内容并不多,当我们程序中有大量的数据需要展示的时候,就可以借助它来完成。它允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内,同时屏幕上原有的数据则会滚动出屏幕。

    一、ListVeiw的简单用法

      首先在XML文件中定义ListView的布局

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

       然后修改activity中的代码,如下所示:

     1 public class SecondActivity extends AppCompatActivity {
     2 
     3     private String[] data = {"Apple", "Banana", "Orange", "Watermelon", "Pear"};
     4 
     5     @Override
     6     protected void onCreate(Bundle savedInstanceState) {
     7         super.onCreate(savedInstanceState);
     8         setContentView(R.layout.activity_second);
     9 
    10         ArrayAdapter<String> adapter = new ArrayAdapter<String>(SecondActivity.this, android.R.layout.simple_list_item_1,data);
    11         ListView listView = (ListView)findViewById(R.id.listView01);
    12         listView.setAdapter(adapter);
    13     }
    14 
    15 }

      这样,我们就简单的实现了ListView的数据展示。不过,数组中的数据是无法直接传递给ListView的,这里我们就要提到适配器的概念了。Android中提供了很多的适配器类,我们先说下ArrayAdapter,它可以通过泛型来指定要适配的数据类型,然后在构造函数中把要适配的数据传入即可。它有多个构造函数的重载,我们可以根据实际情况选择最合适的一种。上面的代码中由于我们提供的数据都是字符串,因此将ArrayAdapter的泛型指定为String,然后在ArrayAdapter的构造函数中依次传入当前上下文、ListView的子项布局的id、以及要适配的数据。注意,我们使用android.R.layout.simple_list_item_1作为它的子项布局id ,这是Android内置的布局文件,里面只有一个TextView,可用于简单的显示一段文本。调用ListViewd的setAdapter()方法,将构造好的适配器对象传递进去,这样ListView和数据之间的关联就建立完成了。

    二、定制ListView

      在项目中ListView不但要展示大量的数据,显示也要非常的美观,只显示一段文本的ListView太过于单调,下面就来介绍一下如何去定制ListView的界面,让它可以显示更加丰富的内容。这里我们让ListView的每一行显示一张图片和一个文本,详细代码如下所示:

      (1)首先在activity对应的XML文件activity_list_view.xml里定义ListView布局

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

      (2)自定义ListView的子项布局,新建一个XML文件custom_item.xml:

    <ImageView
            android:id="@+id/imageView01"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <TextView
            android:id="@+id/listView_TextVeiw01"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginLeft="10dp"
            />

      (3)自定义一个实体类CustomClass,作为ListView适配器的适配类型。

     1 /*
     2  *定制CustomClass实体类,作为ListView适配器的适配类型
     3  *name:表示图片的含义
     4  *imageId:表示对应的图片资源ID
     5  */
     6 public class CustomClass {
     7     private String name;
     8     private int imageId;
     9 
    10     public CustomClass(String name, int imageId){
    11         this.name = name;
    12         this.imageId = imageId;
    13     }
    14 
    15     public String getName() {
    16         return name;
    17     }
    18 
    19     public int getImageId() {
    20         return imageId;
    21     }
    22 }

      (4)自定义适配器CustomAdapter

     1 /*
     2 * CustomAdapter重写了父类的一组构造函数,用于将上下文、ListVeiw的子项布局的id和数据都传递进来
     3 * 另外,又重写了getView()方法,这个方法在每个子项被滚动到屏幕内的时候调用
     4 * 在getView方法中,首先通过getItem()方法得到当前项的CustomClass实例,然后使用LayoutInflater来
     5 * 为这个子项加载我们传入的布局,接着调用Veiw的findViewById()方法分别获取到ImageVeiw和TextView的实例,
     6 * 并分别调用他们的setImageResource()和setText()方法来设置显示的图片和文字,最后将布局返回。
     7 * */
     8 
     9 
    10 public class CustomAdapter extends ArrayAdapter<CustomClass> {
    11     private int resourceId;
    12 
    13     public CustomAdapter(Context context, int textViewResourceId, List<CustomClass> objects){
    14         super(context, textViewResourceId, objects);
    15         resourceId = textViewResourceId;
    16     }
    17 
    18     public View getView(int position, View convertView, ViewGroup parent){
    19         CustomClass custom = getItem(position);
    20         View view = LayoutInflater.from(getContext()).inflate(resourceId, null);
    21         ImageView customImage = (ImageView)view.findViewById(R.id.imageView01);
    22         TextView customTextView = (TextView)view.findViewById(R.id.listView_TextVeiw01);
    23         customImage.setImageResource(custom.getImageId());
    24         customTextView.setText(custom.getName());
    25         return view;
    26     }
    27 }

      (5)下面修改ListViewActivity中的代码

     1 public class ListViewActivity extends AppCompatActivity {
     2 
     3     private List<CustomClass> customList = new ArrayList<CustomClass>();
     4 
     5     @Override
     6     protected void onCreate(Bundle savedInstanceState) {
     7         super.onCreate(savedInstanceState);
     8         setContentView(R.layout.activity_list_view);
     9 
    10         initCustoms();
    11         CustomAdapter adapter = new CustomAdapter(ListViewActivity.this, R.layout.custom_item, customList);
    12         ListView listView = (ListView)findViewById(R.id.listView02);
    13         listView.setAdapter(adapter);
    14 
    15     }
    16     //初始化数据
    17     private void initCustoms(){
    18         CustomClass chat = new CustomClass("Chat", R.drawable.chat_pressed);
    19         customList.add(chat);
    20 
    21         CustomClass friends = new CustomClass("Friends", R.drawable.friends_pressed);
    22         customList.add(friends);
    23 
    24     }
    25 }

      总结:自定义ListView主要自定义了适配器、适配器指定的泛型、ListView的子项,理解了整体流程,实现起来就会更佳方便

      (6)提升ListView的运行效率

      目前我们定制的ListView的运行效率是很低的,因为CustomAdapter的getView()方法中每次都将布局重新加载了一遍,当ListView快速滚动的时候这就会成为性能瓶颈。在getView()中有一个convertView参数,该参数用于将之前加载好的布局进行缓存,以便之后可以进行重用。下面对getView()中的代码进行修改:

    public View getView(int position, View convertView, ViewGroup parent){
            CustomClass custom = getItem(position);
            View view;
            if (convertView == null){
                view = LayoutInflater.from(getContext()).inflate(resourceId, null);
            }else {
                view = convertView;
            }
            ImageView customImage = (ImageView)view.findViewById(R.id.imageView01);
            TextView customTextView = (TextView)view.findViewById(R.id.listView_TextVeiw01);
            customImage.setImageResource(custom.getImageId());
            customTextView.setText(custom.getName());
            return view;
        }

      可以看到,我们在getView()中的代码进行了判断,如果convertView为空,则使用LayoutInflater去加载布局,如果不为空则直接对convertView进行重用。这样就大大提高了ListView的运行效率,在快速滚动的时候也可以表现出更好的性能。

      虽然在运行的时候已经不会再重复去加载布局,但是每次在getView方法中还是会调用View的findViewById()方法来获取一次控件的实例,我们可以借助ViewHolder来对这部分性能进行优化,修改CustomAdapter中的代码,如下所示:

     1 public View getView(int position, View convertView, ViewGroup parent){
     2         CustomClass custom = getItem(position);
     3         View view;
     4         ViewHolder viewHolder;
     5         if (convertView == null){
     6             view = LayoutInflater.from(getContext()).inflate(resourceId, null);
     7 
     8             viewHolder = new ViewHolder();
     9             viewHolder.customImage = (ImageView)view.findViewById(R.id.imageView01);
    10             viewHolder.customTextView = (TextView)view.findViewById(R.id.listView_TextVeiw01);
    11             view.setTag(viewHolder);  //将ViewHolder存储在View中
    12 
    13         }else {
    14             view = convertView;
    15             viewHolder = (ViewHolder)view.getTag();  //重新获取ViewHolder
    16         }
    17 
    18         viewHolder.customImage.setImageResource(custom.getImageId());
    19         viewHolder.customTextView.setText(custom.getName());
    20 
    21         return view;
    22     }
    23 
    24     class ViewHolder{
    25         ImageView customImage;
    26         TextView customTextView;
    27     }

      新增一个内部类ViewHolder,用于对控件的实例进行缓存。当convertView为空的时候,创建一个ViewHolder对象,并将控件的实例都存放在ViewHolder里,然后调用View的setTag()方法,将ViewHolder对象存储在View中。当convertView不为空的时候则调用View的getTag()方法,把ViewHolder重新取出。这样所有控件的实例都缓存在了ViewHolder里,就没有必要每次都通过findViewById()方法来获取控件实例了。

      (7)ListView的点击事件

      修改ListViewActivity中的代码,如下所示:

     1 protected void onCreate(Bundle savedInstanceState) {
     2         super.onCreate(savedInstanceState);
     3         setContentView(R.layout.activity_list_view);
     4 
     5         initCustoms();
     6         CustomAdapter adapter = new CustomAdapter(ListViewActivity.this, R.layout.custom_item, customList);
     7         ListView listView = (ListView)findViewById(R.id.listView02);
     8         listView.setAdapter(adapter);
     9 
    10         listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    11             @Override
    12             public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
    13                 CustomClass custom = customList.get(i);
    14                 Toast.makeText(ListViewActivity.this, custom.getName(), Toast.LENGTH_SHORT).show();
    15             }
    16         });

      

  • 相关阅读:
    [HAOI2008]硬币购物
    [NOI2006]网络收费
    [HNOI2014]米特运输
    Codeforces Round #536 (Div. 2)
    [洛谷P3931]SAC E#1
    [洛谷P1402]酒店之王
    [洛谷P4174][NOI2006]最大获利
    [CF1082G]Petya and Graph
    [CF1095F]Make It Connected
    [CF1083B]The Fair Nut and Strings
  • 原文地址:https://www.cnblogs.com/whongs/p/6741701.html
Copyright © 2020-2023  润新知