加载巨图用的是:
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写一下,然后监听滑动事件,通过布局复用,来控制布局数量。
好了,到此为止,效果图就不贴了。等后续我会去尝试一下布局复用,后续再更新。祝大家开心每一天!