现在长图越来越多 例如微博上就有很多长图 这篇文章就是实现加载长图时能最少的占用内存
首先要自定义一个View代码如下
public class BigView extends View implements GestureDetector.OnGestureListener,View.OnTouchListener{
private final Rect mRect;
private final BitmapFactory.Options mOptions;
private final Scroller mScroller;
private final GestureDetector mGestureDetetor;
private int mImageWidth;
private int mImageHieght;
private BitmapRegionDecoder mDecoder;
private int mViewWidth;
private int mViewHeight;
private float mScale;
private Bitmap mBitmap;
public BigView(Context context) {
this(context,null);
}
public BigView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public BigView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//第一步设置bigview需要的成员变量
mRect=new Rect();
mOptions =new BitmapFactory.Options();//内存复用
mGestureDetetor =new GestureDetector(context,this);//手势识别
mScroller =new Scroller(context);//滚动类
setOnTouchListener(this);
}
//第二步 ,设置图片,并且得到图片信息
public void setImage(InputStream is){
//获取图片宽和高,注意:不能将整个图片加载进内存
mOptions.inJustDecodeBounds=true;
BitmapFactory.decodeStream(is,null,mOptions);
mImageWidth=mOptions.outWidth;//获取图片的宽
mImageHieght=mOptions.outHeight;//获取图片的高
mOptions.inMutable=true;//开启复用
mOptions.inPreferredConfig= Bitmap.Config.RGB_565; //设置图片格式为rgb_565
mOptions.inJustDecodeBounds=false;
//区域解码器
try {
mDecoder= BitmapRegionDecoder.newInstance(is,false);
} catch (IOException e) {
e.printStackTrace();
}
requestLayout();
}
//第三步,开始测量,得到view的宽高,测量加载的图片到底缩放成什么样
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mViewWidth=getMeasuredWidth();//获取view的宽
mViewHeight=getMeasuredHeight();//获取view的高
//确定加载图片的区域
mRect.left=0;
mRect.top=0;
mRect.right=mImageWidth;
//计算缩放因子
mScale=mViewWidth/(float)mImageWidth;
mRect.bottom= (int) (mViewHeight/mScale);
}
//第4步 画出具体的内容
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//判断解码器是不是为空,如果解码器为空,表示没有设置过图片
if (mDecoder==null){
return;
}
//真正内存复用 //f复用的bitmap 必须跟即将解码的bitmap尺寸一样
mOptions.inBitmap=mBitmap;
mBitmap=mDecoder.decodeRegion(mRect,mOptions);//指定解码区域
//得到一个矩阵进行缩放,相当于的到view的大小
Matrix matrix=new Matrix();
matrix.setScale(mScale,mScale);
canvas.drawBitmap(mBitmap,matrix,null);
}
//第5步,处理点击事件
@Override
public boolean onTouch(View v, MotionEvent event) {
//直接将事件交给手势事件处理
return mGestureDetetor.onTouchEvent(event);
}
//第6步 手按下去
@Override
public boolean onDown(MotionEvent e) {
//如果移动没有停止,就强行将它停止
if (!mScroller.isFinished()){
mScroller.forceFinished(true);
}
//继续接收后续事件
return true;
}
//第7 步 处理滑动事件
//e1:开始事件,手指按下去,开始获取坐标
//e2:获取当前事件坐标
//xy:xy轴移动的距离
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
//手上下移动的时候,mRect需要改变显示的区域
mRect.offset(0, (int) distanceY);
//移动时处理到达顶部和底部的情况
if (mRect.bottom>mImageHieght){
mRect.bottom=mImageHieght;
mRect.top= (int) (mImageHieght-(mViewHeight/mScale));
}
if (mRect.top<0){
mRect.top=0;
mRect.bottom= (int) (mViewHeight/mScale);
}
invalidate();//重绘
return false;
}
//第8 步 处理惯性问题
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
mScroller.fling(0,mRect.top,0,(int)-velocityY,0,0,0,mImageHieght-(int)(mViewHeight/mScale));
return false;
}
//第9步 处理计算结果
@Override
public void computeScroll() {
if (mScroller.isFinished()){//滚动结束
return;
}
if (mScroller.computeScrollOffset()){//滚动未结束
mRect.top=mScroller.getCurrY();
mRect.bottom=mRect.top+(int)(mViewHeight/mScale);
invalidate();
}
super.computeScroll();
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
}
然后接下来就是来使用自己写的View来加载图片 代码如下
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BigView bigView= (BigView) findViewById(R.id.bigview);
try {
InputStream is=getAssets().open("c.png");
bigView.setImage(is);
} catch (IOException e) {
e.printStackTrace();
}
}
}
布局代码如下:
<com.example.ttest.BigView
android:id="@+id/bigview"
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
/>
至此使用内存复用加载长图就已经实现完成