【移动应用开发技术】要优雅!Android中这样加载大图片和长图片_第1页
【移动应用开发技术】要优雅!Android中这样加载大图片和长图片_第2页
【移动应用开发技术】要优雅!Android中这样加载大图片和长图片_第3页
【移动应用开发技术】要优雅!Android中这样加载大图片和长图片_第4页
【移动应用开发技术】要优雅!Android中这样加载大图片和长图片_第5页
免费预览已结束,剩余2页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

【移动应用开发技术】要优雅!Android中这样加载大图片和长图片

我们在做开发的时候总是会不可避免的遇到加载图片的情况,当图片的尺寸小于ImageView的尺寸的时候,我们当然可以很happy的去直接加载展示。但是如果我们要加载的图片远远大于ImageView的大小,直接用ImageView去展示的话,就会带来不好的视觉效果,也会占用太多的内存和性能开销。甚至这张图片足够大到导致程序oom崩溃。这个时候我们就需要对图片进行特殊的处理了:图片太大,那我就想办法把它压缩变小呗。老铁,这思路完全没毛病。BitmapFactory这个类就提供了多个解析方法(decodeResource、decodeStream、decodeFile等)用于创建Bitmap。我们可以根据图片的来源来选择解析方法。BitmapFactory为这些方法都提供了一个可选的参数BitmapFactory.Options,用来辅助我们解析图片。这个参数有一个属性inSampleSize,这个属性可以帮助我们来进行图片的压缩。为了解释inSampleSize的效果,我们可以举个栗子。

比如我们有一张2048

1536的图片,设置inSampleSize的值为4,就可以把这张图片压缩为512384,长短各缩小了4倍,所占内存就缩小了16倍。

这就明了了,inSampleSize的作用就是可以把图片的长短缩小inSampleSize倍,所占内存缩小inSampleSize的平方。

官方文档对于inSampleSize的值也做了一些要求,那就是inSampleSize的值必须大于等于1,如果给定的值小于1,那就默认为1。

而且inSampleSize的值需要是2的倍数,如果不是的话,就会自动变为离这个值向下最近的2的倍数的值,比如给定的值是3,那么最终inSampleSize的值会是2。当然了,这个inSampleSize的值我们也不可能随便就给,最好使我们能获取到照片的原始大小,再根据需要进行压缩。别急,谷歌都帮我们想好了!BitmapFactory.Options有一个属性inJustDecodeBounds,这个属性当为true的时候,表明我们当前只是为了获取当前图片的边界的大小,此时BitmapFactory的解析图片方法的返回值为null,该方法是一个十分轻量级的方法。这样我们就可以很愉快的拿到图片大小了,代码如下:BitmapFactory.Options

options

=

new

BitmapFactory.Options();

options.inJustDecodeBounds

=

true;

//

当前只为获取图片的边界大小BitmapFactory.decodeResource(getResources(),

R.drawable.bigpic,

options);int

outHeight

=

options.outHeight;int

outWidth

=

options.outWidth;

String

outMimeType

=

options.outMimeType;拿到了图片的大小,我们就可以根据需要计算出所需要压缩的大小了:private

int

caculateSampleSize(BitmapFactory.Options

options,

int

reqWidth,

int

reqHeight)

{

int

sampleSize

=

1;

int

picWidth

=

options.outWidth;

int

picHeight

=

options.outHeight;

if

(picWidth

>

reqWidth

||

picHeight

>

reqHeight)

{

int

halfPicWidth

=

picWidth

/

2;

int

halfPicHeight

=

picHeight

/

2;

while

(halfPicWidth

/

sampleSize

>

reqWidth

||

halfPicHeight

/

sampleSize

>

reqHeight)

{

sampleSize

*=

2;

}

}

return

sampleSize;

}下面就是完整的代码:

mIvBigPic

=

findViewById(R.id.iv_big_pic);

BitmapFactory.Options

options

=

new

BitmapFactory.Options();

options.inJustDecodeBounds

=

true;

//

当前只为获取图片的边界大小

BitmapFactory.decodeResource(getResources(),

R.drawable.bigpic,

options);

int

outHeight

=

options.outHeight;

int

outWidth

=

options.outWidth;

String

outMimeType

=

options.outMimeType;

System.out.println("outHeight

=

"

+

outHeight

+

"

outWidth

=

"

+

outWidth

+

"

outMimeType

=

"

+

outMimeType);

options.inJustDecodeBounds

=

false;

options.inSampleSize

=

caculateSampleSize(options,

getScreenWidth(),

getScreenHeight());

Bitmap

bitmap

=

BitmapFactory.decodeResource(getResources(),

R.drawable.bigpic,

options);

mIvBigPic.setImageBitmap(bitmap);这样图片压缩到这里就差不多结束了。有时候我们通过压缩可以取得很好的效果,但有时候效果就不那么美好了,例如长图像清明上河图,像这类的长图,如果我们直接压缩展示的话,这张图完全看不清,很影响体验。这时我们就可以采用局部展示,然后滑动查看的方式去展示图片。Android里面是利用BitmapRegionDecoder来局部展示图片的,展示的是一块矩形区域。为了完成这个功能那么就需要一个方法设置图片,另一个方法设置展示的区域。初始化

BitmapRegionDecoder提供了一系列的newInstance来进行初始化,支持传入文件路径,文件描述符和文件流InputStream等例如:mRegionDecoder=BitmapRegionDecoder.newInstance(inputStream,false);

上面这个方法解决了传入图片,接下来就要去设置展示区域了。Bitmapbitmap=mRegionDecoder.decodeRegion(mRect,sOptions);

参数一是一个Rect,参数二是BitmapFactory.Options,可以用来控制inSampleSize,inPreferredConfig等。下面是一个简单的例子,展示图片最前面屏幕大的部分:try

{

BitmapRegionDecoder

regionDecoder

=

BitmapRegionDecoder.newInstance(inputStream,

false);

BitmapFactory.Options

options1

=

new

BitmapFactory.Options();

options1.inPreferredConfig

=

Bitmap.Config.ARGB_8888;

Bitmap

bitmap

=

regionDecoder.decodeRegion(new

Rect(0,

0,

getScreenWidth(),

getScreenHeight()),

options1);

mIvBigPic.setImageBitmap(bitmap);

}

catch

(IOException

e)

{

e.printStackTrace();

}当然了,这只是最简单的用法,对于我们想要完全展示图片并没什么用!客官,稍安勿躁,前途已经明了!既然我们可以实现区域展示,那我们可不可以自定义一个View,可以随着我们的手指滑动展示图片的不同区域。yes!ofcourse。那么我们就继续吧!根据上面的分析,我们自定义控件的思路就很明白了:提供一个设置图片的路口;

重写onTouchEvent,根据用户移动的手势,修改图片显示的区域;

每次更新区域参数后,调用invalidate,onDraw里面去regionDecoder.decodeRegion拿到bitmap,去draw

废话不多说,直接上代码:public

class

BigImageView

extends

View

{

private

static

final

String

TAG

=

"BigImageView";

private

BitmapRegionDecoder

mRegionDecoder;

private

int

mImageWidth,

mImageHeight;

private

Rect

mRect

=

new

Rect();

private

static

BitmapFactory.Options

sOptions

=

new

BitmapFactory.Options();

{

sOptions.inPreferredConfig

=

Bitmap.Config.ARGB_8888;

}

public

BigImageView(Context

context)

{

this(context,

null);

}

public

BigImageView(Context

context,

@Nullable

AttributeSet

attrs)

{

this(context,

attrs,

0);

}

public

BigImageView(Context

context,

@Nullable

AttributeSet

attrs,

int

defStyleAttr)

{

super(context,

attrs,

defStyleAttr);

}

public

void

setInputStream(InputStream

inputStream)

{

try

{

mRegionDecoder

=

BitmapRegionDecoder.newInstance(inputStream,

false);

BitmapFactory.Options

options

=

new

BitmapFactory.Options();

options.inJustDecodeBounds

=

false;

BitmapFactory.decodeStream(inputStream,

null,

options);

mImageHeight

=

options.outHeight;

mImageWidth

=

options.outWidth;

requestLayout();

invalidate();

}

catch

(IOException

e)

{

e.printStackTrace();

}

}

int

downX

=

0;

int

downY

=

0;

@Override

public

boolean

onTouchEvent(MotionEvent

event)

{

switch

(event.getAction())

{

case

MotionEvent.ACTION_DOWN:

downX

=

(int)

event.getX();

downY

=

(int)

event.getY();

break;

case

MotionEvent.ACTION_MOVE:

int

curX

=

(int)

event.getX();

int

curY

=

(int)

event.getY();

int

moveX

=

curX

-

downX;

int

moveY

=

curY

-

downY;

onMove(moveX,

moveY);

System.out.println(TAG

+

"

moveX

=

"

+

moveX

+

"

curX

=

"

+

curX

+

"

downX

=

"

+

downX);

downX

=

curX;

downY

=

curY;

break;

case

MotionEvent.ACTION_UP:

break;

}

return

true;

}

private

void

onMove(int

moveX,

int

moveY)

{

if

(mImageWidth

>

getWidth())

{

mRect.offset(-moveX,

0);

checkWidth();

invalidate();

}

if

(mImageHeight

>

getHeight())

{

mRect.offset(0,

-moveY);

checkHeight();

invalidate();

}

}

private

void

checkWidth()

{

Rect

rect

=

mRect;

if

(rect.right

>

mImageWidth)

{

rect.right

=

mImageWidth;

rect.left

=

mImageWidth

-

getWidth();

}

if

(rect.left

<

0)

{

rect.left

=

0;

rect.right

=

getWidth();

}

}

private

void

checkHeight()

{

Rect

rect

=

mRect;

if

(rect.bottom

>

mImageHeight)

{

rect.bottom

=

mImageHeight;

rect.top

=

mImageHeight

-

getHeight();

}

if

(rect.top

<

0)

{

rect.top

=

0;

rect.bottom

=

getWidth();

}

}

@Override

protected

void

onMeasure(int

widthMeasureSpec,

int

heightMeasureSpec)

{

super.onM

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论