1 选择控件
【
区别于之前的简单控件(如Button,TextView)的特点:
1. 对于选择控件来说,每一个选择控件可以显示多个条目
即一个控件中,可以同时控制显示n组重复格式的简单控件
2. 每个条目都可处理自身的点击事件
】
1.1 Spinner 下拉框
【
如何显示一个Spinner???
方式一:可以通过android:entries属性控制Spinner中显示的内容
属性值:必须是引用的res中的字符串数组资源
<?xml version="1.0"encoding="utf-8"?>
<resources>
<!--
1. 在res~~values文件夹中新建一个arrays.xml文件
2. 在该文件中添加数组标签,并且制定name属性
3. 在数组标签之间添加item标签,每个item代表数组中的一个元素
-->
<string-array name="sp">
<item >Home</item>
<item >Work</item>
<item >Other</item>
<item >Custom</item>
</string-array>
</resources>
缺陷:要显示的数据源只能来自于资源文件,不能使用连网获取资源,局限性比较大。
方式二:通过代码进行处理
实现步骤:
1. 获取Spinner控件对象
2. 初始化适配器对象
3. 通过Spinner对象调用setAdapter方法设置适配器
关于适配器:
适配器的作用:
1. 控制Spinner中要显示的数据(包括数据内容以及数据的个数)
2. 控制Spinner中的每条数据要如何显示
适配器的分类:
1. ArrayAdapter
2.SimpleAdapter
3. BaseAdapter
4.SimpleCursorAdapter
ArrayAdapter的特点:
1. 相对于其他的适配器,使用起来最简单
2. 该种适配器的每个item中只能显示一个TextView
如:想要让每个item中显示一张图片一段文字的话,不能使用ArrayAadapter
ArrayAdapter的使用方式:
构造方法:
1. ArrayAdapter(context, resource)
context:上下文环境
resource:布局文件
2. ArrayAdapter(context, resource,objects)
context:上下文环境
resource:布局文件
objects:数据源 可以为list集合或者数组
3. ArrayAdapter(context, resource,textViewResourceId, objects)
context:上下文环境
resource:布局文件
textViewResourceId:需要填充数据的控件id
objects:数据源
三种构造方法之间的区别:
1. 第二种和第三种构造方法可以之间设置要显示的数据源,而构造方法一中需要在适配对象初始化好之后再通过add或者addAll方法添加要显示的数据
2. inttextViewResId 用于指定参数二的布局文件中对应的textview控件的id
作用: 当构造方法中不包含此参数的时候,那么参数二的布局文件中必须以TextView作为根标签
而包含此参数的构造方法没有限制
Spinner的监听事件:
/*
* 设置Spinner中item的点击事件
* */
sp.setOnItemSelectedListener(newOnItemSelectedListener() {
/*
* onItemSelected:一旦spinner列表中的某个item被点击选中时运行
* 参数
* 3:被点击的item的位置
*
* */
@Override
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, list.get(position), Toast.LENGTH_SHORT).show();
}
// 当spinner中没有任何内容被选中时运行
@Override
public void onNothingSelected(AdapterView<?> parent) {
// TODO Auto-generated method stub
}
});
】
1.1.1 示例代码:Spinner 下拉框
【
public class MainActivity extends Activity {
private Spinner spinner1;
private ArrayList<String> list = newArrayList<String>();
@Override
protected voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
spinner1 = (Spinner) this.findViewById(R.id.spinner1);
for(inti=0;i<=10;i++){
list.add("item"+i);
}
//方式1
ArrayAdapter<String>adapter = newArrayAdapter<String>(this,R.layout.item_layout, R.id.textView1);
adapter.addAll(list);
adapter.add("数据源");
//方式2
ArrayAdapter<String>adapter=newArrayAdapter<String>(this,android.R.layout.simple_spinner_dropdown_item,list);
spinner1.setAdapter(adapter);
//方式3
ArrayAdapter<String> adapter = newArrayAdapter<String>(this, R.layout.item_layout, R.id.textView1);
adapter.addAll(list);
adapter.add("数据源");
/**
* 设置Spinner中的点击事件(即项选择事件)
*/
spinner1.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public voidonItemSelected(AdapterView<?> parent, View view,
int position, longid) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, list.get(position),0).show();
}
//当spinner中没有任何内容选中时调用
@Override
public voidonNothingSelected(AdapterView<?> parent) {
// TODO Auto-generated method stub
}
});
}
}
】
1.2 适配器的使用
1.2.1 ArrayAdapter
【
构造方法:ArrayAdapter(context,resource, textViewResourceId, objects)
context:上下文环境
resource:布局文件
textViewResourceId:需要填充数据的控件id
objects:数据源
清空适配其中的数据显示:
//清出数据的方式一
// adapter.clear();
//清出数据的方式二:
list.clear();
//通知适配器进行刷新
adapter.notifyDataSetChanged();
更新适配器中的数据后刷新显示:
list.add("我是新增的数据");
//当适配器中显示的数据源发生改变时,可通过此方法刷新适配器的显示,重新加载数据
adapter.notifyDataSetChanged();
设置Spinner选中默认内容:
/*
* 参数为想要选中的item在列表中的position位置
* */
spinner.setSelection(2);
proAdapter = newArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line,pros);
】
1.2.2 SimpleAdapter
【
构造方法:Simple(context, data,resource, from, to)
context:上下文环境
data:数据源,每一行是一个Map对象,每个Map对象中存储的是每一行要显示的数据
resource:单行布局(自定义的布局文件),每个item布局文件的id
from:当时在定义List<Map>中的每一个key存放到String[],系统通过填写的key找出value最后填写到控件上
to:需要填充数据的控件id
特点:
* 可以指定让每个item中显示任意内容,没有ArrayAdapter那种只能显示一个TextView的限制
使用方式:
1. 通过SimpleAdapter的构造方法初始化对象
2. 通过Spinner对象调用setAdapter是指适配器即可
构造方法:SimpleAdapter(context, data,resource, from, to)
context:上下文环境
data:数据源,每一行是一个Map对象,每个Map对象中存储的是每一行要显示的数据
resource:单行布局(自定义的布局文件),即控制每个item显示的布局
from:当时在定义List<Map>中的每一个key存放到String[],系统通过填写的key找出value最后填写到控件上
to:需要填充数据的控件id
* 参数4与参数5合起来的效果;
*根据参数4中指定的key取出对应的value后,放到参数5指定的控件中进行显示
*注意:4和5的顺序要对应
案例代码如:
// 封装数据源,实现让Spinner中显示5条数据,每条数据中显示一个图片和一个文本
for (int i=0;i<5;i++) {
HashMap<String,Object> map = newHashMap<String, Object>();
map.put("image",R.drawable.ic_launcher);
map.put("text","item "+i);
list.add(map);
}
Log.i("===", "===== list.s"+list.size());
adapter = newSimpleAdapter(this, list,R.layout.item, newString[]{"image","text"}, new int[]{R.id.imageView1,R.id.textView1});
spinner.setAdapter(adapter);
】
1.2.3 使用步骤
【
1、创建适配器
2、通过setAdapter(adapter)设置适配器
3、如果数据源发生改变,则需要调用adapter.notifyDataSetChanged()方法,通知刷新适配器
】
1.3 AutoCompleteTextView 带下拉框的编辑栏
【
自动提示补全的输入框。当直接在布局中添加AutoCompleteTextView
当直接在布局文件中添加AutoCompleteTextView标签,并且没有做过其他操作时,该控件的效果与输入框一样
如果想要实现像上方效果图一样的提示效果,必须要设置适配器
android:completionThreshold="1":从第几项开始过滤
示例代码:
public class MainActivity extends Activity {
ArrayList<String>list = newArrayList<String>();
ArrayAdapter<String>adapter;
private AutoCompleteTextView actv;
@Override
protected voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
actv = (AutoCompleteTextView) this.findViewById(R.id.actv);
/*
* list.add("abc hdfhd");list.add("gdgh fhd"); list.add("zgh fhd");
* list.add("er fhd");adapter = new
*ArrayAdapter<String>(MainActivity.this,
* android.R.layout.simple_dropdown_item_1line,list);
*/
// 读取资源中的数组
String[] data =getResources().getStringArray(R.array.sp_spinner);
adapter = newArrayAdapter<>(this,
android.R.layout.simple_spinner_dropdown_item, data);
actv.setAdapter(adapter);
}
}
】
1.4 GridView 网格视图
【
GirdView的使用:
1. 通常显示网格形状
2. 与ListView类似,也是一个控件内容可以控制n个item的显示,
不同点在于ListView中所有的item是从上到下竖向排列,而GridView中所有的item是
排列成网格的形状,可以任意指定是9宫格或16宫格等
3. 使用方式与ListView极其类似,即想要控制的GridView的显示必须设置适配器,
想要设置item的点击,也是setOnItemClickListener
常用属性:
<!--
android:numColumns 设置GridView显示的列数
特殊属性值:auto_fit, 此属性值,在没有android:columnWidth配合时,为2列
有配合时,那么就根据android:columnWidth进行自动适应
android:verticalSpacing="10dp" 行间距
android:horizontalSpacing="10dp" 列间距
android:stretchMode 伸缩模式,即控制的是剩余空间的分配方式
none 无效果
如,屏幕总宽度是720像素,指定列宽是40,指定的列间距是10,总共为3列
即占用的总宽度140,剩余:720-140= 580
spcingWidth 将这580的空间平均分配给中间的2个列间距
columWidth 将这580的空间平均分配给每列的columnWidth
spacingWidthUniform 将这580的空间平均分配给中间的2个列间距以及GridView的左右边距
-->
<GridView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="3"
android:verticalSpacing="10px"
android:horizontalSpacing="10px"
android:stretchMode="spacingWidthUniform"
android:id="@+id/gv"/>
】
1.4.1 GridView实例
【
public class MainActivity extends Activity {
private GridView gv;
int[] imgs= { R.drawable.pic0, R.drawable.pic1, R.drawable.pic2,
R.drawable.pic3, R.drawable.pic4,R.drawable.pic5, R.drawable.pic6,
R.drawable.pic7, R.drawable.pic8};
@Override
protected voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gv = (GridView) this.findViewById(R.id.gv);
gv.setAdapter(newGridAdapter());
}
class GridAdapter extendsBaseAdapter {
@Override
public int getCount() {
// TODOAuto-generated method stub
returnimgs.length;
}
@Override
publicObject getItem(int arg0) {
// TODOAuto-generated method stub
returnnull;
}
@Override
public long getItemId(intarg0) {
// TODOAuto-generated method stub
return0;
}
@Override
publicView getView(int position, ViewconvertView, ViewGroup parent) {
// TODOAuto-generated method stub
ViewHolder holder;
if(convertView == null){
convertView = View.inflate(MainActivity.this, R.layout.item,
null);
holder = new ViewHolder();
holder.iv= (ImageView) convertView
.findViewById(R.id.imageView1);
convertView.setTag(holder);
} else{
holder = (ViewHolder)convertView.getTag();
}
holder.iv.setImageResource(imgs[position]);
returnconvertView;
}
}
class ViewHolder {
ImageView iv;
}
}
】
1.5 ;ListView 列表视图
【
特点:直接显示在屏幕上的n行列表数据
使用方式:
通过控件对象设置适配器
BaseAdapter 适配器
特点:
最基础的适配器,最灵活
如:想要实现一个效果:让列表的每个条目中显示一个图片,一个TextView,要求1,3,5显示蓝背景,2,4,6行显示蓝背景
使用方式:
1. 创建一个BaseAdapter的子类,并重写相关方法
2. 初始化子类对象,并setAdapter
关于BaseAdapter中的相关方法:
//一旦设置适配器或者刷新适配器后都会自动调用的方法
/*
*1.通过返回值控制列表中总共要显示的item条数
*2. 当返回值非0的时候,那么会自动调用下方的getView方法
*当返回值为0的时候,不会调用
**/
@Override
public int getCount() {
// TODO Auto-generated method stub
return list.size();
}
//一旦设置适配器或者刷新适配器后都会自动调用的方法
/*
*View 视图,显示方式
*返回值控制的是对应位置上的item条目的显示方式
*参数1:当前item在列表中所处的位置
**/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
}
关于getView方法的处理(基本处理):
1. 准备一个item条目对应的布局文件
2. 将该布局文件转化成View对象
转化方式:
A.//初始化LayoutInflater对象,用于进行布局文件转化成View对象的操作
//初始化方式一:
// inflater = LayoutInflater.from(this);
//初始化方式二:
inflater =getLayoutInflater();
B. /*通过布局文件得到对应的View对象
* 参数一:要转化的布局文件的对应的id
* 参数二:ViewGroup对象,填null即可
* */
View v = inflater.inflate(R.layout.item, null);
3. 将得到的View对象作为返回值返回,并通过View对象获取对应position行的控件,设置不同的显示内容
//获取position行的TextView对象
/*
* 注意:此处一定要通过v对象调用findViewById
* 方法获取控件对象
* 代表用参数指定的id到v对象对应的布局中获取控件
* 如果没写,代表用参数指定的id到setContentView方法对应的布局中获取控件
* 找不到,返回null
* */
TextView tv = (TextView)v.findViewById(R.id.textView1);
tv.setText(list.get(position));
关于适配器子类中的其余两个方法:
/*
*当通过adapter对象调用getItem方法,或者通过listview对象
*调用getItemAtPosition方法时运行,
*返回值即为上方两个方法的运行结果
**/
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
returnlist.get(position);
}
//通常为position,返回值控制 item的点击事件中的参数四
//以及adapter.getItemId方法和lv.getItemIdAtPosition方法的运行结果
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
设置ListView的item点击事件:
lv.setOnItemClickListener(new OnItemClickListener() {
/*
* 参数:
* 1. 当前显示的listView对象
* 2. 被点击那一行的View对象
* 3.被点击的条目的位置
* 4. 如果当前控件设置的的适配器不是BaseAdapter,就是参数三position
* 如果是BaseAdapter,此参数对应的是适配器子类中getItemId方法的返回值
* */
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, " dfoi "+position+" "+id, Toast.LENGTH_SHORT).show();
/*
* 以下两个方法的执行结果,均取决于适配器中getItem方法的返回值
* */
Log.i("===", "===adapter.getItem(2) "+adapter.getItem(2));
Log.i("===", "===lv.getItemAtPosition(3)"+lv.getItemAtPosition(3));
//如:实现点击某一行时,随机改变此行的背景色
Random random = new Random();
view.setBackgroundColor(Color.rgb(random.nextInt(256), random.nextInt(256), random.nextInt(256)));
}
});
】
1.6 BaseAdapter 自定义适配器
【
int getCount():返回Item的数量
Object getItem(int position):返回当前item对应的数据对象
long getItemId(int position):返回当前item的id
View getView(int position, ViewconvertView, ViewGroup parent):返回当前item对应的View对象
】
1.7 案例:下载解析未来7天的天气数据并显示在ListView中(使用自定义适配器)
1.8 示例代码
1.8.1 下拉框简单联动
【
/*
* 在页面上显示两个Spinner,其中一个Spinner显示省份,
* 一个Spinner显示省份对应的城市,并要求,当切换省份时,
* 第二个Spinner中显示的城市也要对应切换
* */
public class MainActivity extendsActivity {
Spinner proSpinner,citySpinner;
String[] pros ={"黑龙江","辽宁","吉林"};
String[][] citys={{"佳木斯","哈尔滨","齐齐哈尔","牡丹江"},
{"铁岭","沈阳","葫芦岛"},
{"长春","吉林","吉林城市a"}};
ArrayAdapter<String> proAdapter;
ArrayAdapter<String> cityAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
/*
* 初始化Adapter
*/
proAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, pros);
//cityAdapter = newArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, citys[0]);
proSpinner.setAdapter(proAdapter);
//citySpinner.setAdapter(cityAdapter);
proSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
// TODO Auto-generated method stub
cityAdapter =new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_dropdown_item_1line, citys[position]);
citySpinner.setAdapter(cityAdapter);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// TODO Auto-generated method stub
}
});
}
private void initView() {
proSpinner=(Spinner) this.findViewById(R.id.spinner1);
citySpinner=(Spinner) this.findViewById(R.id.spinner2);
}
}
】
1.8.2 ListView显示1
【
/*
* 在页面上显示一个ListView,要求每个条目中显示一个图片,两个文字,
* 并且要求每一行显示的内容不相同
* */
public class MainActivity extendsActivity {
ListView lv;
ArrayList<Item> list = new ArrayList<Item>();
int[] imgs ={R.drawable.pic0,R.drawable.pic1,R.drawable.pic2,R.drawable.pic3,R.drawable.pic4};
private LayoutInflater inflater;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv =(ListView) this.findViewById(R.id.lv);
for(int i=0;i<5;i++){
list.add(new Item(imgs[i], "name"+i, "text"+i));
}
inflater = LayoutInflater.from(this);
//设置适配器
lv.setAdapter(newMyAdapter());
}
class MyAdapter extendsBaseAdapter{
@Override
public int getCount() {
// TODO Auto-generated method stub
return list.size();
}
@Override
public Object getItem(intposition) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(intposition) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(intposition, View convertView, ViewGroup parent) {
View v = inflater.inflate(R.layout.item, null);
ImageView iv =(ImageView)v.findViewById(R.id.imageView1);
TextView tv =(TextView)v.findViewById(R.id.textView1);
TextView tv2=(TextView) v.findViewById(R.id.textView2);
Item item =list.get(position);
iv.setImageResource(item.getImageId());
tv.setText(item.getName());
tv2.setText(item.getText());
return v;
}
}
}
】
1.8.3 listView_CheckBox
【
<?xml version="1.0"encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants">
<ImageView
android:id="@+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:src="@drawable/ic_launcher"/>
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/imageView1"
android:layout_centerHorizontal="true"
android:textSize="25sp"
android:text="TextView"/>
<!-- 一旦item中显示一个CheckBox或者Button这种自身自带点击效果的控件的时候
这种控件默认会抢占焦点,焦点作用:没焦点就无法接收点击事件
想要解决这件事情,
方式一:当明确知道是哪个控件抢占了焦点的时候,直接给该控件添加一个
android:focusable=false的属性即可
方式二:当不能明确知道是哪个控件抢占了焦点,在当前布局文件的根标签总添加
android:descendantFocusability="blocksDescendants"属性
用于屏蔽本布局中一切可能抢占焦点的控件
android:clickable="false"屏蔽CheckBox自身点击效果
-->
<CheckBox
android:id="@+id/CheckBok1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/textView1"
android:layout_alignBottom="@+id/textView1"
android:layout_alignParentRight="true"
android:clickable="false"/>
</RelativeLayout>
/*
* 实现:
* 展示一个ListView,要求ListView的每个条目中显示一个图片,
* 一个文字,一个CheckBox,
* 1.当点击ListView的条目的时候,输出点击条目的内容
* 2.在页面上添加一个按钮,实现点击按钮的时候,就将ListView中CheckBox选中
* 的条目删除
*/
public class MainActivity extendsActivity {
ArrayList<String> list = new ArrayList<String>();
ArrayList<String> select=new ArrayList<String>();
ListView lv;
Button but;
CheckBoxAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv = (ListView) this.findViewById(R.id.listView1);
but=(Button) this.findViewById(R.id.button1);
/*
* 实现全选效果
*/
Button all =(Button) this.findViewById(R.id.button2);
all.setOnClickListener(newOnClickListener() {
@Override
public void onClick(View v) {
select.clear();
select.addAll(list);
adapter.notifyDataSetChanged();
}
});
for(int i=0;i<30;i++){
list.add("条目"+i);
}
adapter = new CheckBoxAdapter();
lv.setAdapter(adapter);
//列表的点击事件
lv.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
/*
* 获取被点击行的CheckBox
* 并将选中内容存入select集合
*/
CheckBox cb = (CheckBox)view.findViewById(R.id.CheckBok1);
if(cb.isChecked()){
cb.setChecked(false);
select.remove(position);
}else{
cb.setChecked(true);
select.add(list.get(position));
}
}
});
//一键删除事件
but.setOnClickListener(newOnClickListener() {
@Override
public void onClick(View v) {
list.removeAll(select);
adapter.notifyDataSetChanged();
select.clear();
}
});
}
class CheckBoxAdapter extendsBaseAdapter{
@Override
public int getCount() {
// TODO Auto-generated method stub
return list.size();
}
@Override
public Object getItem(intposition) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(intposition) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(intposition, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView== null){
convertView =getLayoutInflater().inflate(R.layout.item, null);
holder = new ViewHolder();
holder.iv=(ImageView)convertView.findViewById(R.id.imageView1);
holder.tv=(TextView)convertView.findViewById(R.id.textView1);
holder.cb=(CheckBox)convertView.findViewById(R.id.CheckBok1);
convertView.setTag(holder);
}else{
holder =(ViewHolder)convertView.getTag();
}
/*
* 获取自定义字体对象
* 参数一:固定使用使用getAssets()方法,用于获取工程中的assets文件对象
* 参数二:指定自定义字体文件的路径
*/
Typefacetype = Typeface.createFromAsset(getAssets(), "fonts/ShouJinTi.ttf");
//给指定的TextView设置自定义字体
holder.tv.setTypeface(type);
holder.tv.setText(list.get(position));
/*
* 为了防止checkbox勾选状态在ListView滚动的时候随便乱传的问题
* 通过if判断处理checkbox的选中效果
*/
if(select.contains(list.get(position))){
holder.cb.setChecked(true);
}else{
holder.cb.setChecked(false);
}
returnconvertView;
}
}
class ViewHolder{
ImageView iv;
TextView tv;
CheckBox cb;
}
}
】