王学岗ListView和源码解析(二)

在本文中我们介绍ListView第二个的适配器——SimpleAdapter;
与ArrayAdapter只能显示单列的不同,SimpleAdapter可以显示多列。
下面我们使用SimpleAdapter在ListView中显示一个人的信息,包括name,number。
下面看下源码:

package com.example.listview;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;

public class MainActivity extends Activity {

    private ListView lv_list;
    private List<Map<String, String>> data;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lv_list = (ListView) findViewById(R.id.lv_list);
        data = new ArrayList<Map<String, String>>();
        intData();
        // 创建适配器
        SimpleAdapter adapter = new SimpleAdapter(this,// 上下文,不多解释
                data,// 填充到listView里面的数据
                R.layout.list_item,// 每一行的布局文件
                new String[] {"name","number"}, //根据每一行的map里面的key,得到里面的值
                new int[] {R.id.tv_name,R.id.tv_number}//根据ID,去吧每一个数据填充到对应的个控件上
        );
        lv_list.setAdapter(adapter);
    }

    // 初始化数据
    private void intData() {
        for (int i = 0; i < 150; i++) {
            Map<String, String> item = new HashMap<String, String>();
            item.put("name", "周瑜帅" + "-" + i);
            item.put("number", String.valueOf(36+i));
            data.add(item);
        }
    }
}
<?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"
    android:orientation="horizontal" >

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="120dp"
        android:layout_height="wrap_content"
          />

    <TextView
        android:id="@+id/tv_number"
        android:layout_width="140dp"
        android:layout_height="wrap_content"
         />

</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

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

</LinearLayout>

源码解析:与arraydapter极为类似,也是BaseAdapter的子类

我们直接看getView方法,其他的方法参考(一);

public View getView(int position, View convertView, ViewGroup parent) {
    return createViewFromResource(position, convertView, parent, mResource);
}

private View createViewFromResource(int position, View convertView,
        ViewGroup parent, int resource) {
    View v;
    if (convertView == null) {
        v = mInflater.inflate(resource, parent, false);
    } else {
        v = convertView;
    }

    bindView(position, v);

    return v;
}

多了一行代码bindView(position, v);
我们仔细来分析

private void bindView(int position, View view) {
    final Map dataSet = mData.get(position);//根据行号,得到对应的map
    if (dataSet == null) {
        return;
    }

    final ViewBinder binder = mViewBinder;
    final String[] from = mFrom;
    final int[] to = mTo;
    final int count = to.length;

    for (int i = 0; i < count; i++) {
        final View v = view.findViewById(to[i]);//根据对应的ID找到对应的控件
        if (v != null) {
            final Object data = dataSet.get(from[i]);//根据K(name,number)的值拿到相应的数据
            String text = data == null ? "" : data.toString();
            if (text == null) {
                text = "";
            }

            boolean bound = false;
            if (binder != null) {
                bound = binder.setViewValue(v, data, text);
            }

            if (!bound) {
                if (v instanceof Checkable) {//对控件的类型进行判断
                    if (data instanceof Boolean) {
                        ((Checkable) v).setChecked((Boolean) data);
                    } else if (v instanceof TextView) {
                        // Note: keep the instanceof TextView check at the bottom of these
                        // ifs since a lot of views are TextViews (e.g. CheckBoxes).
                        setViewText((TextView) v, text);
                    } else {
                        throw new IllegalStateException(v.getClass().getName() +
                                " should be bound to a Boolean, not a " +
                                (data == null ? "<unknown type>" : data.getClass()));
                    }
                } else if (v instanceof TextView) {
                    // Note: keep the instanceof TextView check at the bottom of these
                    // ifs since a lot of views are TextViews (e.g. CheckBoxes).
                   setViewText((TextView) v, text);//调用该方法赋值
                } else if (v instanceof ImageView) {
                    if (data instanceof Integer) {
                        setViewImage((ImageView) v, (Integer) data);                            
                    } else {
                        setViewImage((ImageView) v, text);
                    }
                } else {
                    throw new IllegalStateException(v.getClass().getName() + " is not a " +
                            " view that can be bounds by this SimpleAdapter");
                }
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ListView的setEmptyView方法是用来设置列表为空时显示的View,但是有时候我们在使用该方法时发现并没有生效,可能是以下几个原因: 1. 没有给ListView设置Adapter,因为只有当Adapter没有数据时才会显示EmptyView。 2. 在设置EmptyView之前已经给ListView设置了数据源,需要在设置EmptyView之前将数据源清空。 3. 在设置EmptyView之前需要先inflate出EmptyView的布局,并将其添加到ListView的父布局中。 以下是一个setEmptyView无效的例子: ```java ListView listView = findViewById(R.id.list_view); View emptyView = findViewById(R.id.empty_view); listView.setEmptyView(emptyView); String[] data = {"item1", "item2", "item3"}; ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, data); listView.setAdapter(adapter); ``` 上述代码中,设置了EmptyView,但是并没有生效,因为在设置EmptyView之前已经给ListView设置了数据源,需要将数据源清空,即在setAdapter之前添加如下代码: ```java listView.setAdapter(null); ``` 另外,还需要注意,EmptyView需要先inflate出来并添加到ListView的父布局中,例如: ```java View emptyView = LayoutInflater.from(this).inflate(R.layout.empty_view, (ViewGroup) listView.getParent(), false); ``` 至于ListView源码实现,可以参考以下几个方法: 1. setEmptyView方法: ```java public void setEmptyView(View emptyView) { mEmptyView = emptyView; final T adapter = mAdapter; final boolean empty = ((adapter == null) || adapter.isEmpty()); updateEmptyStatus(empty); } private void updateEmptyStatus(boolean empty) { if (isInFilterMode()) { empty = false; } if (empty) { if (mEmptyView != null) { mEmptyView.setVisibility(View.VISIBLE); setVisibility(View.GONE); } else { // If the caller just removed our empty view, make sure the list view is visible setVisibility(View.VISIBLE); } // We are now GONE, so pending layouts will not be dispatched. // Force one here to ensure that the state of the list matches // the state of the adapter. if (mDataChanged) { this.onLayout(false, getLeft(), getTop(), getRight(), getBottom()); } } else { if (mEmptyView != null) { mEmptyView.setVisibility(View.GONE); } setVisibility(View.VISIBLE); } } ``` 2. setAdapter方法: ```java public void setAdapter(ListAdapter adapter) { if (mAdapter != null) { mAdapter.unregisterDataSetObserver(mDataSetObserver); resetList(); } mAdapter = adapter; if (mAdapter != null) { mOldSelectedPosition = INVALID_POSITION; mOldSelectedRowId = INVALID_ROW_ID; mItemCount = mAdapter.getCount(); mDataChanged = true; // Detect the case where a cursor that was previously invalidated has // been repopulated with new data. mHasStableIds = mAdapter.hasStableIds(); if (mChoiceMode != CHOICE_MODE_NONE && mAdapter.hasStableIds()) { mChoiceMode = CHOICE_MODE_SINGLE; if (mCheckStates == null) { mCheckStates = new SparseBooleanArray(); } if (mCheckedIdStates == null) { mCheckedIdStates = new LongSparseArray<Boolean>(); } } if (!mPopupHidden) { // Show the popup if we have one if (mAdapter.getCount() > 0) { showPopup(); } } } else { mItemCount = 0; mDataChanged = false; mHasStableIds = false; mOldSelectedPosition = INVALID_POSITION; mOldSelectedRowId = INVALID_ROW_ID; mChoiceMode = CHOICE_MODE_NONE; mCheckStates.clear(); mCheckedIdStates.clear(); // Hide the currently visible popup dismissPopup(); } if (mFilter != null) { mAdapter.getFilter().filter(mFilter); } requestLayout(); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值