Android开发笔记(三十八)列表类视图
2016-01-04 16:30
393 查看
AdapterView
AdapterView顾名思义是适配器视图,Spinner、ListView和GridView都间接继承自AdapterView,这三个视图都存在多个元素并排展示的情况,所以需要引入适配器模式。适配器视图的特点有:
1、定义了适配器的设置方法setAdapter,以及获取方法getAdapter。适配器用于传入视图展示需要的相关数据。
2、定义了一个数据观察者AdapterDataSetObserver,用于在列表数据发生变化时,可以通过notifyDataSetChanged方法来更新视图。
3、定义了单个元素的点击、长按、选中事件。其中点击方法为setOnItemClickListener,点击监听器为OnItemClickListener;长按方法为setOnItemLongClickListener,长按监听器为OnItemLongClickListener;选中方法为setOnItemSelectedListener,选中监听器为OnItemSelectedListener。
Adapter
适配器Adapter与适配视图是配合使用的,每个适配类视图都要搭配相应的适配器,才能够正常工作。Adapter派生出两个接口SpinnerAdapter和ListAdapter,然后BaseAdapter又同时实现了SpinnerAdapter和ListAdapter,所以实际开发中用的是BaseAdapter及其派生出的子类。一般情况下自定义适配器继承自BaseAdapter就够用了,当然Android为了方便懒人,专门扩展了两种简单易用的适配器,如ArrayAdapter用于每行只显示文本的情况,而SimpleAdapter用于每行显示左图标右文本的情况。实际开发中,ArrayAdapter多用于Spinner,但是SimpleAdapter却很少使用。像ListView和GridView一般都是直接使用BaseAdapter,并不使用布局过于简单的SimpleAdapter。
Spinner
Spinner是下拉框,用于从一串列表中选择某项。下面是Spinner常用的属性和方法:xml布局上的属性设置:
prompt : 指定弹窗的标题视图,在spinnerMode=dialog时有效。该属性值不可直接填字符串,但可通过"@string/..."方式来指定标题文字。
spinnerMode : 下拉列表的显示样式,有dialog弹窗和dropdown下拉两种。不过考虑到用户体验,实际开发中一般用dialog。spinnerMode只能在xml中设置,不能在代码中设置。
代码中的方法:
setPrompt : 设置标题文字。
setPromptId : 设置标题视图的资源ID。
setSelection : 设置当前选中哪项。
setAdapter : 设置适配器。源码中的适配器类型是SpinnerAdapter,但该类用起来很麻烦,所以实际中用的一般是ArrayAdapter<String>,ArrayAdapter可以直接传入一个字符串数组。
setOnItemSelectedListener : 设置下拉列表的选中监听器。
下面是Spinner调用的代码例子:
ArrayAdapter<String> starAdapter = new ArrayAdapter<String>(this, R.layout.spinner_item, starArray); starAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item); Spinner sp = (Spinner) findViewById(R.id.sp_hello); sp.setPrompt("请选择行星"); sp.setAdapter(starAdapter); sp.setOnItemSelectedListener(new MySelectedListener()); private String[] starArray = {"水星", "金星", "地球", "火星", "木星", "土星"}; class MySelectedListener implements OnItemSelectedListener { public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { Toast.makeText(MainActivity.this, "您选择的是"+starArray[arg2], Toast.LENGTH_LONG).show(); } public void onNothingSelected(AdapterView<?> arg0) { } }
代码中用到的spinner_item元素布局的示例如下:
<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/text1" style="?android:attr/spinnerItemStyle" android:singleLine="true" android:layout_width="match_parent" android:layout_height="wrap_content" android:ellipsize="marquee" android:textAlignment="inherit" android:textSize="17sp" android:textColor="#0000ff" />上面这个xml布局用到了TextView的三个新属性,说明如下:
singleLine : 指定是否单行显示,取值true表示单行,false表示多行。代码中对应的方法是setSingleLine。
ellipsize : 指定字符超出TextView区域时的显示方式,取值说明如下:start表示在字符串开头显示省略号,end表示在字符串末尾显示省略号,middle表示在字符串中间显示省略号,marquee表示以跑马灯方式显示字符串(即从左向右循环滚动,跑马灯方式需同时指定singleLine为true)。代码中对应的方法是setEllipsize。
textAlignment : 指定文本的对齐方式,常见的取值说明如下:inherit表示继承上级视图的对齐方式,center表示文本居中对齐,textStart表示文本开头对齐,textEnd表示文本末尾对齐,viewStart表示视图开头对齐,viewEnd表示视图末尾对齐。该属性在API17后增加,即Android4.2.2以上版本才支持。代码中对应的方法是setTextAlignment。
ListView
ListView是列表视图,用于分行显示列表信息。下面是ListView常用的属性和方法:ListView的属性和方法
xml布局上的属性设置:divider : 指定分隔线的图形。如需取消分隔线,可设置该属性值为@null
dividerHeight : 指定分隔线的高度。注意如果divider设置为@null时,就不可将dividerHeight设置为大于0dp的数值,因为这样可能导致末尾的元素显示不全。
headerDividersEnabled : 指定是否显示列表开头的分隔线。但实际开发中发现这个设置不起作用,即使该属性设置为true,开头也不会显示分隔线。查看ListView的源码,发现分隔线是画在子视图的下方,所以列表上方的分隔线就画不出来了。有种情况是例外,就是如果stackFromBottom设置为true,表示列表从下往上显示,那么此时会显示列表上方的分隔线,而不会显示列表下方的分隔线了。
footerDividersEnabled : 指定是否显示列表末尾的分隔线。
stackFromBottom : 指定列表项是否从下往上显示。
代码中的方法:
setDivider : 设置分隔线的图形。
setDividerHeight : 设置分隔线的高度。
setHeaderDividersEnabled : 设置是否显示列表开头的分隔线。该方法实际上不起作用。
setFooterDividersEnabled : 设置是否显示列表末尾的分隔线。
setStackFromBottom : 设置列表项是否从下往上显示。
setAdapter : 设置适配器。ListView使用的适配器一般继承自BaseAdapter。
setOnItemClickListener : 设置点击事件的监听器。
setOnItemLongClickListener : 设置长按事件的监听器。
总结ListView的属性设置有两个注意点(不知算不算Android的bug,呵呵):
1、divider设置为@null时,就不能再设置dividerHeight为非0值,不然列表末尾元素显示有问题;
2、不管是否指定headerDividersEnabled,列表上方的分隔线都不会显示;
ListView的使用方式
Android提供了两种使用ListView的方式:1、ListActivity方式。首先xml布局中将ListView的id设置为系统id,即“@android:id/list”,然后页面的代码类继承ListActivity。该方式无需在代码中获取ListView的对象,直接调用setListAdapter方法设置适配器,同时实现ListActivity的点击方法onListItemClick来响应点击事件。
2、普通Activity方式。xml布局中ListView的id可自定义,页面的代码类继承自Activity。该方式要从布局文件中获取ListView的对象,然后调用该对象的setAdapter方法设置适配器,并调用ListView对象的setOnItemClickListener方法来设置点击事件的监听器。
两种使用方式的区别如下:
1、ListActivity方式的视图id被设置为系统id,不方便在代码中修改该列表视图的属性;
2、ListActivity方式只实现点击方法、未实现长按方法,不方便响应列表项的长按事件。
3、实际开发中经常自己写个Activity的基类,具体页面都从该Activity基类派生出来。如果有个页面采用ListActivity方式,就无法继承使用这个Activity基类了。
从上面可以看出,ListActivity方式的限制较多,所以实际开发中我们还是使用普通Activity方式来开发ListView。
ListView的示例代码
下面是适配器的代码例子:import java.util.ArrayList; import com.example.exmsimplewidgte.R; import android.annotation.SuppressLint; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.BaseAdapter; import android.widget.TextView; import android.widget.Toast; @SuppressLint({ "DefaultLocale", "InflateParams" }) public class TitleListAdapter extends BaseAdapter implements OnItemClickListener, OnItemLongClickListener { private ArrayList<String> mTitleList; private LayoutInflater mInflater; private Context mContext; public TitleListAdapter(Context context, String[] title_list) { this.mInflater = LayoutInflater.from(context); mContext = context; mTitleList = new ArrayList<String>(); for (int i=0; i<title_list.length; i++) { mTitleList.add(title_list[i]); } } @Override public int getCount() { return mTitleList.size(); } @Override public Object getItem(int arg0) { return mTitleList.get(arg0); } @Override public long getItemId(int arg0) { return arg0; } @Override public View getView(final int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if (convertView == null) { holder = new ViewHolder(); convertView = mInflater.inflate(R.layout.list_title, null); holder.tv_seq = (TextView) convertView.findViewById(R.id.tv_seq); holder.tv_title = (TextView) convertView.findViewById(R.id.tv_title); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.tv_seq.setText(""+(position+1)); holder.tv_title.setText(mTitleList.get(position)); return convertView; } public final class ViewHolder { public TextView tv_seq; public TextView tv_title; } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { String desc = String.format("您点击了第%d项,该项的标题是%s", position+1, mTitleList.get(position)); Toast.makeText(mContext, desc, Toast.LENGTH_LONG).show(); } @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { String desc = String.format("您长按了第%d项,该项的标题是%s", position+1, mTitleList.get(position)); Toast.makeText(mContext, desc, Toast.LENGTH_LONG).show(); return true; } }
下面是ListView的调用代码例子:
String[] weekArray = {"星期一", "星期二", "星期三", "星期四", "星期五"}; TitleListAdapter titleAdapter = new TitleListAdapter(this, weekArray); ListView lv_hello = (ListView) findViewById(R.id.lv_hello); lv_hello.setFooterDividersEnabled(true); lv_hello.setAdapter(titleAdapter); lv_hello.setOnItemClickListener(titleAdapter); lv_hello.setOnItemLongClickListener(titleAdapter);
GridView
GridView是网格视图,用于分行分列显示表格信息。下面是GridView常用的属性和方法:xml布局上的属性设置:
horizontalSpacing : 指定子视图在水平方向的间距。
verticalSpacing : 指定子视图在垂直方向的间距。
columnWidth : 指定每列的宽度。
numColumns : 指定列的数目。
stretchMode : 指定拉伸的模式。取值说明如下:none表示不做拉伸;columnWidth表示若有空余空间,则拉伸与列宽大小一致;spacingWidth表示若有空余空间,则列宽不变,把空余分配到每列间的空隙;spacingWidthUniform与spacingWidth的区别在于,Uniform方式在每列左边和右边都补上空隙(即每行开头和末尾都补空隙),而spacingWidth在每行开头和末尾不补空隙,只有列与列之间才补空隙。实际开发中一般把模式设置为columnWidth。
代码中的方法:
setHorizontalSpacing : 设置子视图在水平方向的间距。
setVerticalSpacing : 设置子视图在垂直方向的间距。
setColumnWidth : 设置每列的宽度。
setNumColumns : 设置列的数目。
setStretchMode : 设置拉伸的模式。
setAdapter : 设置适配器。GridView使用的适配器一般继承自BaseAdapter。
setOnItemClickListener : 设置点击事件的监听器。
setOnItemLongClickListener : 设置长按事件的监听器。
实际开发中有时需要设置网格之间表格线的颜色,可惜GridView并未直接给出相应的属性和方法,那得变通处理一下。具体的说,就是给GridView设置整个网格的背景色(例如黑色),以及网格之间的水平间距和垂直间距;然后给每项网格的根布局设置背景色(例如白色),这样只有网格间距是黑色,从而间接画上了黑色表格线。
GridView的适配器模板与ListView是一样的,只要换掉代码里的布局文件名以及相关控件名称就好了,所以不再重复贴出GridView的适配器代码。下面是GridView的调用代码例子:
String[] yearArray = {"鼠年", "牛年", "虎年", "兔年", "龙年", "蛇年", "马年", "羊年", "猴年", "鸡年", "狗年", "猪年"}; ContentGridAdapter contentAdapter = new ContentGridAdapter(this, yearArray); GridView gv_hello = (GridView) findViewById(R.id.gv_hello); gv_hello.setNumColumns(5); gv_hello.setStretchMode(GridView.STRETCH_COLUMN_WIDTH); gv_hello.setHorizontalSpacing(1); gv_hello.setVerticalSpacing(1); gv_hello.setAdapter(contentAdapter); gv_hello.setOnItemClickListener(contentAdapter); gv_hello.setOnItemLongClickListener(contentAdapter);
点此查看Android开发笔记的完整目录
相关文章推荐
- Android 手势解锁 GestureLock的使用和简单修复
- 定制Android系统开发之九——在系统服务中实现回调
- Android编程开发之TextView单击链接弹出Activity的方法
- Android QQ音乐/酷狗音乐锁屏控制实现原理,酷狗锁屏
- Android fragment 重叠问题——通过hide,show方式导致的解决方法
- Android 读取SD卡指定后缀的所有文件
- android用户界面之Gallery3D学习资料汇总
- Android 关闭软键盘
- Android SDK Manager国内更新代理
- Android Studio如何发布APK
- Android练兵--Material加载进度条
- [Android实例] 带clean按钮的输入框
- Activity的启动模式(android:launchMode)
- ndk-stack的使用
- 关于android设计理念
- Gradle android自动填写SVN号,并发布(拷贝)到指定目录
- Android开发秘籍学习笔记(十二)
- Android:样式和主题
- adb push 失败提示 ‘Read-only file system’
- [Android实例] 侧边字母滑动检索控件