ListView的Adapter

来源:互联网 发布:无人机地面站软件 编辑:程序博客网 时间:2024/06/05 01:57

**

关于ListView控件的适配器Adapter

**

本人也只是刚刚接触安卓开发,就想对用的比较多的ListView开始进行一点知识的整理。就拿自己写的一个消息列表来作为例子来整理一波吧。

在主活动的布局文件中就只需要加入一个ListView的控件。

<ListView    android:layout_marginTop="5dp"    android:dividerHeight="5dp"    android:divider="#99d9db"    android:id="@+id/lv_msg"    android:layout_width="match_parent"    android:layout_height="match_parent"></ListView>

这里也没什么好讲的…

然后我们再来定义一波ListView中的item布局,我在这里只是简单地设置了一个头像的ImageView、一个用户名的TextView和一条内容的TextViews并为之一一设置ID。

<LinearLayout    android:layout_marginTop="5dp"    xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="horizontal"    android:layout_width="match_parent"    android:layout_height="match_parent">    <LinearLayout        android:gravity="center"        android:layout_weight="1"        android:layout_width="0dp"        android:layout_height="60dp">        <ImageView            android:id="@+id/iv_head"            android:layout_width="65dp"            android:layout_height="55dp" />    </LinearLayout>    <LinearLayout        android:orientation="vertical"        android:layout_weight="4"        android:layout_width="0dp"        android:layout_height="60dp">        <TextView            android:id="@+id/tv_name"            android:layout_marginTop="5dp"            android:layout_marginLeft="5dp"            android:layout_width="100dp"            android:layout_height="20dp" />        <TextView            android:id="@+id/tv_msg"            android:maxLines="1"            android:layout_marginTop="2dp"            android:layout_marginLeft="5dp"            android:layout_width="match_parent"            android:layout_height="30dp" />    </LinearLayout></LinearLayout>

接下来就是重头戏了——一个自定义的适配器

这也是我今天挺想去总结的一个点,因为我个人觉得适配器就是一个ListView的灵魂,操控着它的数据更新、操控着它的视图展示等等。

常用的适配器有BaseAdapter,ArrayAdapter,SimpleAdapter等等。而SimpleAdapter在三者中又用的是比较少的,因为SimpleAdapter已经在内部被写好,改动的地方比较少,因此灵活性较低,不宜被继承改动。而ArrayAdapter则是由BaseAdapter派生而来,具有BaseAdapter的全部功能,再加上继承自ArrayAdapter的适配器在实例化时可直接使用泛型构造,从而使自定义适配器更加灵活。而在本例中的适配器继承的便是ArrayAdapter(因为使用了自定义的一个Msg类。)。

private int resourceId;private List<Msg> message = new ArrayList<Msg>();public MsgAdapter(@NonNull Context context, @LayoutRes int resource) {    super(context, resource);    resourceId = resource;}public MsgAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull List<Msg> objects) {    super(context, resource, objects);    resourceId = resource;    this.message = objects;}public MsgAdapter(@NonNull Context context, @LayoutRes int resource, @IdRes int textViewResourceId) {    super(context, resource, textViewResourceId);}public MsgAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull Msg[] objects) {    super(context, resource, objects);}public MsgAdapter(@NonNull Context context, @LayoutRes int resource, @IdRes int textViewResourceId, @NonNull Msg[] objects) {    super(context, resource, textViewResourceId, objects);}public MsgAdapter(@NonNull Context context, @LayoutRes int resource, @IdRes int textViewResourceId, @NonNull List<Msg> objects) {    super(context, resource, textViewResourceId, objects);}

可见,在继承了ArrayAdater后,IDE会提示你要创建构造方法,而该适配器有6种构造方法。其中的几个参数如context指依附的活动,resource指加载item的布局id,List object则指列表中的对象等等就不一一赘述了,毕竟见名知意。

而在自定义的adapter中还可以重写内部方法。

(一)public View getView(int position, View convertView, ViewGroup parent)

此方法实现了加载每一个item的布局的功能,最终返回的是一个View对象,通常与类ViewHolder连用。此类只定义item的布局中存在的控件,以方便在加载整个列表布局时,更加快速地从类里取出存在的item布局。即若某个item的布局若存在于ViewHolder,则不需再重新实例一个新的对象,重新加载该item布局,而是从ViewHolder中取出该item的布局,直接展示在ui层。

public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {    View item;    ViewHolder mViewHolder;    //获取当前位置的position以填充布局    Msg msg = getItem(position);    //如果当前view为空,则将当前view填充入viewholder中,否则从viewholder中回调出来    if (convertView == null) {        //将当前view加载出来        item = LayoutInflater.from(getContext()).inflate(resourceId, null);        mViewHolder = new ViewHolder();        mViewHolder.head = (ImageView) item.findViewById(R.id.iv_head);        mViewHolder.name = (TextView) item.findViewById(R.id.tv_name);        mViewHolder.msg = (TextView) item.findViewById(R.id.tv_msg);        item.setTag(mViewHolder);    } else {        item = convertView;        mViewHolder = (ViewHolder) item.getTag();    }    mViewHolder.head.setImageResource(msg.getImageResource());//设定头像    mViewHolder.name.setText(msg.getName());//设定用户名    mViewHolder.msg.setText(msg.getMsg());//设定消息    return item;}

(二)public int getCount()、public int getPosition(T item)、public T getItem(int position)

这些方法分别是获取整个列表的长度,即item的数目,一般返回的是mList.size();获取当前item的位置,返回的是item在列表的位置;获取当前位置的item,返回的是position中对应的item对象。

@Overridepublic int getCount() {    return message.size();}//获取item的位置@Overridepublic int getPosition(@Nullable Msg item) {    return super.getPosition(item);}//获取当前位置的item@Nullable@Overridepublic Msg getItem(int position) {    return super.getItem(position);}

(三)public void notifyDataSetChanged()

这个方法是用来刷新列表的。比如当你需要删除列表中的某个item时,点击删除后若当前的适配器没有调用此方法(即没有mAdapter.notifyDataSetChanged()),IDE会报错。而这个方法也可以在Activity的onResume()方法中调用,从而在跳转过程后,回到当前页面仍然保持最新的列表状态。

@Overridepublic void notifyDataSetChanged() {    super.notifyDataSetChanged();}

整个MsgAdapter代码如下:

/**  * Created by Carson on 2017/7/15.  */public class MsgAdapter extends ArrayAdapter<Msg>{    private int resourceId;    private List<Msg> message = new ArrayList<Msg>();    public MsgAdapter(@NonNull Context context, @LayoutRes int resource) {        super(context, resource);        resourceId = resource;    }    public MsgAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull List<Msg> objects) {        super(context, resource, objects);        resourceId = resource;        this.message = objects;    }    //创建item的临时存储器,提升上下拉动时的加载的速度    class ViewHolder {        ImageView head;        TextView name, msg;    }    //获取列表的个数    @Override    public int getCount() {        return message.size();    }    //获取item的位置    @Override    public int getPosition(@Nullable Msg item) {        return super.getPosition(item);    }    //获取当前位置的item    @Nullable    @Override    public Msg getItem(int position) {        return super.getItem(position);    }    //获取item的view    @NonNull    @Override    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {        View item;        ViewHolder mViewHolder;        //获取当前位置的position以填充布局        Msg msg = getItem(position);        //如果当前view为空,则将当前view填充入viewholder中,否则从viewholder中回调出来        if (convertView == null) {            //将当前view加载出来            item = LayoutInflater.from(getContext()).inflate(resourceId, null);            mViewHolder = new ViewHolder();            mViewHolder.head = (ImageView) item.findViewById(R.id.iv_head);            mViewHolder.name = (TextView) item.findViewById(R.id.tv_name);            mViewHolder.msg = (TextView) item.findViewById(R.id.tv_msg);            item.setTag(mViewHolder);        } else {            item = convertView;            mViewHolder = (ViewHolder) item.getTag();        }        mViewHolder.head.setImageResource(msg.getImageResource());//设定头像        mViewHolder.name.setText(msg.getName());//设定用户名        mViewHolder.msg.setText(msg.getMsg());//设定消息        return item;    }    @Override    public void notifyDataSetChanged() {        super.notifyDataSetChanged();    }}

Activity的代码:

public class MsgActivity extends AppCompatActivity {    private List<Msg> mList;    private MsgAdapter mAdapter;    private ListView mListView;    //随机定义一些图片、用户名、内容    private int []head = {            R.drawable.recommend_head1,            R.drawable.recommend_head2,            R.drawable.recommend_head3,            R.drawable.recommend_head4    };    private String []name = {            "King",            "Lily",            "July",            "Kelvin"    };    private String []message = {            "I am message one.",            "I am message two.",            "I am message three.",            "I am message four."    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        getSupportActionBar().hide();        setContentView(R.layout.activity_msg);        initViews();    }    private void initViews() {        mList = new ArrayList<Msg>();        mAdapter = new MsgAdapter(this, R.layout.layout_msg, mList);        mListView = (ListView) findViewById(R.id.lv_msg);        mListView.setAdapter(mAdapter);        Random r = new Random();        //可以从这里初始化listView        for (int i = 1; i <= 10; i++){            Msg msg = new Msg(head[r.nextInt(4)], "" + name[r.nextInt(4)], "" + message[r.nextInt(4)]);            //将实例化后的对象加入到list中,然后list通过adapter适配于listview中            mList.add(msg);        }    }}

当然个人只是处于初学地步,若有错误也请各位大牛指点一下。

原创粉丝点击