1. ListView类
ListView
的主要属性
stackFromBottom
,设置为true
时,内容将从底部开始显示cacheColorHint
,设置为#00000000
透明时,可以避免拖动时背景显示黑色的问题divider
,设置分割线,#00000000
或@null
分割线被隐藏fadingEdge
,设置为none
,去除上边和下边的阴影scrollbars
,设置为none
,隐藏滚动条
2. ListView添加数据
ListView
通过setAdapter(ListAdapter)
方法设置数据,Adapter
需要继承ListAdapter
。
2.1 ArrayAdapter类
ArrayAdapter
继承BaseAdapter
类,其构造函数内,定义界面的resource
和textViewResourceId
,以及数据。
public ArrayAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull T[] objects) {
this(context, resource, 0, Arrays.asList(objects));
}
public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
@NonNull List<T> objects) {
this(context, resource, 0, objects);
}
public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
@IdRes int textViewResourceId, @NonNull List<T> objects) {
this(context, resource, textViewResourceId, objects, false);
}
getView(int, View, ViewGroup)
返回界面,如果mFieldId
(也就是textViewResourceId
)为0时,convertView
必须是TextView
,否则根据mFieldId
来查找TextView
。
public @NonNull View getView(int position, @Nullable View convertView,
@NonNull ViewGroup parent) {
return createViewFromResource(mInflater, position, convertView, parent, mResource);
}
private @NonNull View createViewFromResource(@NonNull LayoutInflater inflater, int position,
@Nullable View convertView, @NonNull ViewGroup parent, int resource) {
final View view;
final TextView text;
if (convertView == null) {
view = inflater.inflate(resource, parent, false);
} else {
view = convertView;
}
try {
if (mFieldId == 0) {
// If no custom field is assigned, assume the whole resource is a TextView
text = (TextView) view;
} else {
// Otherwise, find the TextView field within the layout
text = view.findViewById(mFieldId);
if (text == null) {
throw new RuntimeException("Failed to find view with ID "
+ mContext.getResources().getResourceName(mFieldId)
+ " in item layout");
}
}
} catch (ClassCastException e) {
Log.e("ArrayAdapter", "You must supply a resource ID for a TextView");
throw new IllegalStateException(
"ArrayAdapter requires the resource ID to be a TextView", e);
}
final T item = getItem(position);
if (item instanceof CharSequence) {
text.setText((CharSequence) item);
} else {
text.setText(item.toString());
}
return view;
}
代码调用
ListView listView = findViewById(R.id.list_view);
String[] data = new String[]{"Peter", "Lily", "Jack", "Mike"};
listView.setAdapter(new ArrayAdapter<>(this,
R.layout.list_view_item, R.id.tv_name, data));
list_view_item.xml
文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="#ffa6a5aa">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_marginLeft="15dp"
android:textSize="16sp"
android:textColor="#ffffffff" />
<TextView
android:id="@+id/tv_address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_marginRight="15dp"
android:textSize="16sp"
android:textColor="#ffcccccc" />
</RelativeLayout>
效果如下
2.2 SimpleAdapter类
SimpleAdapter
同样继承BaseAdapter
类,其构造函数内,同样定义了界面resource
,from
表示data中
数据key
,to
则是界面对应的id
。
public SimpleAdapter(Context context, List<? extends Map<String, ?>> data,
@LayoutRes int resource, String[] from, @IdRes int[] to) {
mData = data;
mResource = mDropDownResource = resource;
mFrom = from;
mTo = to;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
data
包含两种数据,分别以name
和address
为关键字表示,对应到界面。
List<Map<String, String>> data = new ArrayList<>();
Map<String, String> item = new HashMap<>();
item.put("name", "Peter");
item.put("address", "ShangHai");
data.add(item);
item = new HashMap<>();
item.put("name", "Lily");
item.put("address", "BeiJing");
data.add(item);
item = new HashMap<>();
item.put("name", "Jack");
item.put("address", "GuangZhou");
data.add(item);
item = new HashMap<>();
item.put("name", "Mike");
item.put("address", "ShengZhen");
data.add(item);
ListView listView = findViewById(R.id.list_view);
listView.setAdapter(new SimpleAdapter(this, data, R.layout.list_view_item,
new String[]{"name", "address"}, new int[]{R.id.tv_name, R.id.tv_address}));
效果如下
2.3 自定义CustomAdapter
CustomAdapter
同样继承BaseAdapter
,并且实现了getCount()
、getItem(int)
、getItemId(int)
和getView(int, View, ViewGroup)
方法。使用ViewHolder
可以减少内存。
public class CustomAdapter extends BaseAdapter {
private Context mContext;
List<Person> mData;
public CustomAdapter(Context context, List<Person> data) {
this.mContext = context;
this.mData = data;
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.listview_item, parent, false);
viewHolder = new ViewHolder();
viewHolder.tvName = convertView.findViewById(R.id.tv_name);
viewHolder.tvAddress = convertView.findViewById(R.id.tv_address);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
Person person = mData.get(position);
viewHolder.tvName.setText(person.name);
viewHolder.tvAddress.setText(person.address);
return convertView;
}
private static class ViewHolder {
TextView tvName;
TextView tvAddress;
}
}
数据类
class Person {
public String name;
public String address;
public Person(String name, String address) {
this.name = name;
this.address = address;
}
}
代码调用
ListView listView = findViewById(R.id.list_view);
listView.setAdapter(new CustomAdapter(this, Arrays.asList(new People[]{
new People("Peter", "ShangHai"),
new People("Lily", "BeiJing"),
new People("Jack", "GuangZhou"),
new People("Mike", "ShengZhen")})));
3. 监听事件
setOnItemClickListener(OnItemClickListener)
监听列表选择事件。
public interface OnItemClickListener {
void onItemClick(AdapterView<?> parent, View view, int position, long id);
}
setOnScrollListener(OnScrollListener)
监听列表滚动事件。
public interface OnScrollListener {
public void onScrollStateChanged(AbsListView view, int scrollState);
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount);
}
4. HeaderView和FooterView
列表有时需要添加一些表头和表尾,可以addHeaderView()
和addFootView()
来添加。
注意点就是这些方法需要在setAdapter(ListAdapter)
之前调用,而有了HeaderView
和FooterView
以后,列表长度也会相应增加。如添加了HeaderView
,HeaderView
的position
为0,列表中的数据相应加一。
addHeaderView(View v)
addHeaderView(View v, Object data, boolean isSelectable)
addFooterView(View v)
addFooterView(View v, Object data, boolean isSelectable)
如果需要动态显示和隐藏HeaderView
,不能直接设置HeaderView.setVisibility(View.GONE)
,那样会留下一片空白。也不能直接removeHeaderView(View v)
,因为不能再添加了。需要在HeaderView
外层添加HeaderParentView
。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/header_view"
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:gravity="center_vertical">
</LinearLayout>
</LinearLayout>
需要隐藏HeadView
时,调用header_view
的setVisibility(View.GONE)
方法
ListView listView = findViewById(R.id.list_view);
View headerParentView = getLayoutInflater().inflate(
R.layout.list_view_header_view, listView, false);
final View headerView = headerParentView.findViewById(R.id.header_view);
listView.addHeaderView(headerParentView, null, false);
headerView.setVisibility(View.GONE)
5. 去除ListView头部和尾部荧光效果
ListView
上拉到头部,下拉到尾部,继续拉会出现荧光效果。去除这种效果,设置overScrollMode
属性。
android:fadingEdge="none"
android:overScrollMode="never"
相关文章
Android ListView控件
Android ListView滚动条
Android 自定义下拉刷新列表