您的位置:首页 > 移动开发 > Android开发

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开发笔记的完整目录
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: