ListView这个列表控件,是我们在开发当中使用频率比较高的一个控件。
既然是使用频率比较高,那么我们就有必要将它的使用方式保存,方便以后直接复制粘贴,把注意力放在架构上面,不用经常做代码搬运工(重复搬运)。
当然Android的API也提供了许多创建ListView适配器的快捷方式。例如ArrayAdapter、SimpleAdapter、SimpleCursorAdapter等。但是在日常的开发当中,我是从来不会使用系统自带的适配器。毕竟一个项目当中,大部分列表Item的高度、容纳的控件数量、控件类型、逻辑处理、事件的处理等等都是不同的,使用系统自带的完全不能胜任。
套用一句俚语:一切不以实际项目为例子的Sample都是耍*流*氓^_^
今天的简单实例为百度地图-收藏夹页面的收藏点列表的仿写(只是列表哟),下面我们先来看看原装正品效果图动画:
怎么样,够简单吧,不过虽然简单,却不能使用系统提供给我们的适配器来做,我们来自定义适配器。
一、纵观全局—-我们先来分析一下页面有哪些元素
1、一个列表(费话,我们就是来做列表的!^_^)。
2、一个餐厅名称、一个收藏时间、一个右箭头。
3、一条分隔线(这一个千万忘不得)。
4、点击Item会有交互颜色变化。
二、技术选型
1、这一步是不可少的哈,因为实现列表,我们有多种方式,ListView可以,RecyclerView也可以,当然硬布局+ScrollView也可以(这一个估计没人这么做)等等。这里,我们使用ListView。没什么原因,就因为今天是ListView的实例。^_^
2、名称和时间肯定使用TextView了。右箭头使用ImageView,由于这个箭头只是一个标识作用,没有集成事件之类的,所以不会选择ImageButton、Button等控件。
3、分隔线,这个就有讲究了。我们仔细观察,这个分隔线是从左到右,横跨整个列表的。实现它的方法,至少有两种:(1)使用Listview自带的divder. (2)写一个View到Item布局当中。
如果这个分隔线不是横跨整个列表,而是有左边距或右边距呢,比如分隔线是和文字以及时间控件左对齐的呢,我们就只能写到Item布局当中了。
4、选择使用Selector。
三、码代码
1、构造数据,模拟好像是在线获取的数据,这里我们封闭一个数据获取的方法即可,所有的数据增删查改等都在此方法内进行。
/**
* 数据封装,模拟从网络上获取到的数据
*
* @return 返回数据列表
*/
private List<RestaurantBean> getDatasFromNetwork() {
for (int i = 0; i < Constants.PLACE.length; i++) {
RestaurantBean restaurant = new RestaurantBean();
restaurant.setPlace(Constants.PLACE[i]);
restaurant.setTime(Constants.TIME[i]);
datas.add(restaurant);
}
//刷新列表,如果是真实的网络数据,则放到请求回调函数当中使用。
//注意如果是在异步线程中,应该怎么使用?它必须在主线程中执行!!
listViewSimpleAdapter.notifyDataSetChanged();
return datas;
}
以下附方法内使用到的常量:
package oliver.zhantao.oliverproject.constants;
/**
* 存放常量类
*
* Created by ZhanTao on 2017/4/17.
*/
public class Constants {
//地点列表
public static final String PLACE[] = {
"德克士(新世幻环球中心店)", "肯德基(九方餐厅)", "第18区海鲜拼盘", "邓家面馆",
"锦水缘餐厅", "麦地里(中海店)", "可可豆汤", "临江门火锅店",
"若水河鲜", "自贡鸿鹤鲜锅兔", "又见曾毛肚老火锅"
};
//时间列表
public static final String TIME[] = {
"2017-04-08" , "2017-04-09", "2017-04-10", "2017-04-11",
"2017-04-12", "2017-04-13", "2017-04-14" , "2017-04-15",
"2017-04-16", "2017-04-17", "2017-04-18"
};
}
以下附方法内使用到的实体类:
package oliver.zhantao.oliverproject.listview;
import java.io.Serializable;
/**
* 用于存放保存餐厅的地点和时间的实体类。
*
* Created by ZhanTao on 2017/4/17.
*/
public class RestaurantBean implements Serializable {
//地点字段
private String place;
//收藏时间字段
private String time;
public String getPlace() {
return place;
}
public void setPlace(String place) {
this.place = place;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}
2、构建一个ListViewSimpleActivity
package oliver.zhantao.oliverproject.listview;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
import oliver.zhantao.oliverproject.R;
import oliver.zhantao.oliverproject.constants.Constants;
/**
* 实战项目中简单的列表实现,自定义适配器。
* 仿写百度地图当中,收藏夹里面,收藏点的列表实现。
* 一切脱离实战的实例,都是耍流氓。
* <p>
* Created by ZhanTao on 2017/4/14.
*/
public class ListViewSimpleActivity extends AppCompatActivity {
private ListView listViewSimple;
private ListViewSimpleAdapter listViewSimpleAdapter;
private List<RestaurantBean> datas = null;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_listview_simple);
datas = new ArrayList<>();
//1、找到布局当中的列表控件
listViewSimple = (ListView) findViewById(R.id.listViewSimple);
//2、创建适配器对象, 上下文必须传(非常有用)、数据必须传
listViewSimpleAdapter = new ListViewSimpleAdapter(ListViewSimpleActivity.this, datas);
//3、将适配器与listview进行绑定
listViewSimple.setAdapter(listViewSimpleAdapter);
//4、构造数据、刷新列表
getDatasFromNetwork();
}
}
3、建立activity的布局文件activity_listview_simple
有人可能会疑惑:ConstraintLayout这个是什么布局。你可以将它改为RelativeLayout或LinearLayout,这个布局我会在以后的文章中介绍到。
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="oliver.zhantao.oliverproject.listview.ListViewSimpleActivity">
<ListView
android:id="@+id/listViewSimple"
android:layout_width="0dp"
android:layout_height="0dp"
android:listSelector="@drawable/listviewsimple_bg_selector"
android:divider="@color/transparent_20"
android:dividerHeight="@dimen/px_1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
以上布局文件要注意几个要点:
(1)分隔线的粗细:dividerHeight
(2)分隔线的颜色:divider
(3)点击Item后交互变化:listSelector
以下来制作:listviewsimple_bg_selector
颜色值就自己定义:以下color_221E90FF名字当中,221E90FF就是颜色值。
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/color_221E90FF" android:state_pressed="true" />
<item android:drawable="@color/transparent" />
</selector>
4、自定义Adapter,按照顺序,得先把优化框架搭上,这个是不能少的。然后再是填数据,附加事件
package oliver.zhantao.oliverproject.listview;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.List;
import oliver.zhantao.oliverproject.R;
/**
* 餐厅列表适配器,在这里将数据与控件进行绑定
* <p>
* 项目中都是自定义适配器,很少用到系统提供的简易适配器。
* 所以果断抛弃系统的简易适配器,自定义想咋样就咋样,一个字,爽^_^
* <p>
* Created by ZhanTao on 2017/4/17.
*/
public class ListViewSimpleAdapter extends BaseAdapter {
private Context mContext;
//餐厅列表
private List<RestaurantBean> restaurantList;
private LayoutInflater mInflater;
public ListViewSimpleAdapter(Context context, List<RestaurantBean> restaurantList) {
this.mContext = context;
this.restaurantList = restaurantList;
mInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return restaurantList.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 holder;
//1、优化框架搭起
if (convertView == null) {
convertView = mInflater.inflate(R.layout.activity_listview_simple_item, null);
holder = new ViewHolder();
holder.place = (TextView) convertView.findViewById(R.id.resturant_place);
holder.time = (TextView) convertView.findViewById(R.id.resturant_time);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
//2、绑定数据到控件
bindViewData(position, convertView, holder);
//3、绑定监听事件
bindViewClickListener(position, convertView, holder);
return convertView;
}
class ViewHolder {
private TextView place;
private TextView time;
}
/**
* 绑定数据到控件,在这里做统一处理,方便数据抽离
*
* @param position 列表索引
* @param convertView 每个position对应的itemView
* @param holder holder对象
*/
private void bindViewData(int position, View convertView, ViewHolder holder) {
holder.place.setText(restaurantList.get(position).getPlace());
holder.time.setText("时间:" + restaurantList.get(position).getTime());
}
/**
* 绑定控件的各种View的事件,在这里做统一处理,比如点击事件,长安事件。
*
* @param position 列表索引
* @param convertView 每个position对应的itemView
* @param holder holder对象
*/
private void bindViewClickListener(int position, View convertView, ViewHolder holder) {
}
}
5、编写Item布局文件activity_listview_simple_item
资源icon_right_arrow,大家都自己去各种app当中扒。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/dp_10"
android:paddingTop="@dimen/dp_10">
<ImageView
android:id="@+id/img_right_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/dp_16"
android:layout_marginRight="@dimen/dp_16"
android:src="@drawable/icon_right_arrow" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/dp_16"
android:layout_toLeftOf="@id/img_right_arrow"
android:orientation="vertical">
<TextView
android:id="@+id/resturant_place"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/color_AA000000"
android:textSize="@dimen/dp_14" />
<TextView
android:id="@+id/resturant_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_5"
android:textSize="@dimen/dp_12" />
</LinearLayout>
</RelativeLayout>
下面我们来看看代码运行后的效果图:
以上,完了。代码贴完就完了。如有问题或好的建议希望大家留言,感激。
作者:Amir
博客:http://blog.csdn.NET/amir_zt/
以上原创,转载请注明出处,谢谢。
http://blog.csdn.net/amir_zt/article/details/70240519