首先說一下定義這樣一個View有什麼用?在一些app中,需要設定頭像,而使用者選擇的圖檔可能是使用攝像頭拍攝,也可能是選擇的相冊裡面的圖檔,總之,這樣的圖檔大小不一,就比如在使用某個聊天軟體的時候,設定頭像,需要對圖檔進行截取.
要實作這樣一個功能,首先,需要分析使用者的操作,即使用者所點選的View的位置,如下圖,我把View分為9個區域,
- 當ACTION_DOWN時如果坐标為1.2.3.4四個區域,則對View進行相應的左上/右上/左下/右下拉伸;
- 當ACTION_DOWN時如果坐标為5.6.7.8四個區域,則分别對上/右/下/左四個方向進行拉伸;
- 當ACTION_DOWN時如果坐标為9這個區域,則對View進行移動;
理論分析完成,下面來看具體實作;
在下面的類中,有五個方法center/left/top/bottom/right分别對應移動/向左拉伸/向上拉伸/向下拉伸/向右拉伸,當Action_down為1-4所在的區域時,組合前面的對應的兩個拉伸方法即可,如左上角拉伸則對應執行left+top方法,這也是把四個單獨一條邊的邊緣拉伸獨立出來的原因;
在View中,我設定了View的最小寬度和高度,都是200,是以當使用者點選邊緣進行縮小操作時,能縮小的最小值也就是200;分别在left/top/bottom/right中展現;
public class DragScaleView extends View implements OnTouchListener {
protected int screenWidth;
protected int screenHeight;
protected int lastX;
protected int lastY;
private int oriLeft;
private int oriRight;
private int oriTop;
private int oriBottom;
private int dragDirection;
private static final int TOP = 0x15;
private static final int LEFT = 0x16;
private static final int BOTTOM = 0x17;
private static final int RIGHT = 0x18;
private static final int LEFT_TOP = 0x11;
private static final int RIGHT_TOP = 0x12;
private static final int LEFT_BOTTOM = 0x13;
private static final int RIGHT_BOTTOM = 0x14;
private static final int CENTER = 0x19;
private int offset = 20;
protected Paint paint = new Paint();
protected void initScreenW_H() {
screenHeight = getResources().getDisplayMetrics().heightPixels - 40;
screenWidth = getResources().getDisplayMetrics().widthPixels;
}
public DragScaleView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setOnTouchListener(this);
initScreenW_H();
}
public DragScaleView(Context context, AttributeSet attrs) {
super(context, attrs);
setOnTouchListener(this);
initScreenW_H();
}
public DragScaleView(Context context) {
super(context);
setOnTouchListener(this);
initScreenW_H();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(Color.RED);
paint.setStrokeWidth(4.0f);
paint.setStyle(Style.STROKE);
canvas.drawRect(offset, offset, getWidth() - offset, getHeight()
- offset, paint);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
oriLeft = v.getLeft();
oriRight = v.getRight();
oriTop = v.getTop();
oriBottom = v.getBottom();
lastY = (int) event.getRawY();
lastX = (int) event.getRawX();
dragDirection = getDirection(v, (int) event.getX(),
(int) event.getY());
}
// 處理拖動事件
delDrag(v, event, action);
invalidate();
return false;
}
protected void delDrag(View v, MotionEvent event, int action) {
switch (action) {
case MotionEvent.ACTION_MOVE:
int dx = (int) event.getRawX() - lastX;
int dy = (int) event.getRawY() - lastY;
switch (dragDirection) {
case LEFT: // 左邊緣
left(v, dx);
break;
case RIGHT: // 右邊緣
right(v, dx);
break;
case BOTTOM: // 下邊緣
bottom(v, dy);
break;
case TOP: // 上邊緣
top(v, dy);
break;
case CENTER: // 點選中心–>>移動
center(v, dx, dy);
break;
case LEFT_BOTTOM: // 左下
left(v, dx);
bottom(v, dy);
break;
case LEFT_TOP: // 左上
left(v, dx);
top(v, dy);
break;
case RIGHT_BOTTOM: // 右下
right(v, dx);
bottom(v, dy);
break;
case RIGHT_TOP: // 右上
right(v, dx);
top(v, dy);
break;
}
if (dragDirection != CENTER) {
v.layout(oriLeft, oriTop, oriRight, oriBottom);
}
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
break;
case MotionEvent.ACTION_UP:
dragDirection = 0;
break;
}
}
private void center(View v, int dx, int dy) {
int left = v.getLeft() + dx;
int top = v.getTop() + dy;
int right = v.getRight() + dx;
int bottom = v.getBottom() + dy;
if (left < -offset) {
left = -offset;
right = left + v.getWidth();
}
if (right > screenWidth + offset) {
right = screenWidth + offset;
left = right - v.getWidth();
}
if (top < -offset) {
top = -offset;
bottom = top + v.getHeight();
}
if (bottom > screenHeight + offset) {
bottom = screenHeight + offset;
top = bottom - v.getHeight();
}
v.layout(left, top, right, bottom);
}
private void top(View v, int dy) {
oriTop += dy;
if (oriTop < -offset) {
oriTop = -offset;
}
if (oriBottom - oriTop - 2 * offset < 200) {
oriTop = oriBottom - 2 * offset - 200;
}
}
private void bottom(View v, int dy) {
oriBottom += dy;
if (oriBottom > screenHeight + offset) {
oriBottom = screenHeight + offset;
}
if (oriBottom - oriTop - 2 * offset < 200) {
oriBottom = 200 + oriTop + 2 * offset;
}
}
private void right(View v, int dx) {
oriRight += dx;
if (oriRight > screenWidth + offset) {
oriRight = screenWidth + offset;
}
if (oriRight - oriLeft - 2 * offset < 200) {
oriRight = oriLeft + 2 * offset + 200;
}
}
private void left(View v, int dx) {
oriLeft += dx;
if (oriLeft < -offset) {
oriLeft = -offset;
}
if (oriRight - oriLeft - 2 * offset < 200) {
oriLeft = oriRight - 2 * offset - 200;
}
}
protected int getDirection(View v, int x, int y) {
int left = v.getLeft();
int right = v.getRight();
int bottom = v.getBottom();
int top = v.getTop();
if (x < 40 && y < 40) {
return LEFT_TOP;
}
if (y < 40 && right - left - x < 40) {
return RIGHT_TOP;
}
if (x < 40 && bottom - top - y < 40) {
return LEFT_BOTTOM;
}
if (right - left - x < 40 && bottom - top - y < 40) {
return RIGHT_BOTTOM;
}
if (x < 40) {
return LEFT;
}
if (y < 40) {
return TOP;
}
if (right - left - x < 40) {
return RIGHT;
}
if (bottom - top - y < 40) {
return BOTTOM;
}
return CENTER;
}
public int getCutWidth() {
return getWidth() - 2 * offset;
}
public int getCutHeight() {
return getHeight() - 2 * offset;
}
}
二.使用View,如果想要對View進行移動,需要在xml中配置android:clickable=”true”屬性;
android:id=”@+id/ds”
android:layout_width=”180dip”
android:layout_height=”180dip”
android:clickable=”true” />