参考资料:http://blog.csdn.net/shulianghan/article/details/18555131
http://www.cnblogs.com/plokmju/p/android__imageview.html
ImageView,直接继承自View类,用于显示任何Drawable对象。ImageView有两个子类 ImageButton 和 QuickContactBadge, ImageButton还有一个子类是 ZoomButton;
一、常用属性
1.调整边界,保持长宽比
同时满足下面三个条件:
android:adjustViewBounds:设置ImageView是否调整自己的边界来保持所显示图片的长宽比。
要与下面两个属性一起用才有效果。
android:maxHeight:设置ImageView的最大高度。
android:maxWidth:设置ImageView的最大宽度。
android:layout_width与android:layout_height都为wrap_content
2.裁剪保留空白:
android:cropToPadding,是否裁剪, 用来保留ImageView的padding。
与android:scrollY 属性一起使用的时候才有用,单独使用没有效果;
即在滚动的时候, 滚动到边界, 边界的padding空白是否显示;
3.其他属性
android:scaleType:设置所显示的图片如何缩放或移动以适应ImageView的大小。
android:src:设置ImageView所显示的Drawable对象的ID。
android:scaleType的可选属性值:
matrix:使用矩阵进行缩放。
fitXY:横向、纵向独立缩放,以适应该ImageView。
fitStart:保持纵横比缩放图片,并且将图片放在ImageView的左上角。
fitCenter:保持纵横比缩放图片,缩放完成后将图片放在ImageView的中央。
fitEnd:保持纵横比缩放图片,缩放完成后将图片放在ImageView的右下角。
center:把图片放在ImageView的中央,但是不进行任何缩放。
centerCrop:保持纵横比缩放图片,以使图片能完全覆盖ImageView。
centerInside:保持纵横比缩放图片,以使得ImageView能完全显示该图片。
二、常用方法
1.缩放图片
View.setLayoutParams(new LinearLayout.LayoutParams(newWidth,newHeight))方法可以直接设定View下的所有控件的外观大小。同样适用于ImageView。
LayoutParmas params = new LinearLayout.LayoutParams(newWidth, newHeight);
params.gravity = Gravity.CENTER;
mImageView.setLayoutParams(params);
更好的方法是这样:
mImageView.getLayoutParmas().width = newWidth;
mImageView.getLayoutParmas().height = newHeight;
mImageView.requestLayout();
也可以用矩阵完成
// 计算缩放比例
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// 缩放矩阵
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
// 生成新的图片
bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
2.旋转图片
// 获取当前待旋转的图片
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), images[currentImage]);
// 设置旋转角度
matrix.setRotate(rotate);
// 生成旋转后的图片
bitmap = Bitmap.createBitmap(bitmap, 0, 0
, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
3.设置图片
currentImage = (currentImage + 1) % images.length;
imageView.setImageResource(images[currentImage]);
4.设置透明度
imageView.setAlpha(alpha);
三、缩放与旋转图片
ImageView的旋转涉及Matrix类,它表示一个3x3的坐标变换矩阵,在这个矩阵内,进行变换、旋转操作,需要通过构造函数显式的初始化之后才可以使用。
Demo布局:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
>
<Button
android:id="@+id/button_last"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="上一张"
/>
<Button
android:id="@+id/button_next"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="下一张"
/>
</LinearLayout>
<TextView
android:id="@+id/text_view_alpha"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="透明度:255"
android:paddingTop="5dp"
/>
<SeekBar
android:id="@+id/seek_bar_alpha"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="255"
android:progress="255"
/>
<TextView
android:id="@+id/text_view_zoom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="缩放"
android:paddingTop="5dp"
/>
<SeekBar
android:id="@+id/seek_bar_zoom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="800"
/>
<TextView
android:id="@+id/text_view_rotate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="旋转"
/>
<SeekBar
android:id="@+id/seek_bar_rotate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="360"
/>
<ImageView
android:id="@+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:scaleType="fitCenter"
android:src="@drawable/pic_1"
/>
</LinearLayout>
MainActivity.java:
public class MainActivity extends Activity implements OnClickListener, OnSeekBarChangeListener{
// 组件
private Button btnLast, btnNext;
private TextView tvAlpha, tvZoom, tvRotate;
private SeekBar sbAlpha, sbZoom, sbRotate;
private ImageView imageView;
// 图片数组
private int[] images;
// 旋转矩阵
private Matrix matrix;
// 当前图片
private int currentImage;
// 初始图片大小
// ImageView未绘制时getWidth()为0,此时用这个
private int initWidth, initHeight;
// 最小宽度
private int minWidth = 50;
// 图片长宽比
private double currentImageRatio;
// 图片缩放比例标记
private boolean hasGetRatio = false;
// 标示是否已经在ImageView的观察者中获取控件大小
private boolean hasMeasured = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
// 初始化
init();
}
/**
* 在onCreate()中获取ImageView的初始宽度和高度
*/
private void getImageViewSizeInit(){
ViewTreeObserver vto = imageView.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
if (!hasMeasured) {
// 获得初始宽高
initWidth = imageView.getMeasuredWidth();
initHeight = imageView.getMeasuredHeight();
// 将滑动条设置为对应位置
adjustZoomTvSb(initWidth, initHeight);
hasMeasured = true;
}
return true;
}
});
}
/*
* 初始化
*/
private void init(){
btnLast = (Button) findViewById(R.id.button_last);
btnNext = (Button) findViewById(R.id.button_next);
tvAlpha = (TextView) findViewById(R.id.text_view_alpha);
tvZoom = (TextView) findViewById(R.id.text_view_zoom);
tvRotate = (TextView) findViewById(R.id.text_view_rotate);
sbAlpha = (SeekBar) findViewById(R.id.seek_bar_alpha);
sbZoom = (SeekBar) findViewById(R.id.seek_bar_zoom);
sbRotate = (SeekBar) findViewById(R.id.seek_bar_rotate);
imageView = (ImageView) findViewById(R.id.image_view);
//添加事件监听器
btnLast.setOnClickListener(this);
btnNext.setOnClickListener(this);
sbAlpha.setOnSeekBarChangeListener(this);
sbZoom.setOnSeekBarChangeListener(this);
sbRotate.setOnSeekBarChangeListener(this);
// 给控制图片大小的SeekBar设置最大值为屏幕宽度
DisplayMetrics metrics = getResources().getDisplayMetrics();
sbZoom.setMax(metrics.widthPixels - minWidth);
// 用观察者在onCreate中获取组件属性
getImageViewSizeInit();
// 初始化旋转矩阵
matrix = new Matrix();
// 添加图片
images = new int[]{R.drawable.pic_1, R.drawable.pic_2, R.drawable.pic_3};
currentImage = 0;
}
/**
* 调整缩放滑动条的位置和TextView显示
* TextView SeekBar
*/
private void adjustZoomTvSb(int width, int height){
sbZoom.setProgress(width);
tvZoom.setText("缩放:宽度 " + width + " px,高度 " + height + " px");
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button_last: // 上一张 按钮
currentImage--;
if (currentImage < 0) {
currentImage = currentImage + images.length;
}
break;
case R.id.button_next: // 下一张 按钮
currentImage = (currentImage + 1) % images.length;
break;
default:
break;
}
// 设置图片
imageView.setImageResource(images[currentImage]);
// adjustZoomTvSb(imageView.getWidth(), imageView.getHeight());
// 每张图片比例不一样,要重新测定
hasGetRatio = false;
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
switch (seekBar.getId()) {
// 透明度滑块
case R.id.seek_bar_alpha:
int alpha = progress;
// 设置透明度
imageView.setAlpha(alpha);
tvAlpha.setText("透明度:" + alpha);
break;
// 图片大小滑块
case R.id.seek_bar_zoom:
// 如果还没绘制图片,则不用计算和改变大小
if (hasMeasured) {
if (!hasGetRatio) {
currentImageRatio = 1.0 *imageView.getHeight() / imageView.getWidth();
Log.v("调试", "缩放比例为:" + currentImageRatio);
hasGetRatio = true;
}
int newWidth = progress + minWidth;
int newHeight = (int) (newWidth * currentImageRatio);
// 改变ImageView的大小
imageView.getLayoutParams().width = newWidth;
imageView.getLayoutParams().height = newHeight;
imageView.requestLayout();
// // 也可以用如下方法
// LayoutParams params = new LinearLayout.LayoutParams(newWidth, newHeight);
// params.gravity = Gravity.CENTER;
tvZoom.setText("缩放:宽度 " + newWidth + " px,高度 " + newHeight + " px");
}
break;
// 图片旋转滑块
case R.id.seek_bar_rotate:
// 获取当前待旋转的图片
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), images[currentImage]);
// 设置旋转角度
matrix.setRotate(progress);
// 生成旋转后的图片
bitmap = Bitmap.createBitmap(bitmap, 0, 0
, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
// 绑定到图片控件上
imageView.setImageBitmap(bitmap);
tvRotate.setText("旋转:" + progress + "°");
default:
break;
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
}
效果图:
四、从互联网获取图片
Android4.0之后不能在主线程中访问网络,必须另开一条线程访问。在子线程中,无法直接操作UI控件的属性。解决方案就是,通过Thread类,进行多线程访问网络,再通过Handler类,进行消息传递。
Handler类的主要作用有两个:
在新启动的线程中发送消息。
在主线程中获取、处理消息。
Handler类的主要作用有两个:
在新启动的线程中发送消息。
在主线程中获取、处理消息。
为了让主线程能接受并处理新启动的线程发送的消息,Android通过回调的方式来实现,开发人员只需要重写Handler类中处理消息的方法,handleMessage(Message)即可,其中Message封装了发送过来的消息。
Handler包含如下方法,用于实现发送和处理消息:
Handler包含如下方法,用于实现发送和处理消息:
void handleMessage(Message msg):处理消息的方法,用于被重写。
final boolean hasMessage(int what):检查消息队列中是否包含what属性为指定值的消息。
sendEmptyMessage(int what):立即发送空消息。
final boolean sendEmptyMessageDelayed(int what,long delayMillis):指定delayMillis毫秒之后发送空消息。
final boolean sendMessage(Message msg):立即发送消息。
final boolean sendMessageDelayed(Message msg,long delayMillis):指定delayMillis毫秒之后发送消息。
Message封装了线程中传递的消息,对于一般的数据,Message提供了getData()和setData()方法来获取与设置数据,其中操作的数据是一个Bundle对象,这个Bundle对象提供一系列的getXxx()和setXxx()方法用于传递基本数据类型。
在Bundle中提供了两个方法,专门用来传递对象的,但是这两个方法也有相应的限制,需要实现特定的接口,当然,一些Android自带的类,其实已经实现了这两个接口中的某一个,可以直接使用。方法如下:
还有另外一种方式在Message中传递对象,那就是使用Message自带的obj属性传值,它是一个Object类型,所以可以传递任意类型的对象,Message自带的有如下几个属性:
putParcelable(String key,Parcelable value):需要传递的对象类实现Parcelable接口。
pubSerializable(String key,Serializable value):需要传递的对象类实现Serializable接口。
还有另外一种方式在Message中传递对象,那就是使用Message自带的obj属性传值,它是一个Object类型,所以可以传递任意类型的对象,Message自带的有如下几个属性:
int arg1:参数一,用于传递不复杂的数据,复杂数据使用setData()传递。
int arg2:参数二,用于传递不复杂的数据,复杂数据使用setData()传递。
Object obj:传递一个任意的对象。
int what:定义的消息码,一般用于确定消息的来源。
Demo:
必须声明联网权限:
<uses-permission android:name="android.permission.INTERNET"/>
activity_main.xml:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/button_download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下载网络图片"
/>
<TextView
android:id="@+id/textview_prompt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<ImageView
android:id="@+id/imageview_show"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitCenter"
/>
</LinearLayout>
package com.example.test;
import java.io.InputStream;
import java.util.Random;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
public class MainActivity extends Activity implements OnClickListener{
private Button btnDownload;
private TextView tvPrompt;
private ImageView ivShow;
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
btnDownload = (Button) findViewById(R.id.button_download);
tvPrompt = (TextView) findViewById(R.id.textview_prompt);
ivShow = (ImageView) findViewById(R.id.imageview_show);
// 定义一个handler,用于接收消息
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
Bitmap bitmap = null;
// 通过消息码确定使用什么方式传递图片信息
if (msg.what == 0) {
bitmap = (Bitmap) msg.obj;
tvPrompt.setText("使用obj传递数据");
} else {
Bundle bundle = msg.getData();
bitmap = (Bitmap) bundle.get("bitmap");
tvPrompt.setText("使用Bundle传递数据");
}
// 设置图片到ImageView中
ivShow.setImageBitmap(bitmap);
}
};
btnDownload.setOnClickListener(this);
}
// 事件监听器
@Override
public void onClick(View v) {
// 清空之前获取的数据
tvPrompt.setText("");
ivShow.setImageBitmap(null);
// 定义一个线程类
new Thread() {
@Override
public void run() {
try{
// 获取网络图片
InputStream input = HttpUtils.getImageViewInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(input);
// 调整宽度为屏幕宽度
bitmap = zoomBitmap(bitmap);
Message msg = new Message();
Random rand = new Random();
int randNum = rand.nextInt(10);
// 通过随机数选择传递图片的方式
if (randNum / 2 == 0) {
msg.what = 0;
msg.obj = bitmap;
} else {
Bundle bundle = new Bundle();
bundle.putParcelable("bitmap", bitmap);
msg.what = 1;
msg.setData(bundle);
}
// 发送消息
handler.sendMessage(msg);
} catch (Exception e) {
}
}
}.start();
}
// 调整图片大小
private Bitmap zoomBitmap(Bitmap bitmap){
int width = bitmap.getWidth();
int height = bitmap.getHeight();
// 设置想要的大小,已知自己手机宽度为1080
int newWidth = 1080;
int newHeight = newWidth * height / width;
// 计算缩放比例
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// 缩放矩阵
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
// 返回新的图片
return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
}
}
效果如图: