先贴上美图秀秀原作的效果图,右边是我仿的效果图。
刚一眼打量过去,吸引我们的就是那四个大点。就从它开始吧,目前看来这个大点是一个图片,当点击下去的时候有加亮的效果,可能这又是一张图片。我们先不要考虑这些,先把它当做一个普通的Point来处理就好了。正常来讲的话,我们这里需要四个Point,但是考虑到后面我们对这些点进行复杂的运算和事件处理,只要申请两个Point就好了,以便降低问题的复杂度。两个即leftUpPoint和rightDownPoint。(其余两个点只要由这个两点拼一下就可以了)
那么画中间的框就用下面的代码:
paint.setARGB(255, 255, 255, 255);paint.setStrokeWidth(3);paint.setStyle(Paint.Style.STROKE);Rect frameRect = new Rect(leftUpPoint.x + offsetLeftUpPoint.x,leftUpPoint.y + offsetLeftUpPoint.y, rightDownPoint.x+ offsetRightDownPoint.x, rightDownPoint.y+ offsetRightDownPoint.y);canvas.drawRect(frameRect, paint);
offsetLeftUpPoint和offsetRightDownPoint是leftUpPoint和rightDownPoint相对的偏移量,后面事件处理的时候会用到。
然后顺势把里面的线条和数字画出来。代码如下:
// 画内框里线条paint.setARGB(90, 255, 255, 255);paint.setStrokeWidth(2);canvas.drawLine(leftUpPoint.x + this.getDynamicFrameWidth() / 3+ offsetLeftUpPoint.x, leftUpPoint.y + offsetLeftUpPoint.y,leftUpPoint.x + this.getDynamicFrameWidth() / 3+ offsetLeftUpPoint.x, rightDownPoint.y+ offsetRightDownPoint.y, paint);canvas.drawLine(rightDownPoint.x - this.getDynamicFrameWidth() / 3+ offsetRightDownPoint.x, leftUpPoint.y + offsetLeftUpPoint.y,rightDownPoint.x - this.getDynamicFrameWidth() / 3+ offsetRightDownPoint.x, rightDownPoint.y+ offsetRightDownPoint.y, paint);canvas.drawLine(leftUpPoint.x + offsetLeftUpPoint.x, leftUpPoint.y+ this.getDynamicFrameHeight() / 3 + offsetLeftUpPoint.y,rightDownPoint.x + offsetRightDownPoint.x,leftUpPoint.y + this.getDynamicFrameHeight() / 3+ offsetLeftUpPoint.y, paint);canvas.drawLine(leftUpPoint.x + offsetLeftUpPoint.x, rightDownPoint.y- this.getDynamicFrameHeight() / 3 + offsetRightDownPoint.y,rightDownPoint.x + offsetRightDownPoint.x, rightDownPoint.y- this.getDynamicFrameHeight() / 3+ offsetRightDownPoint.y, paint);// 画外框里的数字paint.setARGB(255, 255, 255, 255);paint.setStrokeWidth(0);paint.setTextSize(10);paint.setTextAlign(Align.CENTER);canvas.drawText(this.getDynamicFrameWidth() + "*"+ this.getDynamicFrameHeight(),(leftUpPoint.x + offsetLeftUpPoint.x + rightDownPoint.x + offsetRightDownPoint.x) / 2,(leftUpPoint.y + offsetLeftUpPoint.y + rightDownPoint.y+ offsetRightDownPoint.y + 10) / 2, paint);
没有什么说的,大家只要注意一下线条和数字与中间框的坐标关系就可以了,代码上提到的:getDynamicFrameWidth()和getDynamicFrameHeight()这两个方法,后面也会说明的。
再看仔细看一下中间框的外围的情况,像是有一种透明黒的效果,那就对了,这也是一种效果哦,也需要“画”的哦。
还是注意分析与中间框的坐标关系,代码如下咯:
// 画内框外围
paint.setARGB(180, 0, 0, 0);
Rect top = new Rect(0, 0, width, leftUpPoint.y + offsetLeftUpPoint.y);
Rect bottom = new Rect(0, rightDownPoint.y + offsetRightDownPoint.y,width, height);
Rect left = new Rect(0, leftUpPoint.y + offsetLeftUpPoint.y,leftUpPoint.x + offsetLeftUpPoint.x, rightDownPoint.y + offsetRightDownPoint.y);
Rect right = new Rect(rightDownPoint.x + offsetRightDownPoint.x, leftUpPoint.y + offsetLeftUpPoint.y, width, rightDownPoint.y + offsetRightDownPoint.y);
canvas.drawRect(top, paint);
canvas.drawRect(bottom, paint);
canvas.drawRect(left, paint);
canvas.drawRect(right, paint);
静态的问题已经基本处理完了,下面我们要把拖动和放大缩小这两动态问题考虑进来。
那就需要我们重写View的onTouchEvent()这个方法,我们要实现整个效果全在这个方法里呢。
第一步,我要将这个方法的返回值设置成true,否则就接收不到后面的ACTION_MOVE和ACTION_UP这两个事件了。要是这样就悲剧了大哭
第二步,在设置返回值之前,要执行一下this.invalidate();这个方法,因为View的onDraw()方法是被动的,只有当View无效的时候才会执行。
预热一下,说明一下我们需要东西:
a:onTouchEvent()方法的框架,即能处理ACTION_DOWN、ACTION_MOVE和ACTION_UP三种事件。
b:记录leftUpPoint和rightDownPoint两个点的偏移量offsetLeftUpPoint和offsetRightDownPoint
c:记录onTouchEvent()上一次点击的坐标lastPoint,在执行完ACTION_DOWN事件,再执行ACTION_MOVE事件时会用到。
d:六种动作事件的标识符EVENT_NONE = 0, EVENT_MOVE = 1, EVENT_SCALE_LEFTUP = 2, EVENT_SCALE_LEFTDOWN = 3, EVENT_SCALE_RIGHTUP = 4, EVENT_SCALE_RIGHTDOWN = 5;及它们的掌控件变量eventType
e:还有那四个取得中间框长和宽和方法
private int getDynamicFrameWidth() {return (rightDownPoint.x + offsetRightDownPoint.x)- (leftUpPoint.x + offsetLeftUpPoint.x);}private int getDynamicFrameHeight() {return (rightDownPoint.y + offsetRightDownPoint.y)- (leftUpPoint.y + offsetLeftUpPoint.y);}
什么是又动态呢?在onDraw()方法用到长和宽就是动态。关于这一点,大家
在仔细想一想就会明白了。不用我多说什么,我把整个onTouchEvent()方法里的代码贴上来,大家看一下就会明白了,:
/** 接收触屏事件*/@Overridepublic boolean onTouchEvent(MotionEvent event) {// TODO Auto-generated method stubint x = (int) event.getX();int y = (int) event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:handleActionDown(x, y);break;case MotionEvent.ACTION_MOVE:handleActionMove(x, y);break;case MotionEvent.ACTION_UP:handleActionUp();break;}this.invalidate();return true;}
/*** 得到eventType事件类型的值和lastPoint坐标点* * @param x* x坐标* @param y* y坐标*/private void handleActionDown(int x, int y) {// moveif (leftUpPoint.x < x && x < rightDownPoint.x && leftUpPoint.y < y&& y < rightDownPoint.y) {lastPoint = new Point(x, y);eventType = EVENT_MOVE;// leftup} else if (Math.abs(x - leftUpPoint.x) < DOT_RADIO&& Math.abs(y - leftUpPoint.y) < DOT_RADIO) {lastPoint = new Point(x, y);eventType = EVENT_SCALE_LEFTUP;// leftdown} else if (Math.abs(x - leftUpPoint.x) < DOT_RADIO&& Math.abs(y - rightDownPoint.y) < DOT_RADIO) {lastPoint = new Point(x, y);eventType = EVENT_SCALE_LEFTDOWN;// rightup} else if (Math.abs(x - rightDownPoint.x) < DOT_RADIO&& Math.abs(y - leftUpPoint.y) < DOT_RADIO) {lastPoint = new Point(x, y);eventType = EVENT_SCALE_RIGHTUP;// rightdown} else if (Math.abs(x - rightDownPoint.x) < DOT_RADIO&& Math.abs(y - rightDownPoint.y) < DOT_RADIO) {lastPoint = new Point(x, y);eventType = EVENT_SCALE_RIGHTDOWN;} else {eventType = EVENT_NONE;}}/*** 根据eventType进行处理* * @param x* x坐标* @param y* y坐标*/private void handleActionMove(int x, int y) {switch (eventType) {case EVENT_MOVE:offsetLeftUpPoint.x = x - lastPoint.x;offsetLeftUpPoint.y = y - lastPoint.y;moveRestriction();offsetRightDownPoint.x = offsetLeftUpPoint.x;offsetRightDownPoint.y = offsetLeftUpPoint.y;break;case EVENT_SCALE_LEFTUP:offsetLeftUpPoint.x = x - lastPoint.x;offsetLeftUpPoint.y = y - lastPoint.y;leftUpScaleRestriction();offsetRightDownPoint.x = 0;offsetRightDownPoint.y = 0;break;case EVENT_SCALE_LEFTDOWN:offsetLeftUpPoint.x = x - lastPoint.x;offsetRightDownPoint.y = y - lastPoint.y;leftDownScaleRestriction();offsetLeftUpPoint.y = 0;offsetRightDownPoint.x = 0;break;case EVENT_SCALE_RIGHTUP:offsetRightDownPoint.x = x - lastPoint.x;offsetLeftUpPoint.y = y - lastPoint.y;rightUpScaleRestriction();offsetRightDownPoint.y = 0;offsetLeftUpPoint.x = 0;break;case EVENT_SCALE_RIGHTDOWN:offsetRightDownPoint.x = x - lastPoint.x;offsetRightDownPoint.y = y - lastPoint.y;rightDownScaleRestriction();offsetLeftUpPoint.x = 0;offsetLeftUpPoint.y = 0;break;case EVENT_NONE:break;}}/*** 进行复位*/private void handleActionUp() {leftUpPoint.x += offsetLeftUpPoint.x;leftUpPoint.y += offsetLeftUpPoint.y;rightDownPoint.x += offsetRightDownPoint.x;rightDownPoint.y += offsetRightDownPoint.y;offsetLeftUpPoint.x = 0;offsetLeftUpPoint.y = 0;offsetRightDownPoint.x = 0;offsetRightDownPoint.y = 0;eventType = EVENT_NONE;}/*** 移动限制*/private void moveRestriction() {if (leftUpPoint.x + offsetLeftUpPoint.x < 0) {offsetLeftUpPoint.x = -leftUpPoint.x;} else if (leftUpPoint.x + offsetLeftUpPoint.x > this.getWidth()- (rightDownPoint.x - leftUpPoint.x)) {offsetLeftUpPoint.x = this.getWidth()- (rightDownPoint.x - leftUpPoint.x) - leftUpPoint.x;}if (leftUpPoint.y + offsetLeftUpPoint.y < 0) {offsetLeftUpPoint.y = -leftUpPoint.y;} else if (leftUpPoint.y + offsetLeftUpPoint.y > this.getHeight()- (rightDownPoint.y - leftUpPoint.y)) {offsetLeftUpPoint.y = this.getHeight()- (rightDownPoint.y - leftUpPoint.y) - leftUpPoint.y;}}/*** 左上缩放限制*/private void leftUpScaleRestriction() {if (leftUpPoint.x + offsetLeftUpPoint.x < 0) {offsetLeftUpPoint.x = -leftUpPoint.x;}if (rightDownPoint.x - (leftUpPoint.x + offsetLeftUpPoint.x) < FRAME_MIN_WIDTH) {offsetLeftUpPoint.x = rightDownPoint.x - leftUpPoint.x- FRAME_MIN_WIDTH;}if (leftUpPoint.y + offsetLeftUpPoint.y < 0) {offsetLeftUpPoint.y = -leftUpPoint.y;}if (rightDownPoint.y - (leftUpPoint.y + offsetLeftUpPoint.y) < FRAME_MIN_HEIGHT) {offsetLeftUpPoint.y = rightDownPoint.y - leftUpPoint.y- FRAME_MIN_HEIGHT;}}/*** 左下缩放限制*/private void leftDownScaleRestriction() {if (leftUpPoint.x + offsetLeftUpPoint.x < 0) {offsetLeftUpPoint.x = -leftUpPoint.x;}if (rightDownPoint.x - (leftUpPoint.x + offsetLeftUpPoint.x) < FRAME_MIN_WIDTH) {offsetLeftUpPoint.x = rightDownPoint.x - leftUpPoint.x- FRAME_MIN_WIDTH;}if (rightDownPoint.y + offsetRightDownPoint.y > this.getHeight()) {offsetRightDownPoint.y = this.getHeight() - rightDownPoint.y;}if ((rightDownPoint.y + offsetRightDownPoint.y) - leftUpPoint.y < FRAME_MIN_HEIGHT) {offsetRightDownPoint.y = FRAME_MIN_HEIGHT + leftUpPoint.y- rightDownPoint.y;}}/*** 右上缩放限制*/private void rightUpScaleRestriction() {if (rightDownPoint.x + offsetRightDownPoint.x > this.getWidth()) {offsetRightDownPoint.x = this.getWidth() - rightDownPoint.x;}if ((rightDownPoint.x + offsetRightDownPoint.x) - leftUpPoint.x < FRAME_MIN_WIDTH) {offsetRightDownPoint.x = FRAME_MIN_WIDTH + leftUpPoint.x- rightDownPoint.x;}if (leftUpPoint.y + offsetLeftUpPoint.y < 0) {offsetLeftUpPoint.y = -leftUpPoint.y;}if (rightDownPoint.y - (leftUpPoint.y + offsetLeftUpPoint.y) < FRAME_MIN_HEIGHT) {offsetLeftUpPoint.y = rightDownPoint.y - leftUpPoint.y- FRAME_MIN_HEIGHT;}}/*** 右下缩放限制*/private void rightDownScaleRestriction() {if (rightDownPoint.x + offsetRightDownPoint.x > this.getWidth()) {offsetRightDownPoint.x = this.getWidth() - rightDownPoint.x;}if ((rightDownPoint.x + offsetRightDownPoint.x) - leftUpPoint.x < FRAME_MIN_WIDTH) {offsetRightDownPoint.x = FRAME_MIN_WIDTH + leftUpPoint.x- rightDownPoint.x;}if (rightDownPoint.y + offsetRightDownPoint.y > this.getHeight()) {offsetRightDownPoint.y = this.getHeight() - rightDownPoint.y;}if ((rightDownPoint.y + offsetRightDownPoint.y) - leftUpPoint.y < FRAME_MIN_HEIGHT) {offsetRightDownPoint.y = FRAME_MIN_HEIGHT + leftUpPoint.y- rightDownPoint.y;}}
奉上源码下载地址:http://download.csdn.net/detail/ihrthk/4509509