准备
当有一张图片很大的时候,甚至超出手机屏幕的时候,我们又想支持原来的清晰度来显示,这时候我们这篇文章就是来实现这样一种功能,本篇文章主要是基于自定义View的知识点。大致分为以下两个步骤:
- 截取图片的部分大小放在当前的大小中
- 支持滑动,当滑动的时候更新截取图片的部分
先看效果
第一步
我们先认识一个类BitmapRegionDecoder, 这个类就可以对一张图片进行操作了,本来想用Bitmap当中的截取图片的方法,后来发现这个类更好,下面是他得基本用法。
InputStream inputStream = getResources().getAssets().open("world.jpg");
BitmapRegionDecoder bitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, false);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmapDraw = bitmapRegionDecoder.decodeRegion(mRect, mOptions);//mRect针对图片大小坐标的截取矩形
这样就能截取一个大的图片的一部分了,这时候是不是有一点点思路,下一步就是要让这个图片支持跟随手势进行滑动,然后我们再不停地截取图片需要显示的那一部分,再渲染到View上面好了,下面继续。
第二步
这一步主要就是计算滑动的距离,扩展的部分,就行了,我们这里用到的滑动手势工具类GestureDetector,不会的小伙伴们,你只要看一下我这段代码一样可以明白这其中的道理
class MGestureListener implements GestureDetector.OnGestureListener {
@Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
//Logger.i("--------scroll:" + distanceX + "," + distanceY);
float left = mRect.left + distanceX;
left = left < 0 ? 0 : left; //处理一下左边界
float right = mRect.right + distanceX;
right = right > bitmapWidth ? bitmapWidth : right; //处理右边界
float top = mRect.top + distanceY;
top = top < 0 ? 0 : top; //上边界
float bottom = mRect.bottom + distanceY;
bottom = bottom > bitmapHeight ? bitmapHeight : bottom; //下边界
//当处于边界的时候,我们这里计算mRect的左右上下值
if (left == 0) {
right = getMeasuredWidth();
}
if (right == bitmapWidth) {
left = bitmapWidth - getMeasuredWidth();
}
if (top == 0) {
bottom = getMeasuredHeight();
}
if (bottom == bitmapHeight) {
top = bitmapHeight - getMeasuredHeight();
}
mRect.left = (int) left;
mRect.right = (int) right;
mRect.top = (int) top;
mRect.bottom = (int) bottom;
Logger.e("---------width:" + (right - left) + ",height:" + (bottom - top));
invalidate(); //刷新重绘View
return true;
}
@Override
public boolean onDown(MotionEvent e) {
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return false;
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public void onLongPress(MotionEvent e) { }
@Override
public void onShowPress(MotionEvent e) { }
}
做完了这些,我们再在View初始化的时候去实例化这个对象
mGestureDetector = new GestureDetector(context, new MGestureListener());
还有onDraw中执行操作
@Overrideprotected
void onDraw(Canvas canvas) {
super.onDraw(canvas);
bitmapDraw = bitmapRegionDecoder.decodeRegion(mRect, mOptions);
canvas.drawBitmap(bitmapDraw, 0, 0, null);
}
基本上核心代码就这些了,还有几个,计算的时候也要使用到的,有需要的可以稍微记一下
WindowManager manager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = getResources().getDisplayMetrics();
manager.getDefaultDisplay().getMetrics(metrics);
screenWidth = metrics.widthPixels; //获取屏幕宽度
screenHeight = metrics.heightPixels; //获取屏幕高度
int height=getSupportActionBar().getHeight(); //获取toolbar的高度
//第一种获取状态栏的高度
private int getStatusBarHeight() {
try {
Class<?> c = Class.forName("com.android.internal.R$dimen");
Object obj = c.newInstance();
Field field = c.getField("status_bar_height");
int x = Integer.parseInt(field.get(obj).toString());
return getResources().getDimensionPixelSize(x);
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
//第二种方式获取状态栏的高度
private int getStatusBarHeight(Context context) {
int result = 0;
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = context.getResources().getDimensionPixelSize(resourceId);
}
return result;
}
好了,到此就算是大功告成了。
github代码地址