附:适配器包括三种:
ArrayAdapter
SimpleAdapter
SimpleCursorAdapter
ListView允许用户通过手指上下滑动的方式,将屏幕外的数据滚动到屏幕内,同时屏幕原有数据滚出屏幕。
简单功能:建立一个简单的listview,可以滑动。
步骤:
1)在布局中加入listview控件
2)修改代码:
创建要传递给listview的数组;
这里借助ArrayAdapter适配器,把要传入的数组传给listview。适配器的三个参数为:当前上下文、listview子项布局的id、要适配的数据。
范例:
layout:
<ListView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/list_view" ></ListView>
activity:
public class ThirdActivity extends Activity{
private ListView mListview;
private String[] array = {"apple","banana","orange","pear","grape","strawberry","cherry","pear","ettre","rewy","rewyhrtwhj","rewytyrestre","rewytrw","trwhtrw","trewe4rty","rewytrew","rewyhtrw","trwyrtew"};
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
mListview=(ListView) findViewById(R.id.list_view);
//创建适配器,将array数据以安卓已写好的simple_list_item_1布局的格式做好。
ArrayAdapter<String> adapter = new ArrayAdapter<String>(ThirdActivity.this, android.R.layout.simple_list_item_1, array);
//将创建好的适配器设置给listview
mListview.setAdapter(adapter);
}
}
结果:
补充:可以将simple_list_item_1布局更改,但id名称一定不能改变,以为android默认arrayadapter找这个id。
SimpleAdapter(context,数据,item布局,from,to)
注:1)这里的数据类型是list
//1.listView
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" >
<ListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="match_parent" ></ListView>
</LinearLayout>
//2.自定义的item布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" >
<TextView android:id="@+id/name" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" />
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical" >
<TextView android:id="@+id/age" android:layout_width="wrap_content" android:layout_height="0dp" android:layout_weight="1" />
<TextView android:id="@+id/sex" android:layout_width="wrap_content" android:layout_height="0dp" android:layout_weight="1" />
</LinearLayout>
<TextView android:id="@+id/hobby" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" />
</LinearLayout>
//3.activity界面代码
public class ThirdActivity extends Activity{
private ListView mListView;
private String[] array = {"apple","pear","orange","neat","watar"};
private List<Map<String,String>> list ;//这里list选用ArrayList,map类型选择HashMap
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
mListView = (ListView) findViewById(R.id.listview);
//ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.list_item, array);
//mListView.setAdapter(adapter);
//SimpleAdapter演示:传入的数据时MAP类型
initList();
SimpleAdapter adapter = new SimpleAdapter(this,list,R.layout.simple_list,new String[]{"name","age","sex","hobby"},new int[]{R.id.name,R.id.age,R.id.sex,R.id.hobby});
mListView.setAdapter(adapter);
}
//对数据进行初始化,不用返回值
public void initList(){
list = new ArrayList();//对list进行初始化,新建ArrayList
HashMap<String, String> zhangsan = newHash("张三","34","男","喜欢运动");
HashMap<String, String> lisi = newHash("李四三","34","男","喜欢运动");
HashMap<String, String> zhaoliu = newHash("赵六","34","男","喜欢运动");
HashMap<String, String> wangwu = newHash("王五","34","男","喜欢运动");
HashMap<String, String> yuge = newHash("宇哥","34","男","喜欢运动");
list.add(zhangsan);
list.add(lisi);
list.add(zhaoliu);
list.add(wangwu);
list.add(yuge);
}
public HashMap<String, String> newHash(String name,String age,String sex,String hobby){ //创建一个可以建立HashMap<String, String>对象的方法
HashMap<String, String> zhangsan= new HashMap<String, String>();
zhangsan.put("name", name);
zhangsan.put("age", age);
zhangsan.put("sex", sex);
zhangsan.put("hobby", hobby);
return zhangsan;
}
}
范例演示:
功能:出现的listview,每条包括文字和图片
思路:需要自定义的item的类,以及它的layout。需要自定义的适配器。最后在代码中利用适配器,将数据都加到listview中即可。
1.自定义的fruit类:
/**一:自定义的类:定义水果中的两个属性,名称和图片的id * 构造器传入,并定义获取它们的方式 * */
public class Fruit {
private String name;
private int imageId;
public Fruit(String name,int imageId){
this.name=name;
this.imageId=imageId;
}
public String getName() {
return name;
}
public int getImageId() {
return imageId;
}
}
2.item的布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" >
<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/fruit_img"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:gravity="center_horizontal" android:id="@+id/fruit_name"/>
</LinearLayout>
3.自定义的适配器:
/**二:自定义适配器,泛型Fruit。 * 重写父类构造方法,将上下文,子项布局的id,以及数据都传进来。 * 重写方法getView,这个方法在每个子项被滚动到屏幕内的时候会被调用。 * */
public class FruitAdapter extends ArrayAdapter<Fruit>{
private int resourceId;
public FruitAdapter(Context context, int textViewResourceId, List<Fruit> objects) {
super(context, textViewResourceId, objects);
resourceId=textViewResourceId;//将传进来的子项的id传给此类的成员变量resourceId
}
//重写方法getView
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//1.获取当前项的Fruit实例
Fruit fruit = getItem(position);
//2.利用LayoutInflater为子项加载我们传入的布局。
View view = LayoutInflater.from(getContext()).inflate(resourceId, null);//********************重要
//3.分别获取layout中定义的图片和text实体。
ImageView image_fruit = (ImageView) view.findViewById(R.id.fruit_img); //这里的view就是上句得到的。
TextView text_fruit = (TextView) view.findViewById(R.id.fruit_name);
//4.然后将图片资源和名称分别设置到上面的实例中
image_fruit.setImageResource(fruit.getImageId());//传入的参数是上面获得的FFruit实体中的getImageId()的方法
text_fruit.setText(fruit.getName());
return view; //返回设置好的view布局
}
}
4.使用:
public class ThirdActivity extends Activity{
//1.创建list,泛型Fruit
private List<Fruit> fruitList = new ArrayList<Fruit>();
private ListView mListview;//2.真正使用的listview
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
mListview=(ListView) findViewById(R.id.list_view);
initFruits();//3.初始化数据,下面有函数
//4.建立适配器,传入上下文,自定义的item布局,以及list数据,
FruitAdapter adapter = new FruitAdapter(ThirdActivity.this, R.layout.activity_item, fruitList);
mListview.setAdapter(adapter);
//添加点击事件
mListview.setOnItemClickListener(new OnItemClickListener() {//list的点击事件,用setOnItemClickListener
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
Fruit fruit = fruitList.get(position);//通过get判断点击的是哪个子项,获取到相应的水果类
Toast.makeText(ThirdActivity.this, fruit.getName(), Toast.LENGTH_LONG).show();//将水果的名称显示出来
}
});
}
private void initFruits() {//初始化的list函数
fruitList.add(new Fruit("apple",R.drawable.main_icon01));
fruitList.add(new Fruit("banana",R.drawable.main_icon02));
fruitList.add(new Fruit("eurq",R.drawable.main_icon03));
fruitList.add(new Fruit("etw",R.drawable.main_icon04));
fruitList.add(new Fruit("ewt",R.drawable.main_icon05));
fruitList.add(new Fruit("er",R.drawable.main_icon06));
fruitList.add(new Fruit("wrt",R.drawable.main_icon07));
fruitList.add(new Fruit("fsh",R.drawable.main_icon08));
fruitList.add(new Fruit("sh",R.drawable.main_icon09));
fruitList.add(new Fruit("fhgdfg",R.drawable.a));
fruitList.add(new Fruit("thrs",R.drawable.selected));
fruitList.add(new Fruit("sd",R.drawable.c));
fruitList.add(new Fruit("dfshb",R.drawable.d));
}
}
自定义适配器的另种写法:老师所教,继承BaseAdapter抽象类。
public class MyAdapter extends BaseAdapter{
private List<Student> list;
private LayoutInflater flater;
//构造器
public MyAdapter(LayoutInflater flater,List<Student> list){
this.flater=flater;
this.list=list;
}
@Override
public int getCount() {
// 返回list可显示的数据个数
return list.size();
}
@Override
public Object getItem(int arg0) {
// 返回索引
return arg0;
}
@Override
public long getItemId(int arg0) {
// 返回索引号
return arg0;
}
@Override
public View getView(int arg0, View arg1, ViewGroup arg2) {
//返回view
View view = flater.inflate(R.layout.simple_list, null);//flater中的inflate()方法获得item的view
Student student = list.get(arg0);//获得list中mouposition的student
//下面将list中的数据存到相应的view中
ImageView image = (ImageView) view.findViewById(R.id.image);
TextView name = (TextView) view.findViewById(R.id.name);
TextView age = (TextView) view.findViewById(R.id.age);
TextView sex = (TextView) view.findViewById(R.id.sex);
TextView hobby = (TextView) view.findViewById(R.id.hobby);
image.setImageResource(student.getImg());
name.setText(student.getName());
age.setText(student.getAge());
hobby.setText(student.getHobby());
return view;
}
}
在使用时利用:
LayoutInflater flater = getLayoutInflater();
获得flater传入自定义适配器中。
ListView不允许使用onClickListener,会报错,使用:
setOnItemClickListener 点击事件
setOnItemLongListener 长按事件
MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。
(控制器Controller)- 负责转发请求,对请求进行处理。
(视图View) - 界面设计人员进行图形界面设计。
(模型Model) - 程序员编写程序应有的功能(实现算法等等)、数据库专家进行数据管理和数据库设计(可以实现具体的功能).
附:这里用到mvc模式,规范写法:
包下建立modle文件:用于存放数据,这里放Student类等数据。
包下建立adapter文件:用于存放所有的自定义的适配器。
layout布局中建立item子项的布局文件。
想要对ListView的外观、行为进行定制,需要把ListView作为AdapterView使用,通过Adapter控制每个列表的外观和行为。
而Adapter本身只是个接口,且派生了两个子接口。且从上表可以看出:几乎所有的Adapter都继承了BaseAdapter,而BaseAdapter同时实现了两个接口,因此BaseAdapter及其子类可以同时为AbsListView和AbsSpinner提供列表项。
所以在自定义适配器时,也要继承BaseAdapter类。
由于在上面定制界面时,每次适配子项都要使用inflate()来获取view,这样十分消耗内存,所以这里使用converView来改进。
思路:利用converView,它表示当界面向上滑屏时,离开界面的view跑到下面成为converView,再被赋值,重新进入视线,向下滑屏也同理。这里只需判断converView的值是否为空,如果不是空再建立view界面(用flater.inflate()), 范例中将建立的view也都赋值给converView,它会再滑到视线内,如果屏幕满了,它就不为空了。
这里的getView()方法中就已经传入了converView,直接利用。
//自定义适配器中:
public View getView(int position, View converView, ViewGroup parent) {
if(converView==null){
converView = flater.inflate(R.layout.item, null);//3.如果converView为空,建立view的同时,也将findview存到vh中
ImageViewima ge = (ImageView) converView.findViewById(R.id.imageView);
TextView name = (TextView) converView.findViewById(R.id.textView_name);
TextView age = (TextView) converView.findViewById(R.id.textView_age);
CheckBox checkBox=(CheckBox) converView.findViewById(R.id.checkbox);
}
}
//之后可以将数据添加到上面得到的控件中。所以只有converView为空时,创建view,否则,直接传入数据。
结果:
可以通过android studio观察内存变化,这里不再演示。
由于上面的范例,在自定义适配器时,及时view界面不需要一直创建,但findview仍然会耗时,所以这里利用viewHolder类(默认此名称),将控件口存到其中,用view一直带着它,用时get得到即可。
public class viewHolder{//1.创建viewHolder,因为每个界面view的布局都是一样的,且findview耗时,这里讲找到的控件都存到viewHolder中。
ImageView image;
TextView name;
TextView age;
CheckBox checkBox;
}
//getView中:
if(converView==null){
vh = new viewHolder();//只有converView为空时,才新建
converView = flater.inflate(R.layout.item, null);//3.如果converView为空,建立view的同时,也将findview存到vh中
vh.image = (ImageView) converView.findViewById(R.id.imageView);
vh.name = (TextView) converView.findViewById(R.id.textView_name);
vh.age = (TextView) converView.findViewById(R.id.textView_age);
vh.checkBox=(CheckBox) converView.findViewById(R.id.checkbox);
converView.setTag(vh);//将viewHolder放入converView中
}else{
vh = (viewHolder) converView.getTag();//如果converView不为null,则直接获取到viewHolder即可,无需再寻找控件。
}
由于list子项中存在CheckBox,Button,RadioButton时,屏幕获得用户触摸或点击后,将事件传给Activity,然后Activity传给它的layout,由于布局中有上面所说的控件,它们会吃掉事件。
处理方法:
在layout控件中设置:
focusable=”false” //表示只要不点击控件,就不接收事件。这样listview就可以接收点击事件。
1)避免滑屏时有版本低的会有变黑边框,在listView中加一句:
cacheColorHint=”@color/” //加个颜色
2)当数据中复制了相同的对象时,在选中复选框时,要动态的使所有相同的对象都被选中,需要来次实时刷屏操作。
在每次更改需要刷屏,否则不能及时响应:
在自定义适配器中:
notifyDataSetChanged(); //用于刷屏
1)点击list子项,使复选框获取到事件。
2)用一个数组去存放复选框的选中情况。
3)加分隔线:
<ListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="match_parent" android:divider="#00ff00" android:dividerHeight="5dp" ></ListView>
4)增加header和foot。但注意:
1>增加了header后,在listView的点击事件中,必须要让position-1,因为在listView中header也占position了,
2>必须在添加适配器之前,添加header
增加header实例:
LayoutInflater flater = getLayoutInflater();//获得页面的flater
mViewHeader = flater.inflate(R.layout.activity_header, null);//添加自定义的布局,或者android内部提供的
mlistview.addHeaderView(mViewHeader);//将header添加给listview
汇总后的范例:
layout:
//activity_header.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >
<Button android:id="@+id/btn_checkedAll" android:layout_width="match_parent" android:layout_height="match_parent" android:text="@string/checkAll" />
</LinearLayout>
-------------------------------------------
//activity_foot.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >
<Button android:id="@+id/btn_checked_fan" android:layout_width="match_parent" android:layout_height="match_parent" android:text="@string/checked_fan"/>
</LinearLayout>
------------------------------------------------
//activity_item.xml:(listview中子项布局)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" android:background="@drawable/item_selecter" >
<ImageView android:id="@+id/imageView" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<TextView android:id="@+id/textView_name" android:layout_width="wrap_content" android:layout_height="wrap_content" />
<TextView android:id="@+id/textView_age" android:layout_width="wrap_content" android:layout_height="wrap_content" />
<CheckBox android:id="@+id/checkbox" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="请选择:" android:focusable="false" />
</LinearLayout>
model:数据
//Student.java (数据类)
public class Student {
private String name;
private String age;
private int image;
private boolean checked;
public Student(String name,String age,int image){
this.age=age;
this.image=image;
this.name=name;
}
public int getImage() {
return image;
}
public String getName() {
return name;
}
public String getAge() {
return age;
}
public Boolean getChecked() {
return checked;
}
public void setChecked(Boolean checked) {
this.checked = checked;
}
}
自定义适配器:
//MyAdapter.java
public class MyAdapter extends BaseAdapter{
private List<Student> list;//传过来的数据
private LayoutInflater flater;
private boolean[] mCheckedPosition;
public MyAdapter(LayoutInflater flater,List<Student> list){
this.flater=flater;
this.list=list;
mCheckedPosition = new boolean[list.size()];
}
public void isChecked(int position){//list点击时,将位置position传过来
mCheckedPosition[position]=!mCheckedPosition[position];
notifyDataSetChanged();//重点。。。
}
//全选时调用
public void checkedALL(){
for (int i = 0; i < mCheckedPosition.length; i++) {
mCheckedPosition[i]=true;
notifyDataSetChanged();
}
}
//反选时调用
public void checkedFan(){
for (int i = 0; i < mCheckedPosition.length; i++) {
mCheckedPosition[i]=!mCheckedPosition[i];
notifyDataSetChanged();
}
}
@Override
public int getCount() {
// 指定一共包含多少选项
return list.size();
}
@Override
public Object getItem(int arg0) {
return arg0;
}
@Override
public long getItemId(int positionId) {
// 返回值作为列表项的ID
return positionId;
}
@Override
public View getView(final int position, View converView, ViewGroup parent) {//第一个参数:是当前子项的position,第二个参数是converView,第三个参数是parent父类控件
// 该方法返回的view将作为列表框。
Student student = list.get(position);
viewHolder vh=null;//2.viewHolder初始化null
/**利用converView,它表示当界面向上滑屏时,离开界面的view跑到下面成为converView,再被赋值,重新进入视线,向下滑屏也同理。 * 这里只需判断converView的值是否为空,如果不是空再建立view界面(用flater.inflate()), * 范例中将建立的view也都赋值给converView,它会再滑到视线内,如果屏幕满了,它就不为空了。 * */
if(converView==null){
vh = new viewHolder();
converView = flater.inflate(R.layout.item, null);//3.如果converView为空,建立view的同时,也将findview存到vh中
vh.image = (ImageView) converView.findViewById(R.id.imageView);
vh.name = (TextView) converView.findViewById(R.id.textView_name);
vh.age = (TextView) converView.findViewById(R.id.textView_age);
vh.checkBox=(CheckBox) converView.findViewById(R.id.checkbox);
converView.setTag(vh);//将viewHolder放入converView中
}else{
vh = (viewHolder) converView.getTag();//如果converView不为null,则直接获取到viewHolder即可,无需再寻找控件。
}
vh.image.setImageResource(student.getImage());
vh.name.setText(student.getName());
vh.age.setText(student.getAge());
// vh.checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {//对复选框设置监听事件,判断是否被选中。//将结果赋给这个子项的Checked;
//
// @Override
// public void onCheckedChanged(CompoundButton arg0, boolean isChecked) {
// list.get(position).setChecked(isChecked);
// notifyDataSetChanged();//对象一样的时候让所有监听的动作一样。用来刷屏
//
//
// }
// });
//
student.setChecked(mCheckedPosition[position]);
vh.checkBox.setChecked(student.getChecked());
return converView;
}
public class viewHolder{//1.创建viewHolder,因为每个界面view的布局都是一样的,且findview耗时,这里讲找到的控件都存到viewHolder中。
ImageView image;
TextView name;
TextView age;
CheckBox checkBox;
}
}
主界面:
public class SecondActivity extends Activity{
private List<Student> list;
private ListView mlistview;
private CheckBox mCheckBox;
private MyAdapter adapter;
private View mViewHeader;
private View mViewFoot;
private Button mButtonCheckedAll;
private Button mButtonCheckedFan;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
mlistview = (ListView) findViewById(R.id.listview);
mCheckBox=(CheckBox) findViewById(R.id.checkbox);
LayoutInflater flater = getLayoutInflater();
mViewHeader = flater.inflate(R.layout.activity_header, null);
mViewFoot = flater.inflate(R.layout.activity_foot, null);
mlistview.addHeaderView(mViewHeader);
mlistview.addFooterView(mViewFoot);
mButtonCheckedAll = (Button) mViewHeader.findViewById(R.id.btn_checkedAll);
mButtonCheckedFan = (Button) mViewFoot.findViewById(R.id.btn_checked_fan);
mButtonCheckedAll.setOnClickListener(new OnClickListener() {//点击全选按钮时,使list中所有checkbox被选中。
@Override
public void onClick(View arg0) {
adapter.checkedALL();//调用此方法,将存放复选框是否选中的布尔类型都变为true
}
});
mButtonCheckedFan.setOnClickListener(new OnClickListener() {//点击取反按钮时,反选
@Override
public void onClick(View arg0) {
adapter.checkedFan();
}
});
init();//初始化数据
adapter = new MyAdapter(flater, list);
//lisiview点击事件
mlistview.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position,
long arg3) {
adapter.isChecked(position-1);//当增加了header时,position必须要-1。
}
});
mlistview.setAdapter(adapter);
}
public void init(){
list = new ArrayList<Student>();
list.add(new Student("张三", "34", R.drawable.b));
list.add(new Student("的撒三", "34", R.drawable.h));
list.add(new Student("爱国", "8", R.drawable.d));
list.add(new Student("格式", "34", R.drawable.e));
list.add(new Student("多个", "34", R.drawable.c));
list.add(new Student("张三", "34", R.drawable.b));
list.add(new Student("的撒三", "34", R.drawable.h));
list.add(new Student("爱国", "8", R.drawable.d));
list.add(new Student("格式", "34", R.drawable.e));
list.add(new Student("多个", "34", R.drawable.c));
list.add(new Student("张三", "34", R.drawable.b));
list.add(new Student("的撒三", "34", R.drawable.h));
list.add(new Student("爱国", "8", R.drawable.d));
list.add(new Student("格式", "34", R.drawable.e));
list.add(new Student("多个", "34", R.drawable.c));
}
}