1.1.1.图片视图ImageView
ImageView,顾名思义,是一个展示图片的组件,它非常简单而且易用,下面我们来看一个示例,在我们的工程里面增加一个新类,命名为ImageViewActivity,具体代码如下:
ImageViewActivity.java代码清单5-14:
/**
* ImageView展示类
*
* @author孔明
*
*/
publicclass ImageViewActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置标题
setTitle("ImageViewActivity");
// 设置布局文件
setContentView(R.layout.image_view);
}
}
在代码里面,我们除了设置标题和布局文件之外没有任何其他的操作,我们来看下布局文件:
image_view.xml代码清单5-14:
<?xml version=“1.0” encoding=“utf-8”?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="图片展示:"/>
<ImageView
android:id="@+id/imagebutton"
android:src="@drawable/fitstpeoplelogo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
我们为ImageView配置了一个drawable里面的一个文件,运行程序,如图5-21所示:
图5-21 ImageView组件示意图
在ImageView中,我们可以通过设置android:scaleType属性来配置图片的位置和缩放规则。在上面的例子中由于我们给ImageView的宽和高的配置都是wrap_content,所以实际的ImageView的大小将有图片大小来决定。假如我们给ImageView配置了宽和高,比如,都配置成fill_parent,那么我们就可以通过配置android:scaleType来决定图片在ImageView中的大小和位置。android:scaleType的属性值有很多种,下面我们列一个表格来说明每一种的具体含义,如下所示:
scaleType属性值 | 含义 |
matrix | 用矩阵来绘图(默认)。 |
fitXY | 无视图片原始比例拉伸图片以填充View的宽和高 |
fitStart | 按比例拉伸图片,拉伸后图片的高度为View的高度,且显示在View的左边。 |
fitCenter | 按比例拉伸图片,拉伸后图片的高度为View的高度,且显示在View的中间。 |
fitEnd | 按比例拉伸图片,拉伸后图片的高度为View的高度,且显示在View的右边。 |
center | 按原图大小显示图片,但图片宽高大于View的宽高时,截图图片中间部分显示 |
centerCrop | 按比例放大原图直至等于某个View的宽高显示。 |
centerInside | 当原图宽高小于或等于View的宽高时,按原图大小居中显示;反之将原图缩放至View的宽高居中显示 |
当然ImageView还有其他几个比较重要的属性值,我们列表如下:
属性值 | 属性值以及含义 |
android:adjustViewBounds | 是否保持宽高比。需要与maxWidth、MaxHeight一起使用,否则单独使用没有效果。 |
android:maxHeight | 设置View的最大高度,单独使用无效,需要与setAdjustViewBounds一起使用。如果想设置图片固定大小,又想保持图片宽高比,需要如下设置: 1) 设置setAdjustViewBounds为true; 2) 设置maxWidth、MaxHeight; 3) 设置layout_width和layout_height为wrap_content。 |
android:tint | 将图片渲染成指定的颜色。 |
在后面的许多例子中,我们将会看到这些具体的属性值的应用。
1.1.2.菜单Menu
菜单键在早期Android的版本上用的比较多,在3.0之后,Menu逐渐淡化被其他的一些控件如ActionBar所取代,但是作为一个基础的控件,我们还是来介绍一下Menu的基本用法。
Android当中的Menu一共有三种,分别是选择菜单(OptionsMenu),环境菜单(ContextMenu)以及子菜单(SubMenu)。选择菜单是系统的Menu键对应的菜单,而环境菜单是需要长按一些控件(比如一段文字)才会弹出的菜单,子菜单可以加入到选择菜单和环境菜单里面去,需要注意的是子菜单不支持嵌套。
下面我们来看一下如何使用菜单,选择菜单与Activity相对应。一个Activity只能显示与监听一个选择菜单。在定义了选择菜单之后,按下系统的Menu键将会显示已经定义的菜单。这里值得一提的是,选择菜单最多能显示6个菜单项(MenuItem)。当菜单项超过6个时,在第6个菜单的位置上将显示“更多”菜单,点击后会出现后续的菜单项。我们还可以为选择菜单设置图标,增加子菜单等。环境菜单是与View对应的,一个View需要注册才能拥有自己的环境菜单,Activity也会相应环境菜单的选择。
孔明:你们可一定要记住了,子菜单是不能显示图标的,就像很多事情都是不能强求的一样! |
我们新建一个类,命名为:MenuCodeActivity,内容如下所示:
/**
* 使用硬编码方式来定义和使用菜单示例
* @author孔明
*/
publicclass MenuCodeActivity extends Activity {
// 创建一个TextView以便示例ContextMenu
private TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置布局文件
setContentView(R.layout.menu_code);
// 加载控件
mTextView = (TextView) findViewById(R.id.menu_textview);
// 为mTextView注册ContextMenu
registerForContextMenu(mTextView);
}
// 创建OptionsMenu时执行的回调方法,仅在第一次按menu键时执行一次
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
// 添加菜单项(多种方式)
// 1.直接指定标题
menu.add("菜单项1");
// 2.显示指定菜单项的组号、ID、排序号、标题
menu.add(1, // 组号
Menu.FIRST,// 唯一的ID号
Menu.FIRST,// 排序号
"菜单项2"); // 标题
menu.add(1, Menu.FIRST+ 1, Menu.FIRST + 1, "菜单项3");
menu.add(1, Menu.FIRST+ 2, Menu.FIRST + 2, "菜单项4");
// 返回一个菜单项的对象
MenuItem mi = menu.add(1, Menu.FIRST + 3, Menu.FIRST+ 3, "菜单项5");
menu.add(1, Menu.FIRST+ 4, Menu.FIRST + 4, "菜单项6");
menu.add(1, Menu.FIRST+ 5, Menu.FIRST + 5, "菜单项7");
// 为这个菜单项设置图标
mi.setIcon(R.drawable.menu_icon);
// 添加一个子菜单,并返回该子菜单的对象
SubMenu subMenu = menu.addSubMenu(1, Menu.FIRST + 6, Menu.FIRST + 6,
"我有子菜单哦");
// 添加子菜单
subMenu.add(1, Menu.FIRST + 7, Menu.FIRST+ 7, "子菜单1");
subMenu.add(1, Menu.FIRST + 8, Menu.FIRST+ 8, "子菜单2");
// 如果希望显示菜单,请返回true
return true;
}
// 当有菜单项被选择的时候调用的回调方法
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// 提示一下id,示意一下
Toast.makeText(this, "选择了id为" + item.getItemId() + "的菜单",
Toast.LENGTH_SHORT).show();
returnsuper.onOptionsItemSelected(item);
}
// 创建ContextMenu时的回调方法,每次都会被调用
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfomenuInfo) {
// 设置标题
menu.setHeaderTitle("这是一个ContextMenu");
// 添加菜单项
menu.add(0, 1, Menu.NONE, "菜单项1");
menu.add(0, 2, Menu.NONE, "菜单项2");
menu.add(0, 3, Menu.NONE, "菜单项3");
menu.add(0, 4, Menu.NONE, "菜单项4");
}
// 当ContextMenu中有被选择的菜单项时的回调方法
@Override
public boolean onContextItemSelected(MenuItem item) {
// 提示一下id,示意一下
Toast.makeText(this, "选择了id为" + item.getItemId() + "的菜单",
Toast.LENGTH_SHORT).show();
returnsuper.onContextItemSelected(item);
}
}
该类使用的布局文件为menu_code.xml,内容如下:
menu_code.xml代码清单5-15:
<?xml version=“1.0” encoding=“utf-8”?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:id="@+id/menu_textview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="30sp"
android:text="长按我可以产生ContextMenu哦"/>
</LinearLayout>
布局文件里面只定义了一个TextView,为的是长按可以产生一个环境菜单。我们运行程序如图5-22所示:
图5-22 硬编码方式控制的Menu组件示意图
我们点击模拟器的菜单按钮就会出现一个系统的菜单,由于我们在程序里面定义了8个菜单项,因此最后一个显示“more”按钮,我们给第5个菜单项定义了图标,如图5-22所示,我们点击more按钮,如图5-23所示:
图5-23 点击more之后的示意图
可以看到,没有显示出来的菜单项在此显示出来了,在代码里我们为第8个菜单项定义为一个子菜单并增加了几个子菜单项,我们点击“我有子菜单哦”之后,如图5-24所示:
图5-24 子菜单示意图
可以看到,我们定义的两个子菜单项都显示了出来,当我们点击其中某一个的时候,菜单会显示,同时显示提示信息:
图5-25 子菜单点击事件示意图
根据TextView的提示,我们长按TextView将会弹出如下的ContextMenu菜单:
图5-26 长按TextView之后产生的ContextMenu示意图
选择其中某一项之后也会得到相应的提示。
从代码来看,我们实现的菜单全都是靠硬编码来实现的。我们都知道这种方式在Android当中是不推荐的,下面我们来介绍使用xml文件配置的方式来实现菜单。新建一个类,命名为MenuXmlActivity,具体内容如下:
MenuXmlActivity.java代码清单5-16:
/**
* 使用xml定义菜单的示例
*
* @author孔明
*
*/
publicclass MenuXmlActivity extends Activity {
// 创建一个TextView以便示例ContextMenu
private TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置布局文件
setContentView(R.layout.menu_code);
// 加载控件
mTextView = (TextView) findViewById(R.id.menu_textview);
// 为mTextView注册ContextMenu
registerForContextMenu(mTextView);
}
// 创建OptionsMenu时执行的回调方法,仅在第一次按menu键时执行一次
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
// 获取MenuInflater
MenuInflater inflater = getMenuInflater();
// 使用xml文件定义的菜单填充menu对象
inflater.inflate(R.menu.options_menu, menu);
// 如果希望显示菜单,请返回true
return true;
}
// 当有菜单项被选择的时候调用的回调方法
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// 提示一下id,示意一下
Toast.makeText(this, "选择了id为" + item.getItemId() + "的菜单",
Toast.LENGTH_SHORT).show();
returnsuper.onOptionsItemSelected(item);
}
// 创建ContextMenu时的回调方法,每次都会被调用
@Override
public voidonCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfomenuInfo) {
// 获取MenuInflater
MenuInflater inflater = getMenuInflater();
// 使用xml文件定义的菜单填充menu对象
inflater.inflate(R.menu.context_menu, menu);
// 设置标题
menu.setHeaderTitle("这是一个ContextMenu");
}
// 当ContextMenu中有被选择的菜单项时的回调方法
@Override
public boolean onContextItemSelected(MenuItem item) {
// 提示一下id,示意一下
Toast.makeText(this, "选择了id为" + item.getItemId() + "的菜单",
Toast.LENGTH_SHORT).show();
returnsuper.onContextItemSelected(item);
}
}
在此类里面,我们还是实现了相同的方法,只不过,我们定义的按钮通过使用MenuInflater来将xml文件中定义的菜单映射到实际的菜单对象上去。在该类里面使用到的两个菜单xml的文件时在res/menu下的,系统会自动使用R.menu来获取其id来引用定义的菜单。options_menu.xml的内容如下:
options_menu.xml代码清单5-16:
<?xml version=“1.0” encoding=“utf-8”?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:id="@+id/group1">
<item android:id="@+id/item1"android:title="菜单项1"/>
<item android:id="@+id/item2"android:title="菜单项2"/>
<item android:id="@+id/item3"android:title="菜单项3"/>
<item android:id="@+id/item4"android:title="菜单项4"/>
<item android:id="@+id/item5"android:title="菜单项5"
android:icon="@drawable/menu_icon"/>
<item android:id="@+id/item6"android:title="菜单项6"/>
<item android:id="@+id/item7"android:title="菜单项7"/>
<item android:id="@+id/item8"android:title="我有子菜单哦">
<menu>
<item android:id="@+id/item9"android:title="子菜单1"/>
<item android:id="@+id/item10"android:title="子菜单2"/>
</menu>
</item>
</group>
</menu>
根结点为menu元素,里面定义了一个group为菜单的组,group里面定义了许多的菜单项item。为了跟之前的例子保持一致,我们依旧给第5个菜单项设置一个图标,给第8个菜单设置一个子菜单,并设置两个子菜单项。同理,context_menu.xml文件如下所示:
context_menu.xml代码清单5-16:
<?xml version=“1.0” encoding=“utf-8”?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:id="@+id/group2">
<item android:id="@+id/item1"android:title="菜单项1"/>
<item android:id="@+id/item2"android:title="菜单项2"/>
<item android:id="@+id/item3"android:title="菜单项3"/>
<item android:id="@+id/item4"android:title="菜单项4"/>
</group>
</menu>
在此文件里面只是定义了四个菜单项,我们运行程序之后,发现界面跟之前的完全一样,但是显示的id不同,这是因为,我们通过xml文件定义了控件的id,这些id全部交由系统自行管理,但是运行效果是完全一样的。由此我们可以看出通过使用xml文件来定义菜单的方式非常简单。
由于菜单逐渐被ActionBar所取代,下一小节,我们来讲一下这个3.0之后新出现的控件,ActionBar。
孔明:菜单虽然复杂,但是一个好的应用往往要把菜单的功能完善起来,这是提升用户体验的一个很重要的方面。 |
1.1.3.动作栏ActionBar
ActionBar是3.0新增加的一个控件,可以说是OptionsMenu的完全替代品。它位于标题栏的右侧,能够完成的任务有很多。由于ActionBar是3.0新增加的控件,所以只能在AndroidMenifest.xml里面将<uses-sdkandroid:minSdkVersion="11"/>才可以看到ActionBar的具体效果。
我们修改5.2.11中的options_menu.xml布局文件,将其修改为:
options_menu.xml代码清单5-17:
<?xml version=“1.0” encoding=“utf-8”?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:id="@+id/group1">
<item android:id="@+id/item1"android:title="菜单项1"/>
<item android:id="@+id/item2"android:title="菜单项2"/>
<item android:id="@+id/item3"android:title="菜单项3"/>
<item android:id="@+id/item4"android:title="菜单项4"
android:showAsAction="ifRoom|withText"/>
<item android:id="@+id/item5"android:title="菜单项5"
android:icon="@drawable/menu_icon"
android:showAsAction="ifRoom|withText"/>
<item android:id="@+id/item6"android:title="菜单项6"/>
<item android:id="@+id/item7"android:title="菜单项7"/>
<item android:id="@+id/item8"android:title="我有子菜单哦">
<menu>
<item android:id="@+id/item9"android:title="子菜单1"/>
<item android:id="@+id/item10"android:title="子菜单2"/>
</menu>
</item>
</group>
</menu>
我们给第四个和第五个菜单增加了android:showAsAction属性,这个属性有四个可选的值,含义如下:
always:这个值会使菜单项一直显示在ActionBar上。
ifRoom:如果有足够的空间,这个值会使菜单项显示在ActionBar上。
never:这个值使菜单项永远都不出现在ActionBar上, 但是该菜单项会出现在平常的菜单中。
withText:这个值使菜单项和它的图标,菜单文本一起显示。
运行程序,进入到5.2.11的Activity里面,截图如5-27所示:
图5-27 ActionBar组件示意图
通过上图可以看出,ActionBar可以完全取代OptionsMenu,当然ActionBar还有其他许多复杂的功能,包括,提供标签页的切换方式的导航功能,可以切换多个fragment;提供下拉的导航条目;提供交互式活动视图代替选项条目;使用程序的图标作为返回Home主屏或向上的导航操作。这些功能可以实现非常复杂精致的效果,在此就不一一介绍了。
1.1.4.图片按钮ImageButton
图片按钮ImageButton的作用与Button基本相同,只不过ImageButton是一个图片的按钮而不是一个文本的按钮,下面我们通过一个实例来看一下ImageButton如何使用,在5.2.1的工程里面增加一个新类,命名为:ImageButtonActivity,具体代码如下:
ImageButtonActivity.java代码清单5-18:
/**
* ImageButton展示类
* @author孔明
*
*/
publicclass ImageButtonActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//设置标题
setTitle("ImageButtonActivity");
// 设置布局
setContentView(R.layout.image_button);
}
}
布局文件image_button.xml如下所示:
image_button.xml代码清单5-18:
<?xml version=“1.0” encoding=“utf-8”?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="图片按钮:"/>
<ImageButton
android:id="@+id/imagebutton"
android:src="@drawable/playbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
可以看出ImageButton与Button不同的是通过设置android:src可以指定一个图片来作为按钮,而Button也是可以设置背景的,需要通过android:background来设置。运行程序如5-28图所示:
图5-28 ImageButton组件示意图
值得一提的是,ImageButton设置监听器的方法与Button的完全一致,在此就不多讲了。
孔明:感谢Google!ImageButton极大的提升了程序员的自由,使得程序员可以不用重写Button,就可以创建一个自定义图片的按钮了。 |
1.1.5.拖动条SeekBar
拖动条也是一个十分常用的控件,用拖动条我们可以来实现比如音量控制,文本拖动等效果,下面我们来看如何在代码里面使用拖动条。我们在5.2.1的工程里面增加一个新类,命名为SeekBarActivity,内容如下:
SeekBarActivity.java代码清单5-19:
/**
* SeekBar(拖动条)展示类
* @author孔明
*/
publicclass SeekBarActivity extends Activity implementsOnSeekBarChangeListener {
// 定义两个文本框来显示状态
private TextView mSeekBarTextView1 = null;
private TextView mSeekBarTextView2 = null;
// 定义拖动条
private SeekBar mSeekBar;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置标题
setTitle("SeekBarActivity");
// 设置布局
setContentView(R.layout.seek_bar);
// 通过id来加载TextView以及SeekBar
mSeekBarTextView1 = (TextView) findViewById(R.id.seekbar_textview1);
mSeekBarTextView2 = (TextView) findViewById(R.id.seekbar_textview2);
mSeekBar = (SeekBar) findViewById(R.id.seek);
// 设置拖动条SeekBar的监听器为Activity本身
// 当拖动条状态改变的时候将会执行监听器方法
mSeekBar.setOnSeekBarChangeListener(this);
}
// 当进度改变的时候执行
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
mSeekBarTextView1.setText("当前值:"+progress);
}
// 当开始拖动的时候执行
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
mSeekBarTextView2.setText("拖动中...");
}
// 当停止拖动的时候执行
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
mSeekBarTextView2.setText("拖动完毕");
}
}
代码中的两个文本主要是为了显示拖动条的状态以及观察拖动条的监听器的执行状态而设定的,这个Activity用到的布局文件seek_bar.xml为:
seek_bar.xml代码清单5-19:
<?xml version=“1.0” encoding=“utf-8”?>
<LinearLayout xmlns:android=http://schemas.android.com/apk/res/android
android:orientation="vertical"android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/seekbar_textview1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="拖动条"/>
<TextView
android:id="@+id/seekbar_textview2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="拖动条"/>
<SeekBar
android:id="@+id/seek"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:max="100"
android:thumb="@drawable/thumb"
android:progress="42"/>
</LinearLayout>
在这个布局文件当中,我们通过android:max来设置了最大的进度为100,通过android:progress来设置了拖动条的初始进度为42,通过android:thumb来设置指示器为drawable里面的一个名为thumb的文件,thumb是图5-29的红色滚动块。运行程序,截图如5-29所示:
图5-29 SeekBar组件示意图
刚启动程序的时候,两个TextView都显示的是初始设置的字符串,即“拖动条”。当我们按在指示器上并进行拖动的时候,两个TextView的显示如图5-30所示:
图5-30 SeekBar组件拖动中示意图
当我们停止拖动,并不在按在指示器上的时候,两个TextView的显示如图5-31所示:
图5-31 SeekBar组件拖动完成示意图
孔明:一般人我不告诉,拖动条可以用来实现好多复杂的功能,比如播放器的播放进度条,音量调节器等。 |
1.1.6.拖动效果Gallery
Gallery,顾名思义,是画廊,长廊的意思。它是一个用来展示图片的控件。Gallery也需要一个适配器来填充数据到里面。下面我们来看一下具体的一个实例。在5.2.1的工程里面增加一个新类,命名为GalleryActivity,具体的代码如下:
GalleryActivity.java代码清单5-20:
/**
* Gallery展示类
*
* @author孔明
*/
publicclass GalleryActivity extends Activity {
private Gallery mGallery;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置标题
setTitle("GalleryActivity");
// 指定布局文件
setContentView(R.layout.gallery);
mGallery = (Gallery)findViewById(R.id.gallery);
mGallery.setAdapter(new ImageAdapter(this));
}
// 私有类,自定义的Adapter适配器
private class ImageAdapter extendsBaseAdapter {
// 保存环境变量
private Context mContext;
// 图像的索引
private Integer[] mImage = {
R.drawable.scarduck_0,R.drawable.scarduck_1,R.drawable.scarduck_2,
R.drawable.scarduck_3,R.drawable.scarduck_4,R.drawable.scarduck_5,
R.drawable.scarduck_6,R.drawable.scarduck_7
};
// 构造方法
public ImageAdapter(Context c) {
mContext = c;
}
// 返回所有图片的个数
@Override
public int getCount() {
return mImage.length;
}
// 返回一个特定位置的资源
@Override
public Object getItem(intposition) {
return position;
}
// 返回图片在资源的id,这个方法以及上面的方法没有被用到
// 因此继承的时候没写具体的代码
@Override
public long getItemId(intposition) {
return position;
}
// 最重要的方法,通过此方法可以获得对应为的View控件
@Override
public View getView(int position,View convertView, ViewGroup parent) {
// 新建一个ImageView
ImageView iv = newImageView(mContext);
// 设置ImageView的资源来源
iv.setImageResource(mImage[position]);
// 设置缩放规则
iv.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
// 设置ImageView的大小
iv.setLayoutParams(new Gallery.LayoutParams(250,
LayoutParams.FILL_PARENT));
return iv;
}
}
}
在代码里面,我们自定义了一个ImageAdapter,继承自BaseAdapter,在代码里面我们实现了几个关键的方法,包括getView()和getCount()等。具体的过程是这样的,程序通过getCount()方法可以得知整个图片集共有多少张图片,因此此方法的返回值不能超过实际的图片的数量(如果想要超过的话,那么必须在getView()方法里面做一些取余的处理,以免发生数组越界的错误),然后通过getView()来获得指定位置要显示的View控件,并填充图像内容返回给Gallery来显示。
该类用到的布局文件gallery.xml为:
gallery.xml代码清单5-20:
<?xml version=“1.0” encoding=“utf-8”?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Gallery
android:id="@+id/gallery"
android:layout_width="fill_parent"
android:layout_height="400dp"/>
</LinearLayout>
在布局文件里面,我们只定义了一个Gallery控件,非常的简单,有了前面的基础,我相信大家一看这个文件就懂了。运行的截图如5-32所示:
图5-32 Gallery组件示意图
我们可以拖动图片进行左右切换操作。
1.1.7.切换图片ImageSwitcher
ImageSwitcher是图片切换查看器,可以实现类似于Windows下的图片与传真查看器的功能,下面我们来看一个具体的示例,在5.2.1的工程中,新建一个类,命名为ImageSwitcherActivity,具体内容如下:
ImageSwitcherActivity.java代码清单5-21:
/**
* ImageSwitcher展示类
*
* @author孔明
*/
publicclass ImageSwitcherActivity extends Activity {
// 保存ImageSwitcher的引用
private ImageSwitcher mImageSwitcher;
// 保存两个按钮的引用,分别为下一张和上一张的按钮
private Button mNextBtn;
private Button mPreBtn;
// 要展示的图片的id
private Integer[] mImage = {
R.drawable.scarduck_0,R.drawable.scarduck_1,R.drawable.scarduck_2,
R.drawable.scarduck_3,R.drawable.scarduck_4,R.drawable.scarduck_5,
R.drawable.scarduck_6,R.drawable.scarduck_7
};
// 记录要展示的图片在mImage里面的索引值
private int mIndex;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置标题
setTitle("ImageSwitcherActivity");
// 指定布局文件
setContentView(R.layout.imageswitcher);
// 通过id来加载ImageSwitcher
mImageSwitcher = (ImageSwitcher)findViewById(R.id.switcher);
// 为ImageSwitcher设置一个ViewFactory,负责为ImageSwitcher产生View控件所用
mImageSwitcher.setFactory(mViewFactory);
// 设置ImageSwitcher显示的第一张图片
mImageSwitcher.setImageResource(mImage[mIndex]);
// 点击Button来加载下一张图片
mNextBtn = (Button)findViewById(R.id.next_btn);
// 设置监听器
mNextBtn.setOnClickListener(mNextBtnListener);
// 点击Button来加载上一张图片
mPreBtn = (Button)findViewById(R.id.pre_btn);
// 设置监听器
mPreBtn.setOnClickListener(mPreBtnListener);
}
// 定义下一张按钮的监听器
private OnClickListener mNextBtnListener = new OnClickListener() {
public void onClick(View v) {
// 索引值自增
mIndex++;
// 判断是否是最后一张,如果不是
// 则设置ImageSwitcher背景为此索引值对应的图片,否则,显示提示信息
if (mIndex < mImage.length) {
mImageSwitcher.setImageResource(mImage[mIndex]);
} else {
Toast.makeText(ImageSwitcherActivity.this, "这是最后一张了",
Toast.LENGTH_SHORT).show();
}
}
};
// 定义上一张按钮的监听器
private OnClickListener mPreBtnListener = newOnClickListener() {
public void onClick(View v) {
// 索引值自减
mIndex--;
// 判断是否是第一张,如果不是
// 则设置ImageSwitcher背景为此索引值对应的图片,否则,显示提示信息
if (mIndex >= 0) {
mImageSwitcher.setImageResource(mImage[mIndex]);
} else {
Toast.makeText(ImageSwitcherActivity.this, "没有前一张了",
Toast.LENGTH_SHORT).show();
}
}
};
// 定义ImageSwitcher的ViewFactory,用于ImageSwitcher的控件生成
private ViewFactory mViewFactory = newViewFactory() {
@Override
public View makeView() {
// 返回一个ImageView,即所有图片以ImageView的形式来显示
return new ImageView(ImageSwitcherActivity.this);
}
};
}
跟之前的例子一样,我们在例子里面定义了两个按钮,分别用来实现上一页和下一页的功能,同时还定义了一个ImageSwitcher切换器,用来切换图片。当然切换的图片资源用了一个数组来表示,同时定义了一个索引值用来切换图片。当然对于ImageSwitcher来说,我们还需要定义一个ViewFactory来为ImageSwitcher填充View。
上面的类所用到的布局文件imageswitcher.xml为:
imageswitcher.xml代码清单5-21:
<?xml version=“1.0” encoding=“utf-8”?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageSwitcher
android:id="@+id/switcher"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/next_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下一张"/>
<Button
android:id="@+id/pre_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="上一张"/>
</LinearLayout>
</LinearLayout>
运行程序,截图如5-33所示:
图5-33 ImageSwitcher组件示意图
孔明:玄德,Gallery和ImageSwitcher相结合可以完成电子相册的功能,你要不要自己来试一下呢? 刘备:我?且慢,待我再研究一下! 孔明:编程就像踢足球,光看可是一辈子都学不会的哦~
|
1.1.8.网格视图GridView
网格视图是一种以网格的形式展示视图的控件,在网格视图里可以填充很多其他类型的控件,如Button,ImageView等,因此GridView又被称为“九宫格”。下面我们通过一个具体的实例看一下GridView的使用方法。在5.2.1的工程里面新增加一个类,命名为GridViewActivity,具体代码如下:
GridViewActivity.java代码清单5-22:
/**
* GridView展示类
* @author孔明
*/
publicclass GridViewActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置布局
setContentView(R.layout.grid_view);
// 设置标题
setTitle("GridViewActivity");
// 通过id加载定义在布局文件里的GridView
GridView gridview = (GridView)findViewById(R.id.grid_view);
// 设置一个Adapter
gridview.setAdapter(new ImageAdapter(this));
}
// 自定义一个ImageAdapter继承自BaseAdapter
public class ImageAdapter extendsBaseAdapter {
// 保存当前环境变量引用
private Context mContext;
// 构造方法
public ImageAdapter(Context c) {
mContext = c;
}
// 返回所有图片的个数
public int getCount() {
return mThumbIds.length;
}
public Object getItem(intposition) {
return null;
}
public long getItemId(intposition) {
return 0;
}
// 返回一个ImageView填充到GridView里面
public View getView(int position,View convertView, ViewGroup parent) {
ImageView imageView = null;
// 判断convertView是否为空
if (convertView == null) {
// 新建一个ImageView
imageView = newImageView(mContext);
// 设置ImageView的大小
imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
// 设置ImageView的缩放规则
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
} else {
// 利用convertView来生成ImageView,这是一个优化的操作
imageView = (ImageView)convertView;
}
// 设置图片
imageView.setImageResource(mThumbIds[position]);
return imageView;
}
// 图片的id数组,保存图片的id
private Integer[] mThumbIds = {
R.drawable.grid_view_01,R.drawable.grid_view_02,R.drawable.grid_view_03,
R.drawable.grid_view_04,R.drawable.grid_view_05,R.drawable.grid_view_06,
R.drawable.grid_view_07,R.drawable.grid_view_08,R.drawable.grid_view_09,
R.drawable.grid_view_10,R.drawable.grid_view_11,R.drawable.grid_view_12,
R.drawable.grid_view_13,R.drawable.grid_view_14,R.drawable.grid_view_15,
R.drawable.grid_view_16,
};
}
}
跟之前讲过的Gallery一样,在代码里面,我们也是自定义了一个ImageAdapter,用来为GridView来填充View。在getView()方法里面,我们返回一个ImageView。在这个方法里面,我们用了convertView来进行了优化,convertView保存了滑出屏幕的View的引用,这样可以在我们需要一个ImageView的时候,再也不用new关键字去生成了,而是直接使用之前用过的convertView即可。
该类使用的布局文件非常简单,grid_view.xml的内容如下:
grid_view.xml代码清单5-22:
<?xml version=“1.0” encoding=“utf-8”?>
<GridViewxmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/grid_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:numColumns="auto_fit"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:columnWidth="90dp"
android:stretchMode="columnWidth"
android:gravity="center"/>
图5-34 GridView组件示意图
在布局文件里面只包含了一个控件,就是GridView,GridView有许多属性,我们列表来介绍一下,如下所示:
属性名 | 属性值 |
android:numColumns | 设置列数,auto_fit表示根据内容的大小自动调整列数,尽可能多的显示列来填充可用空间。 |
android:verticalSpacing | 上下两行之间的距离 |
android:horizontalSpacing | 左右两列之间的距离 |
android:columnWidth | 设置列的宽度 |
android:stretchMode | 设置缩放模式,有四种模式,none表示无缩放,spacingWidth表示在每列之间的空间进行缩放,columnWidth表示每列进行平均的缩放,spacingWidthUniform表示每一列之间的间隔是均匀地缩放。 |