(1)BaseAdapter与ArrayAdapter的区别,应用场合区别。
个人理解:但凡需求需要重写ArrayAdapter的getView方法的。都不如用BaseAdapter简洁(注意不是BaseAdapter更好,要分场合,如果ListView的内容很多条,好几十条,上百条,据说用ArrayAdapter更好,没看源码。).
如果能MyExtendsArrayAdaptermAdapter=
newMyExtendsArrayAdapter(this,R.layout.simple_list_item_1,data);
如果能用系统的,而不是自定义的View。一步到位的,就优先用ArrayAdapter.
而且用BaseAdapter更省资源,因为ArrayAdapter继承于BaseAdapter.
如果ListView,GridView中的part,也就是自定义View涉及到的组件比较多,比较复杂的时候。用ArrayAdapter层次感个人感觉更好点。用BaseAdapter也可以。
Publicclass TestAdapter extends BaseAdapter{
//在构造方法中传入你需要的参数,自己随意定义类型和个数。
publicTestAdapter(x1,x2,x3....)
{
….
}
//继承BaseAdapter需要重写四个方法。比较重要的是getCount(),get
Publicint getCount(){
returnnum;//ListView,GridView等的内容的个数。num<=内容的个数。小于的话就显示不全
}
publicobject getItem(int positon){
//getItem方法不是在Baseadapter类中被调用的,而是在Adapterview.getItemAtPosition(position) 中被调用的。getItemAtPosition(position)是在setOnItemClickListener、setOnItemLongClickListener、setOnItemSelectedListener的点击选择处理事件中方便地调用来获取当前行数据的。
returnpositon;
}
publiclong getItemId(int position){
//该方法的返回值决定第position处的列表项的ID,某些方法(如onclicklistener的onclick方法)有id这个参数,而这个id参数就是取决于getItemId()这个返回值的。如:publicvoid onItemClick(AdapterView<?> parent, View view,intposition, longid)
returnposition;
}
publicView getView(int position,ViewconvertView,ViewGroup parent){
//根据构造方法传入的参数来获取到ListView,GridView中的内容。并根据positon的不同。用switch(position)来给每个内容赋予不同的属性。最后返回你的自定义View就可以了。
returnurView;
}
}
(2)ListView添加页眉,页脚
添加页脚:addFooterView
添加页眉:addHeaderView
方法两种:
//添加的view要从一个xml文件中解析出来,而不是当前的xml文件中的一个组件。
LayoutInflatermInflater=getLayoutInflater();
ViewmView=mInflater.inflate(R.layout.footer, null);
//两个方法的区别,前一种是可以选中的,后一种把boolean设置成false,就表示不可以选中。
mListView.addFooterView(mView);
mListView.addFooterView(mView,null,false);
//添加页眉页脚要在setAdapter前
mListView.setAdapter(adapter);
//因为是添加到listView中,所以页眉页脚相当于listview的一部分,是可以跟随手指一起滑动的。
而且会影响到listView的itemposition。这个在处理点击事件时要注意一下,而且listview.getCount()也会发生变化。详细用到时候再深究
(3)缓存的使用ListView中convertView和ViewHolder,优化效率
View类的setTag和getTag
源码如下:
protectedObjectmTag;
publicObject getTag() {
returnmTag;
}
publicvoidsetTag(finalObject tag) {
mTag= tag;
}
说白了就是存取一个任意对象(因为Object是所有类的父类)。为什么是final Object tag,final的意义是什么?
在方法参数前面加final关键字就是为了防止数据在方法体重被修改。
主要分为两种情况:第一,用final修饰基本数据类型;第二,用final修饰引用数据类型。
第一种情况,修饰基本数据类型,这时参数的值在方法体内是不能被修改的,即不能被重新赋值。否则编译就不通过。
第二种情况,修饰引用类型。这时参数变量所引用的对象是不能被改变的。但是对于引用数据类型,如果修改其属性的话是完全可以的。
所以,final这个关键字,想用的话就用基本数据类型,还是很有作用的。
比如下例中ViewHolder类对象给到View中的mTag,那么View中是不能出现mTag=viewHolder2.(也就是getView中不能出现view.setTag(viewHolder2),因为之前已经view.setTag(viewHolder)了,此时mTag已经是一个final对象了,不能第二次赋值或改变引用),但是view中是可以对mTag也就是viewHolder对象的属性进行操作的,比如mTag. fruitImage=xxx;(因为这样是没改变mTag这个final对象的引用的)。
说白了这么设计原因有个原因就是防止外面多次调用view.setTag方法。
当然,也考虑到多个参数的保存和获取。
public void setTag(int key, final Object tag)
这个方法是用来存多个对象的,key要求唯一,需要在res/values xml文件<item type="id" name="tag_first">
引用是R.id.tag_first.
详细怎么用回头用到的时候再深究。
publicclass FruitAdapter extends ArrayAdapter<Fruit> {
......
@Override
publicView getView(int position, View convertView,ViewGroup parent) {
Fruitfruit = getItem(position);
Viewview;
ViewHolderviewHolder;
if(convertView == null) {
view= LayoutInflater.from(getContext()).inflate(resourceId, null);
viewHolder= new ViewHolder();
viewHolder.fruitImage= (ImageView) view.findViewById
(R.id.fruit_image);
viewHolder.fruitName= (TextView) view.findViewById
(R.id.fruit_name);
view.setTag(viewHolder);//将ViewHolder存储在View中
}else {
view= convertView;
viewHolder= (ViewHolder) view.getTag(); // 重新获取ViewHolder,注意类型要转换
}
viewHolder.fruitImage.setImageResource(fruit.getImageId());
viewHolder.fruitName.setText(fruit.getName());
returnview;
}
classViewHolder {
ImageViewfruitImage;
TextViewfruitName;
}
}
因为在FruitAdapter的getView()方法中每次都将布局重新加载了一遍,并且通过findViewById()方法来获取控件实例。
优化后,布局之加载一次,获取控件实例也只进行一次。以后每次就是view.setText()等api来反复修改控件实例的属性。ViewHolder类是自己创建的内部类。
(4)屏蔽掉ListView的Item的点击效果
xml文件中ListView控件增加如下属性。
android:listSelector="@android:color/transparent"
这样ListViewItem依然可以响应点击事件,但是没有点击效果。
(5)ListView小技巧
设置单项高度
android:height是无效的。
正确的做法是在item的layout文件中,给item设定minHeight
隐藏ListView每个Item的分割线
ListView中每个Item项之间都有分割线,设置Android:footerDividersEnabled表示是否显示分割线,此属性默认为true。
1.不显示分割线只要在ListView控件中添加android:footerDividersEnabled="false"即可。
<ListView
android:id="@+id/local_groups_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:footerDividersEnabled="false"
/>
改变分割线颜色和宽度
2.改变ListView的分割线颜色和宽度,需要在布局中定义android:divider和android:dividerHeight属性。
<ListView android:id="@+id/local_groups_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="@color/divider_color"
android:dividerHeight="1px"
/>
自定义分割线(主要是控制分割线的左右padding)
创建分割线的布局文件:
list_item_divider.xml:
<?xml
version="1.0" encoding="UTF-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="15dp"
android:insetRight="15dp"
android:drawable="@color/line_gray">
</inset>
在listview的divider属性中引用这个布局
<ListView
android:id="@+id/listView1"
android:divider="@drawable/list_item_divider"
android:dividerHeight="1px"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>(6)ListView部分属性
可以做到消除上下拖动的阴影,自定义分割线高度,宽度,颜色(or图片)。自定义item选中的样式,也可以设置为透明,就看不到点击效果,但是依然响应事件。
android:fadingEdge
上边和下边有黑色的阴影android:fadingEdge="none"设置后没有阴影了。
android:divider
android:dividerHeight
android:listSelector="@color/pink"listView item 选中时的颜色。默认为橙黄底色。
android:cacheColorHint
如果你只是换背景的颜色的话,可以直接指定android:cacheColorHint为你所要的颜色;如果你是用图片做背景的话,那也只要将android:cacheColorHint指定为透明(#00000000)就可以了,当然为了美化是要牺牲一些效率的
(7)ListViewsetOnItemLongClickListenersetOnItemClickListener冲突
Item长按后,拿开手指依然会触发Item单击事件。
解决方法:setOnItemLongClickListener的returnfalse(默认)修改成returntrue.
(8)GridView,ListView的android:descendantFocusability属性
android:descendantFocusability=“xxx”;
xxx可以为:
beforeDescendants:viewgroup会优先其子类控件而获取到焦点
afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点
blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点
项目中的listview不仅仅是简单的文字,常常需要自己定义listview,自己的Adapter去继承BaseAdapter,在adapter中按照需求进行编写,问题就出现了,可能会发生点击每一个item的时候没有反应,无法获取的焦点。原因多半是由于在你自己定义的Item中存在诸如ImageButton,Button,CheckBox等子控件(也可以说是Button或者Checkable的子类控件),此时这些子控件会将焦点获取到,所以常常当点击item时变化的是子控件,item本身的点击没有响应。
找时间写个demo三个都试试。一般应该第一个和第三个用的多。应该就是与事件分发有关,之前解决过GridView的点击问题的。
实测,这个属性并不是写在listView控件中的,而是ListView对应的item.xml的容器中的。切记!
(9)setTextFilterEnabled
AbsListView.setTextFilterEnabled(true);
这个方法的作用是用来过滤选项的.
例如在软键盘上打出一个a,则会过滤掉除了a开头的所有选项.