Android查缺补漏之ListView

上一篇“查缺补漏”总结了Toolbar的用法,这次我们来看一看ListView。

或许很多人会认为Android出了RecyclerView之后就不用再去了解ListView了,但实际上,ListView作为一种展示列表的控件,曾经在很多的APP中大量的使用,在很多场景中都是很经典的,而且理解了ListView,也会更容易理解RecyclerView。

什么是ListView

ListView是Android开发中非常重要的基础组件之一,它使得开发者能够很容易的展示一组数据。一般而言,实现一个ListView通常需要三个部分:ListView控件、Data数据、Adpter适配器,通过适配器实现将数据绑定到ListView里面的控件中。

基本用法

和其他控件一样,ListView需要先在布局文件中声明(当然特殊情况下也可以直接在Java中创建对象)
    <ListView
        android:id="@+id/listview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></ListView>
然后在相应的Acrivity中进行绑定
mListView = (ListView)findViewById(R.id.listview);
之后,创建一些数据,这里我们需要使用ArrayList对数据进行管理
        List<Map<String, String>> datas = new ArrayList<Map<String,String>>();
        Map<String,String> map1 = new HashMap<String,String>();
        map1.put("key","item1");
        datas.add(map1);
        Map<String,String> map2 = new HashMap<String,String>();
        map2.put("key","item2");
        datas.add(map2);
创建一个SimpleAdapter将数据放到listView中
        mListView.setAdapter(new SimpleAdapter(this,datas,android.R.layout.simple_list_item_1,
                new String[]{"key"},
                new int[]{android.R.id.text1}
        ));
这样一个最基本的ListView就完成了

在上面的代码中,可以看到在创建SimpleAdapter的时候,传入了一个R.layout.simple_list_item_1的参数,这个参数用来确定item中展示的样式,除了simple_list_item_1以外,还有一些其他的样式。

样式simple_list_item_2

simple_list_item_2是一种包含副标题的样式,用法和simple_list_item_1类似,我们在设置数据的时候增加一个参数
        List<Map<String, String>> datas = new ArrayList<Map<String,String>>();
        Map<String,String> map1 = new HashMap<String,String>();
        map1.put("key1","item1");
        map1.put("key2","value1");
        datas.add(map1);
        Map<String,String> map2 = new HashMap<String,String>();
        map2.put("key1","item2");
        map2.put("key2","value1");
        datas.add(map2);
创建一个新的SimpleAdapter,设置为simple_list_item_2
        mListView.setAdapter(new SimpleAdapter(this,datas,android.R.layout.simple_list_item_2,
                new String[]{"key1","key2"},
                new int[]{android.R.id.text1,android.R.id.text2}
        ));
其中key1和key2的值分别对应android.R.id.text1和android.R.id.text2

样式simple_list_item_checked

simple_list_item_checked是一种选择的样式,用法和simple_list_item_1相似,也只需设置一个key
        mListView.setAdapter(new SimpleAdapter(this,datas,android.R.layout.simple_list_item_checked,
                new String[]{"key1"},
                new int[]{android.R.id.text1}
        ));
但是需要设置选择的模式
        /*
         * CHOICE_MODE_SINGLE  单选--ListView中只能有一个item被选中
         * CHOICE_MODE_MULTIPLE  多选--允许选中多个item
         * CHOICE_MODE_NONE  默认值,点击没反应
         */
        mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
除此之外,还有simple_list_item_multiple_choice,simple_list_item_single_choice,可以实现其他的选择样式。

自定义布局

很多时候,这些自定义布局并不能满足我们的需求,那么便需要我们自己定义item的布局。比如我们新建一个布局文件名为list_item.xml,里面放了一个高度为150dp的TextView
<?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="150dp">

    <TextView
        android:gravity="center"
        android:id="@+id/text"
        android:text="asd"
        android:layout_width="match_parent"
        android:layout_height="150dp" />
    
</LinearLayout>
然后在activity中创建SimpleAdapter
        mListView.setAdapter(new SimpleAdapter(this,datas,R.layout.list_item,
                new String[]{"key1"},
                new int[]{R.id.text}
        ));
就可以在ListView中看到我们自定义的布局

自定义适配器

虽然自定义了布局,但是在很多时候使用SimpleAdapter并不能满足我们的需求,我们可以通过自己定义适配器的方式实现我们期望的各种效果,比如我们再次实现上图的效果,创建一个继承BaseAdapter的适配器
package com.example.steveyg.listdemo;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

/**
 * Created by steveyg on 17/1/16.
 */

public class MyAdapter extends BaseAdapter{

    //数据集
    String []datas = {"item1","item2"};
    Context context;

    public MyAdapter(Context context){
        this.context = context;
    }
    @Override
    public int getCount() {
        return datas.length;
    }

    @Override
    public Object getItem(int position) {
        return datas[position];
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        LayoutInflater li = LayoutInflater.from(context);
        TextView tv = (TextView) li.inflate(R.layout.list_item, null);
        tv.setText(datas[position]);
        return tv;
    }
}
在这个适配器里面重写5个方法,通过view的方式生成view进行处理,这样就可以使得item更加复杂,实现更多的效果,甚至可以返回不同的样式。而数据集datas也可以使用List的方式传入,更加的灵活。

ViewHolder

当ListView里面的数据特别多的时候,如果每次都重新创建一个View的话,会占用大量内存,对性能造成影响,因此我们需要通过重新填充的方式减少对象的创建。

图片来自网络
修改我们的Adapter
package com.example.steveyg.listdemo;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;

/**
 * Created by steveyg on 17/1/16.
 */

public class MyAdapter extends BaseAdapter {

    //数据集
    String[] datas = {"item1", "item2"};
    Context context;

    public MyAdapter(Context context) {
        this.context = context;
    }

    @Override
    public int getCount() {
        return datas.length;
    }

    @Override
    public Object getItem(int position) {
        return datas[position];
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        ViewHolder holder = null;
        if (convertView == null) {
            convertView = LinearLayout.inflate(context, R.layout.list_item, null);
            holder = new ViewHolder(convertView);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.textview.setText(datas[position]);
        return convertView;
    }

    class ViewHolder {
        TextView textview;

        public ViewHolder(View view) {
            this.textview = (TextView) view.findViewById(R.id.text);
        }
    }
}
这样便实现了view holder对于adapter的优化。

点击事件

ListView的点击事件可以通过listview实现也可以通过adaper设置,如果使用了SimpleAdapter则需要通过listview实现:
        //点击事件
        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                //点击了第position个item
            }
        });

        //长按事件
        mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                return false;
            }
        });
而如果通过adapter设置,那么直接在getView中设置各个控件的点击事件即可。

大家好,今天给大家分享一下Android里的Context的一些用法. 这里大致可以分为两种:一是传递Context参数,二是调用全局的Context. 其实我们应用启动的时候会启动Application这个类,这个类是在AndroidManifest.xml文件里其实是默认的 为了让大家更容易理解,写了一个简单的Demo.步骤如下: 第1步:新建一个Android工程ApplicationDemo,目录结构如下: 第2步:新建一个工具类ToolsUtil.java,代码如下 package com.tutor.application; import android.content.Context; import android.widget.Toast; /** * @author carlshen. * 应用的一些工具类. */ public class ToolUtils { /** * 参数带Context. * @param context * @param msg */ public static void showToast(Context context,String msg){ Toast.makeText(context, msg, Toast.LENGTH_SHORT).show(); } /** * 调用全局的Context. * @param msg */ public static void showToast(String msg){ Toast.makeText(MainApplication.getContext(), msg, Toast.LENGTH_SHORT).show(); } } 第3步:新建一个View命名为MainView.java就是我们Activity现实的View.代码如下: package com.tutor.application; import android.app.Activity; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; import android.widget.FrameLayout; /** * @author carlshen. * 自定义的MainView. */ public class MainView extends FrameLayout implements View.OnClickListener{ private Context mContext; private Activity mActivity; /** * 参数Button. */ private Button mArgButton; /** * 全局Button. */ private Button mGlobleButton; /** * 退出Button. */ private Button mExitButton; public MainView(Context context){ super(context); setupViews(); } public MainView(Context context, AttributeSet attrs) { super(context, attrs); setupViews(); } private void setupViews(){ //获取View的上下文. mContext = getContext(); //这里将Context转换为Activity. mActivity = (Activity)mContext; LayoutInflater inflater = LayoutInflater.from(mContext); View v = inflater.inflate(R.layout.main, null); addView(v); mArgButton = (Button)v.findViewById(R.id.arg_button); mGlobleButton = (Button)v.findViewById(R.id.glo_button); mExitButton = (Button)v.findViewById(R.id.exit_button); mArgButton.setOnClickListener(this); mGlobleButton.setOnClickListener(this); mExitButton.setOnClickListener(this); } public void onClick(View v) { if(v == mArgButton){ ToolUtils.showToast(mContext, "我是通过传递Context参数显示的!"); }else if(v == mGlobleButton){ ToolUtils.showToast("我是通过全局Context显示的!"); }else{ mActivity.finish(); } } } 这里MainView.java使用的布局main.xml代码如下: <?xml version="1.0" encoding="utf-8"?> 第4步:修改ApplicationDemoActivity.java,代码如下: package com.tutor.application; import android.app.Activity; import android.os.Bundle; public class ApplicationDemoActivity extends Activity { private static Context aContext; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MainView mMainView = new MainView(this); setContentView(mMainView); aContext = getApplicationContext(); } /**获取Context. * @return */ public static Context getContext(){ return aContext; } } 第5步:运行上述工程效果如下:
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值