ImageView,和前面介绍的TextView、EditText,都继承自View都是View的子类。
ImageView 是用于呈现图片的视图。View可以理解为一个视图或控件。
1.简单使用
在drawable-xxhdpi文件夹下放一张图片:
xml中把这张图片设置给ImageView,这样就可以在屏幕上看到这张图:
<ImageView
android:id="@+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/girl" />
另外也可以在代码中给ImageView设置图片:
方法1:
imageView = findViewById(R.id.image_view);
imageView.setImageResource(R.drawable.girl);
方法2:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.girl);
imageView.setImageBitmap(bitmap);
方法1中通过:setImageResource(@DrawableRes int resId)方式,传入一个资源Id,在该方法内会把资源Id加载成一个Drawable。
ImageView.java中
try {
d = mContext.getDrawable(mResource);
} catch (Exception e) {
Log.w(LOG_TAG, "Unable to find resource: " + mResource, e);
// Don't try again.
mResource = 0;
}
方法2中,先把资源Id解析成一个Bitmap,然后把Bitmap设置给ImageView。
imageView.setImageBitmap(bitmap); 这个方法中,也会把传进来的bitmap转换成Drawable。
mDrawable = null;
if (mRecycleableBitmapDrawable == null) {
mRecycleableBitmapDrawable = new BitmapDrawable(mContext.getResources(), bm);
} else {
mRecycleableBitmapDrawable.setBitmap(bm);
}
setImageDrawable(mRecycleableBitmapDrawable);
以上两种方式都会把生成的Drawable赋值给ImageView的成员变量:Drawable mDrawable
设置完成后,都调用了invalidate();
这会调用父类View的invalidate(),
在View中会调用Parent,也就是ViewRootImpl的invalidate()方法。
在ViewRootImpl的invalidate()方法中,会触发scheduleTraversals,执行遍历,重新 进行布局layout测量measure绘制draw方法。
所以最终会回调到了ImageView的onDraw方法中,ondraw方法中会调用drawable.draw方法。
在draw方法中,传递进来一个画布canvas,最终会把该drawable转成一个bitmap绘制在canvas上,然后交给Native层,在屏幕上进行呈现。
@Override
protected void onDraw(Canvas canvas) {
if (mDrawMatrix == null && mPaddingTop == 0 && mPaddingLeft == 0) {
mDrawable.draw(canvas);
} else {
........
mDrawable.draw(canvas);
.........
}
}
2.BitmapFactory相关方法介绍:
//从drable目录下加载一个Bitmap
BitmapFactory.decodeResource(getResources(), R.drawable.girl);
//把指定文件解析成一个Bitmap
BitmapFactory.decodeFile(file);
//从内存数组中解析成一个Bitmap
BitmapFactory.decodeByteArray(byteArray,offset,lenght);
//从流中加载一个Bitmap,
//这个可以是一个文件流,读取本地的一个缓存文件
//也可以是一个网络流,从网络获取。
BitmapFactory.decodeStream(inputStream);
1)从文件中读取一张图片,由于设计到文件io操作,最好是放在子线程中。
示例:通过RxJava读取一张图片到内存。
首先在build.gragle引入Rxjava相关jar包:
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
implementation 'io.reactivex.rxjava2:rxjava:2.2.4'
代码实现:
public void createBitmap(ImageView imageView,String file) {
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
emitter.onNext(file);
}
}).subscribeOn(Schedulers.io()).map(new Function<String, Bitmap>() {
@Override
public Bitmap apply(String file) throws Exception {
return BitmapFactory.decodeFile(file);
}
}).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<Bitmap>() {
@Override
public void accept(Bitmap bitmap) throws Exception {
imageView.setImageBitmap(bitmap);
}
});
}
2)从网络获取图片示例:
/**
* 获取网络图片
*
* @param imageurl 图片网络地址
* @return Bitmap 返回位图
*/
public Bitmap GetImageInputStream(String imageurl) {
URL url;
HttpURLConnection connection = null;
Bitmap bitmap = null;
try {
url = new URL(imageurl);
connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(6000); //超时设置
connection.setDoInput(true);
connection.setUseCaches(false); //设置不使用缓存
InputStream inputStream = connection.getInputStream();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeStream(inputStream, null, options);
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
3.BitmapFactory.Options
1)options.inJustDecodeBounds = true;不把图加载到内存,只获取宽高。
FileInputStream fis = new FileInputStream("fileName");
BitmapFactory.Options options = new BitmapFactory.Options();
//为true则只加载图片的大小,返回一个null值,不会把图片加载到内存
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(fis, null, options);
//得到图片的宽高
int imgWidth = options.outWidth;
int imgHeight = options.outHeight;
2) options.inSampleSize = 2; 设置值大于1,加载的图片大小是原理的4分之1,
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bitmap = BitmapFactory.decodeFile(imageFile,options);
4.创建Bitmap:Bitmap.createBitmap()
1)代码示例:把View保存到一个bitmap:
public static Bitmap getBitmapForView(View view) {
int width = view.getWidth();
int height = view.getHeight();
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);//准备图片
Canvas canvas = new Canvas(bitmap);//将bitmap作为绘制画布
view.draw(canvas);//讲View特定的区域绘制到这个canvas(bitmap)上去,
return bitmap;//得到最新的画布
}
2)从一个bitmap得到另外一个大小的bitmap
Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.girl);
int x = 0;
int y = 0 ;
float rate = 1.5f;
int width = (int) (srcBitmap.getWidth()*rate);
int height = (int) (srcBitmap.getHeight()*rate);
Bitmap bitmap = Bitmap.createBitmap(srcBitmap,x,y,width,height);
3)将内存中的一个bitmap保存为一张本地图片:
Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.girl);
try {
FileOutputStream fos = new FileOutputStream("fileName");
srcBitmap.compress(Bitmap.CompressFormat.JPEG,100,fos);
} catch (FileNotFoundException e) {
e.printStackTrace();
}