Android通过自定义ImageView控件实现图片的缩放和拖动的实现代码
程序员文章站
2024-03-04 11:21:29
概述:通过自定义imageview控件,在xml布局里面调用自定的组件实现图片的缩放。
/**
* 自定义的imageview控制,可对图片进行多点触控缩放和拖...
概述:通过自定义imageview控件,在xml布局里面调用自定的组件实现图片的缩放。
/** * 自定义的imageview控制,可对图片进行多点触控缩放和拖动 * * @author qiuwanyong */ public class myimageview extends imageview { /** * 初始化状态常量 */ public static final int status_init = 1; /** * 图片放大状态常量 */ public static final int status_zoom_out = 2; /** * 图片缩小状态常量 */ public static final int status_zoom_in = 3; /** * 图片拖动状态常量 */ public static final int status_move = 4; /** * 用于对图片进行移动和缩放变换的矩阵 */ private matrix matrix = new matrix(); /** * 待展示的bitmap对象 */ private bitmap sourcebitmap; /** * 记录当前操作的状态,可选值为status_init、status_zoom_out、status_zoom_in和status_move */ private int currentstatus; /** * zoomimageview控件的宽度 */ private int width; /** * zoomimageview控件的高度 */ private int height; /** * 记录两指同时放在屏幕上时,中心点的横坐标值 */ private float centerpointx; /** * 记录两指同时放在屏幕上时,中心点的纵坐标值 */ private float centerpointy; /** * 记录当前图片的宽度,图片被缩放时,这个值会一起变动 */ private float currentbitmapwidth; /** * 记录当前图片的高度,图片被缩放时,这个值会一起变动 */ private float currentbitmapheight; /** * 记录上次手指移动时的横坐标 */ private float lastxmove = -1; /** * 记录上次手指移动时的纵坐标 */ private float lastymove = -1; /** * 记录手指在横坐标方向上的移动距离 */ private float moveddistancex; /** * 记录手指在纵坐标方向上的移动距离 */ private float moveddistancey; /** * 记录图片在矩阵上的横向偏移值 */ private float totaltranslatex; /** * 记录图片在矩阵上的纵向偏移值 */ private float totaltranslatey; /** * 记录图片在矩阵上的总缩放比例 */ private float totalratio; /** * 记录手指移动的距离所造成的缩放比例 */ private float scaledratio; /** * 记录图片初始化时的缩放比例 */ private float initratio; /** * 记录上次两指之间的距离 */ private double lastfingerdis; /** * zoomimageview构造函数,将当前操作状态设为status_init。 * * @param context * @param attrs */ public myimageview(context context, attributeset attrs) { super(context, attrs); currentstatus = status_init; } /** * 将待展示的图片设置进来。 * * @param bitmap * 待展示的bitmap对象 */ public void setimagebitmap(bitmap bitmap) { sourcebitmap = bitmap; invalidate(); } @override protected void onlayout(boolean changed, int left, int top, int right, int bottom) { super.onlayout(changed, left, top, right, bottom); if (changed) { // 分别获取到zoomimageview的宽度和高度 width = getwidth(); height = getheight(); } } @suppresslint("newapi") @override public boolean ontouchevent(motionevent event) { if (initratio == totalratio) { getparent().requestdisallowintercepttouchevent(false); } else { getparent().requestdisallowintercepttouchevent(true); } switch (event.getactionmasked()) { case motionevent.action_pointer_down: if (event.getpointercount() == 2) { // 当有两个手指按在屏幕上时,计算两指之间的距离 lastfingerdis = distancebetweenfingers(event); } break; case motionevent.action_cancel: case motionevent.action_move: if (event.getpointercount() == 1) { // 只有单指按在屏幕上移动时,为拖动状态 float xmove = event.getx(); float ymove = event.gety(); if (lastxmove == -1 && lastymove == -1) { lastxmove = xmove; lastymove = ymove; } currentstatus = status_move; moveddistancex = xmove - lastxmove; moveddistancey = ymove - lastymove; // 进行边界检查,不允许将图片拖出边界 if (totaltranslatex + moveddistancex > 0) { moveddistancex = 0; } else if (width - (totaltranslatex + moveddistancex) > currentbitmapwidth) { moveddistancex = 0; } if (totaltranslatey + moveddistancey > 0) { moveddistancey = 0; } else if (height - (totaltranslatey + moveddistancey) > currentbitmapheight) { moveddistancey = 0; } // 调用ondraw()方法绘制图片 invalidate(); lastxmove = xmove; lastymove = ymove; } else if (event.getpointercount() == 2) { // 有两个手指按在屏幕上移动时,为缩放状态 centerpointbetweenfingers(event); double fingerdis = distancebetweenfingers(event); if (fingerdis > lastfingerdis) { currentstatus = status_zoom_out; } else { currentstatus = status_zoom_in; } // 进行缩放倍数检查,最大只允许将图片放大4倍,最小可以缩小到初始化比例 if ((currentstatus == status_zoom_out && totalratio < 4 * initratio) || (currentstatus == status_zoom_in && totalratio > initratio)) { scaledratio = (float) (fingerdis / lastfingerdis); totalratio = totalratio * scaledratio; if (totalratio > 4 * initratio) { totalratio = 4 * initratio; } else if (totalratio < initratio) { totalratio = initratio; } // 调用ondraw()方法绘制图片 invalidate(); lastfingerdis = fingerdis; } } break; case motionevent.action_pointer_up: if (event.getpointercount() == 2) { // 手指离开屏幕时将临时值还原 lastxmove = -1; lastymove = -1; } break; case motionevent.action_up: // 手指离开屏幕时将临时值还原 lastxmove = -1; lastymove = -1; break; default: break; } return true; } /** * 根据currentstatus的值来决定对图片进行什么样的绘制操作。 */ @override protected void ondraw(canvas canvas) { super.ondraw(canvas); switch (currentstatus) { case status_zoom_out: case status_zoom_in: zoom(canvas); break; case status_move: move(canvas); break; case status_init: initbitmap(canvas); default: if (sourcebitmap != null) { canvas.drawbitmap(sourcebitmap, matrix, null); } break; } } /** * 对图片进行缩放处理。 * * @param canvas */ private void zoom(canvas canvas) { matrix.reset(); // 将图片按总缩放比例进行缩放 matrix.postscale(totalratio, totalratio); float scaledwidth = sourcebitmap.getwidth() * totalratio; float scaledheight = sourcebitmap.getheight() * totalratio; float translatex = 0f; float translatey = 0f; // 如果当前图片宽度小于屏幕宽度,则按屏幕中心的横坐标进行水平缩放。否则按两指的中心点的横坐标进行水平缩放 if (currentbitmapwidth < width) { translatex = (width - scaledwidth) / 2f; } else { translatex = totaltranslatex * scaledratio + centerpointx * (1 - scaledratio); // 进行边界检查,保证图片缩放后在水平方向上不会偏移出屏幕 if (translatex > 0) { translatex = 0; } else if (width - translatex > scaledwidth) { translatex = width - scaledwidth; } } // 如果当前图片高度小于屏幕高度,则按屏幕中心的纵坐标进行垂直缩放。否则按两指的中心点的纵坐标进行垂直缩放 if (currentbitmapheight < height) { translatey = (height - scaledheight) / 2f; } else { translatey = totaltranslatey * scaledratio + centerpointy * (1 - scaledratio); // 进行边界检查,保证图片缩放后在垂直方向上不会偏移出屏幕 if (translatey > 0) { translatey = 0; } else if (height - translatey > scaledheight) { translatey = height - scaledheight; } } // 缩放后对图片进行偏移,以保证缩放后中心点位置不变 matrix.posttranslate(translatex, translatey); totaltranslatex = translatex; totaltranslatey = translatey; currentbitmapwidth = scaledwidth; currentbitmapheight = scaledheight; canvas.drawbitmap(sourcebitmap, matrix, null); } /** * 对图片进行平移处理 * * @param canvas */ private void move(canvas canvas) { matrix.reset(); // 根据手指移动的距离计算出总偏移值 float translatex = totaltranslatex + moveddistancex; float translatey = totaltranslatey + moveddistancey; // 先按照已有的缩放比例对图片进行缩放 matrix.postscale(totalratio, totalratio); // 再根据移动距离进行偏移 matrix.posttranslate(translatex, translatey); totaltranslatex = translatex; totaltranslatey = translatey; canvas.drawbitmap(sourcebitmap, matrix, null); } /** * 对图片进行初始化操作,包括让图片居中,以及当图片大于屏幕宽高时对图片进行压缩。 * * @param canvas */ private void initbitmap(canvas canvas) { if (sourcebitmap != null) { matrix.reset(); int bitmapwidth = sourcebitmap.getwidth(); int bitmapheight = sourcebitmap.getheight(); if (bitmapwidth > width || bitmapheight > height) { if (bitmapwidth - width > bitmapheight - height) { // 当图片宽度大于屏幕宽度时,将图片等比例压缩,使它可以完全显示出来 float ratio = width / (bitmapwidth * 1.0f); matrix.postscale(ratio, ratio); float translatey = (height - (bitmapheight * ratio)) / 2f; // 在纵坐标方向上进行偏移,以保证图片居中显示 matrix.posttranslate(0, translatey); totaltranslatey = translatey; totalratio = initratio = ratio; } else { // 当图片高度大于屏幕高度时,将图片等比例压缩,使它可以完全显示出来 float ratio = height / (bitmapheight * 1.0f); matrix.postscale(ratio, ratio); float translatex = (width - (bitmapwidth * ratio)) / 2f; // 在横坐标方向上进行偏移,以保证图片居中显示 matrix.posttranslate(translatex, 0); totaltranslatex = translatex; totalratio = initratio = ratio; } currentbitmapwidth = bitmapwidth * initratio; currentbitmapheight = bitmapheight * initratio; } else { // 当图片的宽高都小于屏幕宽高时,直接让图片居中显示 float translatex = (width - sourcebitmap.getwidth()) / 2f; float translatey = (height - sourcebitmap.getheight()) / 2f; matrix.posttranslate(translatex, translatey); totaltranslatex = translatex; totaltranslatey = translatey; totalratio = initratio = 1f; currentbitmapwidth = bitmapwidth; currentbitmapheight = bitmapheight; } canvas.drawbitmap(sourcebitmap, matrix, null); } } /** * 计算两个手指之间的距离。 * * @param event * @return 两个手指之间的距离 */ @suppresslint("newapi") private double distancebetweenfingers(motionevent event) { float disx = math.abs(event.getx(0) - event.getx(1)); float disy = math.abs(event.gety(0) - event.gety(1)); return math.sqrt(disx * disx + disy * disy); } /** * 计算两个手指之间中心点的坐标。 * * @param event */ @suppresslint("newapi") private void centerpointbetweenfingers(motionevent event) { float xpoint0 = event.getx(0); float ypoint0 = event.gety(0); float xpoint1 = event.getx(1); float ypoint1 = event.gety(1); centerpointx = (xpoint0 + xpoint1) / 2; centerpointy = (ypoint0 + ypoint1) / 2; } }
布局中调用
以上所述是小编给大家介绍的android通过自定义imageview控件实现图片的缩放和拖动的实现代码,希望对大家有所帮助