Android 自定义View实现加载巨图
加载巨图用的是:
BitmapRegionDecoder
这个类的实现就是通过Rect 获取图片中的某一块,这样就防止图片过大直接导致OOM。
我先用自定义ImageView实现,然后发现每滑动一次时,重新setImage一次,这样会有些卡顿的感觉。
于是我联想到ViewGroup,通过几个View来加载图片,于是开始行动,不过因为比较忙,所以只是用了偷懒的方式看这个想法能不能实现。下面贴代码:
/**
* Project Name: Demo0808
* Describe: 加载超大图片
* Author: laicl
* Create Time: 2016/8/11 0011 上午 11:16
*/
public class LargeImageView extends ScrollView {
//ScrollView 的子控件
private HorizontalScrollView parent;
//HorizontalScrollView 的子控件
private LinearLayout mLinear;
//BitmapRegionDecoder 获取图片的
private Rect mRect = new Rect();
private BitmapRegionDecoder mDecoder;
private Context mContext;
private int width;
private int height;
public LargeImageView(Context context) {
this(context, null);
}
public LargeImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LargeImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
//添加一个横向的ScrollView
parent = new HorizontalScrollView(context);
addView(parent);
mLinear = new LinearLayout(context);
mLinear.setOrientation(LinearLayout.VERTICAL);
//横向的ScrollView中添加一个垂直的LinearLayout
parent.addView(mLinear);
WindowManager wm = (WindowManager) mContext
.getSystemService(Context.WINDOW_SERVICE);
width = wm.getDefaultDisplay().getWidth();
height = wm.getDefaultDisplay().getHeight();
parent.setHorizontalScrollBarEnabled(false);
setVerticalScrollBarEnabled(false);
}
/**
* 设置图片
* @param res 资源文件
*/
public void setImageView(int res){
initData(res);
}
private void initData(int res){
try {
InputStream is = mContext.getResources().openRawResource(res);
mDecoder = BitmapRegionDecoder.newInstance(is, true);
}catch (Exception e){
Toast.makeText(mContext, e.getMessage(), Toast.LENGTH_SHORT);
e.printStackTrace();
return;
}
int imageWidth = mDecoder.getWidth();
int imgHeight = mDecoder.getHeight();
//如果图片的宽度为0
if(imageWidth == 0){
return;
}
//如果图片的高度为0
if(imgHeight == 0){
return;
}
//判断xml中该控件设置的大小
if(getMeasuredHeight() == 0){
if(getMeasuredWidth() == 0){
setMeasuredDimension(width,height);
}else{
setMeasuredDimension(getMeasuredWidth(),height);
}
}else{
if(getMeasuredWidth() == 0){
setMeasuredDimension(width,getMeasuredHeight());
}
}
int wLength = 0;
int hLength = 0;
//计算宽度需要的布局数量,根据控件宽度来计算
if(imageWidth % getMeasuredWidth() == 0){
wLength = imageWidth/getMeasuredWidth();
}else{
wLength = imageWidth/getMeasuredWidth() + 1;
}
//计算高度需要的布局数量,根据控件高度来计算
if(imgHeight % getMeasuredHeight() == 0){
hLength = imgHeight/getMeasuredHeight();
}else{
hLength = imgHeight/getMeasuredHeight() + 1;
}
//通过计算数量进行布局添加
for(int i = 0;i<hLength;i++){
LinearLayout linear = new LinearLayout(mContext);
linear.setOrientation(LinearLayout.HORIZONTAL);
for(int j = 0;j<wLength;j++){
ImageView image = new ImageView(mContext);
Bitmap bitmap = getBitmap(0 + getMeasuredHeight() * i, 0 + getMeasuredWidth() * j, getMeasuredWidth(), getMeasuredHeight());
image.setImageBitmap(bitmap);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(bitmap.getWidth(),bitmap.getHeight());
image.setLayoutParams(layoutParams);
linear.addView(image);
}
mLinear.addView(linear);
}
}
//根据传进来的数值获取bitmap
private Bitmap getBitmap(int top,int left,int w,int h){
if(left < 0){
left = 0;
}
mRect.left = left;
mRect.top = top;
//限制不能超过图片宽度
if(mRect.left + w > mDecoder.getWidth()){
mRect.right = mDecoder.getWidth();
}else{
mRect.right = mRect.left + w;
}
//限制不能超过图片高度
if(mRect.top + h > mDecoder.getHeight()){
mRect.bottom = mDecoder.getHeight();
}else{
mRect.bottom = mRect.top + h;
}
Bitmap bitmap = mDecoder.decodeRegion(mRect, null);
return bitmap;
}
}
运行后,发现可行。不过这是偷懒写的,这样可能会因为布局过多出现问题,可以自己集成LinearLayout或者ViewGroup写一下,然后监听滑动事件,通过布局复用,来控制布局数量。
好了,到此为止,效果图就不贴了。等后续我会去尝试一下布局复用,后续再更新。祝大家开心每一天!