自己对于ListView的理解以及常用用法

ListView虽然现在几乎被RecyclerView所替代,但是在一些简单的列表中ListView会自动给每个子项之间添加一条分隔线,如果使用RecyclerVIew实现相同的功能的话会显复杂。而且学习使用ListView会进一步了数据填充器Adapter和如何优化简单的代码。

ListView的简单用法

1.最简单的创建一个只含有ListView的布局:在ListView控件中设置完id和宽高后,就完成一个最简单的控件初始化

<?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">

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

</LinearLayout>

2.在ListView这个列表中,每一项都是其中的一个小布局,所以我们还要创建一个list_item.xml布局文件

<?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">

    <ImageView
        android:id="@+id/imgView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

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

</LinearLayout>

3.ListView一般我们其中填充的数据都是在网上所获取的,所以每个Item下可能会有多个数据,所以现在我们需要一个实体类Item来作为ListView的适配器的适配类型,因为我们的布局中写入了ImageView和TextView两个所需要填充数据的地方,所在实体类中我们需要获取到img的Id以及text文字。

public class Item {
    private int imgId;
    private String itemText;

    public Item(int imgId, String itemText) {
        this.imgId = imgId;
        this.itemText = itemText;
    }

    public int getImgId() {
        return imgId;
    }

    public void setImgId(int imgId) {
        this.imgId = imgId;
    }

    public String getItemText() {
        return itemText;
    }

    public void setItemText(String itemText) {
        this.itemText = itemText;
    }
}

4.在实体类创建后,我们就需要创建ListView最重要的适配器了,常见的Adapter有。BaseAdapter:抽象类,实际开发中我们会继承这个类并且重写相关方法以及ArrayAdapter:支持泛型操作,最简单的一个Adapter,可以直接在ListView逻辑的地方建立。但是这里我们创建一个ItemAdapter类这个适配器继承自BaseAdapter,在ItemAdapter中重写父类的四个方法,getCount()获取listView的item项的总数,getItem()获取单个Item,getItemId()获取item的id,getView()设值返回每一个Item。以及构造方法ItemAdapter传入填充的数据,以及上下文对象。在getView()方法中,为了防止converView不断创建所以我们要添加一个盘空操作,之后获取所需填充位置的id,设值,最后返回converView。注意:getView在界面每显示一条就会调用一次。这里还有一个需要优化的地方,在后面进行。

public class ItemAdapter extends BaseAdapter {

    private List<Item> date;
    private Context context;

    public ItemAdapter(List<Item> date, Context context) {
        this.date = date;
        this.context = context;
    }

    @Override
    public int getCount() {
        return date.size();
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false);
        }
        ImageView img_icon = convertView.findViewById(R.id.imgView);
        TextView item_text = convertView.findViewById(R.id.itemView);
        img_icon.setImageResource(date.get(position).getImgId());
        item_text.setText(date.get(position).getItemText());
        return convertView;
    }
}

5.在MainActivity中,首先我们要创建一个集合存放要加载的图片及文字,在initItems中初始化我们所需要的数据,创建一个adapter实例和一个Listview,将adapter填充到ListView当中。

public class MainActivity extends AppCompatActivity {
    private List<Item> Data = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initItems();
        ItemAdapter adapter = new ItemAdapter(Data,this);
        ListView listView = findViewById(R.id.listView);
        listView.setAdapter(adapter);
    }

    private void initItems() {
        for (int i = 0; i < 50; i++) {
            Data.add(new Item(R.drawable.ic_launcher_foreground,"这是第"+i+"项"));
        }
    }
}

6.这样我们就可以在模拟器或者真机上看到结果了。

 

ListView的运行优化

       其中第一点优化已经写入到代码中了,是convertView的复用。界面上有多少个Item,那么getView方法就会被调用多少次,inflate()每次都要加载一次xml,这个convertView是系统提供给我们的可供服用的View 的缓存对象,以便于进行之后复用,所以我们需要判断一下convertView是否为空。另一点是每次getView在调用的时候都要findViewById,findViewById也是非常耗时,所以我们需要借助一个ViewHolder来对性能进行优化,接下来我们在ItemAdapter中进行代码修改,,首先我们新增了一个内部类ViewHolder,用于对控件的缓存,将控件的实例存放在ViewHolder中,调用setTag()方法见ViewHolder对象存放到View中。

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false);
            viewHolder = new ViewHolder();
            viewHolder.img_icon = convertView.findViewById(R.id.imgView);
            viewHolder.item_text = convertView.findViewById(R.id.itemView);
            convertView.setTag(viewHolder);
        }else {
            viewHolder = (ViewHolder) convertView.getTag();
        }
        viewHolder.img_icon.setImageResource(date.get(position).getImgId());
        viewHolder.item_text.setText(date.get(position).getItemText());
        return convertView;
    }
    static class ViewHolder{
        ImageView img_icon;
        TextView item_text;
    }

ListView的点击事件

能够进行每项的点击是特别重要的事情,我们使用listView.setOnItemClickL()方法为ListView注册一个监听器,当用户点击每个item时都会回调OnItemClick方法。这个方法会通过position参数判断用户点击的是哪一个子项。

listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(MainActivity.this,"你点击了"+position+"项",Toast.LENGTH_SHORT).show();
            }
        });

ListView的部分属性

ListView作为一个控件就会有一些我们经常可能用到的属性:

footerDividersEnabled:是否在footerView(表尾)前绘制一个分隔条,默认为true

headerDividersEnabled:是否在headerView(表头)前绘制一个分隔条,默认为true

divider:设置分隔条,可以用颜色分割,也可以用drawable资源分割

dividerHeight:设置分隔条的高度

stackFromBottom:设置为true后列表将从底部开始显示

cacheColorHint:.设置点击颜色

focusable:为抢占了控件的组件

descendantFocusability:item根节点

  • beforeDescendants:viewgroup会优先其子类控件而获取到焦点
  • afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点
  • blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点

我们如果需要设置表头或者表尾属性就需要在Java或者Kotlin中进行设置:

addHeaderView(View v):添加headView(表头),括号中的参数是一个View对象

addFooterView(View v):添加footerView(表尾),括号中的参数是一个View对象

addHeaderView(headView, null, false):和前面的区别:设置Header是否可以被选中

addFooterView(View,view,false):和前面的区别:设置Header是否可以被选中

这就是我对于ListView的自己的理解和常用的部分方法,虽然现在ListView几乎被RecyclerView所替代但列表作为经常使用的控件之一,我们还是得了解ListView、ListView的属性及数据填充器的使用。如需转载请注明出处https://blog.csdn.net/weixin_47425891/article/details/116785975

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值