- Android开发权威指南(第二版)
- 李宁编著
- 1213字
- 2024-12-21 14:46:39
13.4 图像控件(ImageView)
前面介绍过很多可以显示图像的控件,但显示图像对于这些控件来说都只是辅助功能,而本节要介绍的ImageView控件则是专门用来显示和控制图像的,例如,放大、缩小、旋转图像。
13.4.1 ImageView控件的基本用法
源代码目录:src/ch13/ImageView
ImageView控件可用于显示Android系统支持的图像,其支持的图像格式有gif、jpg、png、bmp等。在布局文件中使用<ImageView>标签来定义一个ImageView控件,代码如下:
源代码文件:src/ch13/ImageView/res/layout/main.xml
<ImageView android:id="@+id/imageview" android:layout_width="wrap_content"
android:background="#F00" android:layout_height="wrap_content"
android:src="@drawable/icon" android:scaleType="center" />
在上面的代码中通过android:src属性指定了一个图像资源ID,并使用android:scaleType属性指定ImageView控件显示图像的方式。例如,center表示图像显示在ImageView控件的中心。如果将android:scaleType属性设为fitCenter,表示将图像按比例缩放至合适的大小,并显示在ImageView控件的中心。通常在设计相框时将android:scaleType属性设为fitCenter,这样可以使照片按比例显示在相框的中心。
源代码文件:src/ch13/ImageView/res/layout/main.xml
<ImageView android:layout_width="300dp" android:layout_height="200dp"
android:background="#FFF" android:src="@drawable/background"
android:scaleType="fitCenter" android:padding="10dp" />
上面的代码直接设置了ImageView控件的宽度和高度,也可以在代码中设置和获得ImageView控件的宽度和高度。
源代码文件:src/ch13/ImageView/src/mobile/android/imageview/Main.java
ImageView imageView = (ImageView) findViewById(R.id.imageview);
// 设置ImageView控件的宽度和高度
imageView.setLayoutParams(new LinearLayout.LayoutParams(200, 100));
// 获得ImageView控件的宽度和高度,并将获得的值显示在窗口的标题栏上
setTitle("height:" + imageView.getLayoutParams().width + " height:" + imageView.get LayoutParams().height);
运行本例,显示的效果如图13-19所示。
▲图13-19 图像的显示方式
13.4.2 显示指定区域的图像
源代码目录:src/ch13/RectImageview
虽然ImageView控件可以用不同的缩放类型(通过scaleType属性设置)显示图像,但遗憾的是ImageView控件只能显示整个图像。如果只想显示图像的某一部分,单纯使用ImageView控件就无能为力了。
尽管ImageView控件无法实现这个功能,但可以采用“曲线救国”的方法来达到只显示图像的某一部分的目的。该方法的基本原理是首先获得原图像的Bitmap对象,然后使用Bitmap.createBitmap方法将要显示的图像区域生成新的Bitmap对象,最后将这个新的Bitmap对象显示在ImageView控件上。
本例使用了一个分辨率为500408的图像文件(dog.jpg),当触摸该图像的某一点时,会将以该点为左上顶点的一个正方形区域复制到另一个100dp100dp的ImageView控件中。下面的代码定义了两个ImageView控件,分别用于显示原图像和原图某个区域的图像。
源代码文件:src/ch13/RectImageview/res/layout/main.xml
<!-- 显示原图像 -->
<ImageView android:id="@+id/imageview1" android:layout_width="fill_parent"
android:background="#F00" android:layout_height="261dp" android:src="@drawable/
background" android:scaleType="fitStart" />
<!-- 显示原图像的指定区域 -->
<ImageView android:id="@+id/imageview2" android:layout_width="100dp"
android:background="#F00" android:layout_height="100dp"
android:layout_marginTop="10dp" android:scaleType="fitCenter" />
第1个<ImageView>标签的android:scaleType属性值为fitStart,表示让图像从左上角开始显示(左上角对齐)。
本例的核心代码在Activity.onTouch方法中,要捕捉onTouch事件,必须实现OnTouchListener接口。实现单击图像截取图像区域的完整代码如下:
public class Main extends Activity implements OnTouchListener
{
private ImageView imageView1;
private ImageView imageView2;
@Override
public boolean onTouch(View view, MotionEvent event)
{
try
{
BitmapDrawable bitmapDrawable = (BitmapDrawable) imageView1
.getDrawable();
// 由于在ImageView控件中显示的图像尺寸会小于原图像尺寸(ImageView控件的高度是261,
// 而图像的高度是408,所以需要计算一个ImageView控件中的坐标与图像实际坐标的换算比例
// 也就是用原图像高度除以ImageView控件的高度
float scale =
(float)bitmapDrawable.getBitmap().getHeight()/imageView1.getMeasuredHeight();
// 将当前单击的横坐标换算成原图像的横坐标
int x = (int) (event.getX() * scale);
// 将当前单击的纵坐标换算成原图像的纵坐标
int y = (int) (event.getY() * scale);
// 将要截取的宽度换算成原图像对应的宽度
int width = (int)(100 * scale);
// 将要截取的高度换算成原图像对应的高度
int height = (int)(100 * scale);
// 从原图像截取图像区域,并将截取后的图像显示在第2个ImageView控件中
imageView2.setImageBitmap(Bitmap.createBitmap(
bitmapDrawable.getBitmap(), x, y, width, height));
}
catch (Exception e)
{
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
}
return false;
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
imageView1 = (ImageView) findViewById(R.id.imageview1);
imageView2 = (ImageView) findViewById(R.id.imageview2);
imageView1.setOnTouchListener(this);
}
}
运行本例后,单击第1个ImageView控件中的某一点,将显示如图13-20所示的效果。
▲图13-20 截取图像的指定区域
扩展学习:如何装载大图像
可以通过android.graphics.BitmapFactory类的静态方法从不同来源创建Bitmap对象。例如,下面的代码从SD卡中的图像文件创建了一个Bitmap对象。
Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/abc.jpg");
虽然从SD卡、资源中装载图像,并创建Bitmap对象很容易,但这里有一个问题,手机毕竟不是PC,内存和其他硬件资源有限(至少在可预见的未来手机还无法和同一时代的PC相比),无法一次性装载过大的图像(例如,装载文件大小在1MB以上的图像很可能会出现内存溢出错误)。那么在这种情况下,就需要将图像按比例缩小来装载(不是显示效果上的缩小,而是图像本身的缩小,这一点和ImageView控件按比例缩小图像不同),这就需要使用decodeFile方法的第2个参数(其他类似的方法,例如,decodeResource方法也有这个参数)来设置缩小的比例。
decodeFile方法的第2个参数的数据类型是android.graphics.BitmapFactory.Options,Options类有一个inSampleSize字段用于设置图像缩小的比例。该属性是int类型,例如,如果该属性的值是5,则以1/5,也就是20%的大小来缩小原图像。下面的代码将以25%的大小生成一个缩小版的Bitmap对象。
Options options = new Options();
options.inSampleSize = 4;
Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/abc.jpg", options);
在创建Bitmap对象后,就可以直接使用ImageView.setImageBitmap方法将缩小版的图像在ImageView控件上显示了。
13.4.3 缩放和旋转图像
源代码目录:src/ch13/ResizeRoundImage
缩放图像的方法很多,最简单的方法无疑是改变ImageView控件的大小,但应将<ImageView>标签的android:scaleType属性值设为fitCenter。旋转图像可以用android.graphics.Matrix.setRotate方法来实现,通过该方法可以指定旋转的度数。
本节的例子提供了两个滚动条控件(SeekBar),第1个SeekBar控件(将在后面详细介绍)用于缩放图像(android:max属性值为240),第2个SeekBar控件用于旋转图像(android:max属性值为360,也就是说,通过该SeekBar控件可以使图像最多旋转360°)。
为了自适应屏幕的宽度(图像放大到与屏幕宽度相等时为止),在本例中没有直接将第1个SeekBar控件的android:max属性值设为240,而是使用如下代码来获得屏幕的宽度,并将屏幕宽度与图像的最小宽度(在本例中是minWidth变量,值为80)的差作为android:max属性的值。
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
seekBar1.setMax(dm.widthPixels - minWidth);
在SeekBar类的onProgressChanged事件方法中需要控制图像的缩放和旋转,代码如下:
源代码文件:src/ch13/ResizeRoundImage/src/mobile/android/resize/round/image/Main.java
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
// 处理图像缩放
if (seekBar.getId() == R.id.seekBar1)
{
int newWidth = progress + minWidth; // 计算缩放后图像的新宽度
int newHeight = (int) (newWidth * 3 / 4); // 计算缩放后图像的新高度
// 设置ImageView控件的尺寸
imageView.setLayoutParams(new LinearLayout.LayoutParams(newWidth,newHeight));
textView1.setText("图像宽度:" + newWidth + " 图像高度:" + newHeight);
}
// 处理图像旋转
else if (seekBar.getId() == R.id.seekBar2)
{
// 装载dog.jpg文件,并返回该文件的Bitmap对象
Bitmap bitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.dog)).
getBitmap();
// 设置图像的旋转角度
matrix.setRotate(progress);
// 旋转图像,并生成新的Bitmap对象
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
matrix, true);
// 重新在ImageView组件中显示旋转后的图像
imageView.setImageBitmap(bitmap);
textView2.setText(progress + "度");
}
}
在编写上面代码时需要了解如下几点。
由于在本例中允许图像的最小宽度是80,因此,缩放后的新宽度应为seekBar1的当前进度与最小宽度(minWidth)之和。新高度可以根据新宽度计算出来。
由于图像的宽度和高度之比是4:3,因此,显示图像的ImageView控件的android:layout_width和android:layout_height属性的值的比例也应该是4:3,例如,在本例中这两个属性值分别是200dp和150dp,并且为了保证图像和ImageView控件的大小相同,android:scaleType属性值应设为fitCenter。
运行本例后,拖动第1个和第2个SeekBar控件对图像进行缩放和旋转,将显示如图13-21所示的效果。
▲图13-21 缩放和旋转图像