Android實現(xiàn)控件的縮放移動功能
上篇文章給大家介紹了 Android控件實現(xiàn)圖片縮放功能 ,需要的朋友點擊查看。
1.簡介
話不多說先來張效果圖
控件縮放移動.gif
上面的gif中,依次進(jìn)行了拖動——>觸摸右上角放大,縮小——>觸摸上方與右測邊緣——>雙指放大縮小。
2 使用步驟
2.1 布局。外層一個LinearLayout,里面一個自定義的控件DragScaleView,為了能夠更清楚的看到控件的變化過程,就給控件加了一個灰色帶虛線的邊框bg_dashgap。
layout文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:id="@+id/root" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#80ce3d3a" android:gravity="center_horizontal" android:fitsSystemWindows="true"> <com.xxx.xxx.ui.DragScaleView android:id="@+id/hair_dv" android:src="@drawable/ic_sure" android:background="@drawable/bg_dashgap" android:adjustViewBounds="true" android:layout_marginLeft="50dp" android:layout_marginTop="10dp" android:layout_width="100dp" android:layout_height="120dp" android:clickable="true"/> </LinearLayout>
在drawable文件夾下的bg_dashgap.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" > <!-- 圓角 --> <corners android:bottomLeftRadius="8dp" android:bottomRightRadius="8dp" android:radius="15dp" android:topLeftRadius="8dp" android:topRightRadius="8dp" /> <!-- 描邊 --> <stroke android:dashGap="4dp" android:dashWidth="4dp" android:width="2dp" android:color="@color/my_gery" /> </shape>
2.2 自定義的控件
單指觸摸:
當(dāng)ACTION_DOWN時如果坐標(biāo)為1.2.3.4四個區(qū)域,則對View進(jìn)行相應(yīng)的左上/右上/左下/右下拉伸;
當(dāng)ACTION_DOWN時如果坐標(biāo)為5.6.7.8四個區(qū)域,則分別對上/右/下/左四個方向進(jìn)行拉伸;
當(dāng)ACTION_DOWN時如果坐標(biāo)為9這個區(qū)域,則對View進(jìn)行移動;
雙指觸摸:
先計算出觸摸時雙指的距離,float oriDist=distance(event);
再得到雙指離開屏幕的距離,float newDist =distance(event);
得到兩者之間的比例 float scale = newDist / oriDist;
計算雙指間距離的方法
/**
* 計算兩個手指間的距離
* @param event 觸摸事件
* @return 放回兩個手指之間的距離
*/
private float distance(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);//兩點間距離公式
}
自定義的控件
onTouch(View v, MotionEvent event)的觸摸事件中代碼塊
image.png
其他的關(guān)鍵地方,代碼中都有比較詳細(xì)的注釋了。思路就是
觸摸監(jiān)聽
判斷不同情況---getDirection(v, (int) event.getX(), (int) event.getY())
計算得到新的oriLeft, oriTop, oriRight, oriBottom
重新繪制---v.layout(oriLeft, oriTop, oriRight, oriBottom)
3 DragScaleView 的完整代碼
public class DragScaleView extends android.support.v7.widget.AppCompatImageView implements View.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 TOUCH_TWO = 0x21;
private static final int CENTER = 0x19;
private int offset = 0; //可超出其父控件的偏移量
protected Paint paint = new Paint();
private static final int touchDistance = 80; //觸摸邊界的有效距離
// 初始的兩個手指按下的觸摸點的距離
private float oriDis = 1f;
/**
* 初始化獲取屏幕寬高
*/
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.GRAY);
paint.setStrokeWidth(4.0f);
paint.setStyle(Paint.Style.STROKE);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
setBackgroundResource(R.drawable.bg_dashgap);
int action = event.getAction()& MotionEvent.ACTION_MASK;
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());
}
if (action == MotionEvent.ACTION_POINTER_DOWN){
oriLeft = v.getLeft();
oriRight = v.getRight();
oriTop = v.getTop();
oriBottom = v.getBottom();
lastY = (int) event.getRawY();
lastX = (int) event.getRawX();
dragDirection = TOUCH_TWO;
oriDis = distance(event);
}
// 處理拖動事件
delDrag(v, event, action);
invalidate();
return false;
}
/**
* 處理拖動事件
*
* @param v
* @param event
* @param action
*/
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;
case TOUCH_TWO: //雙指操控
float newDist =distance(event);
float scale = newDist / oriDis;
//控制雙指縮放的敏感度
int distX = (int) (scale*(oriRight-oriLeft)-(oriRight-oriLeft))/50;
int distY = (int) (scale*(oriBottom-oriTop)-(oriBottom-oriTop))/50;
if (newDist>10f){//當(dāng)雙指的距離大于10時,開始相應(yīng)處理
left(v, -distX);
top(v, -distY);
right(v, distX);
bottom(v, distY);
}
break;
}
if (dragDirection != CENTER) {
v.layout(oriLeft, oriTop, oriRight, oriBottom);
}
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
dragDirection = 0;
break;
}
}
/**
* 觸摸點為中心->>移動
*
* @param v
* @param dx
* @param dy
*/
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();
}
Log.d("raydrag", left+" "+top+" "+right+" "+bottom+" "+dx);
v.layout(left, top, right, bottom);
}
/**
* 觸摸點為上邊緣
*
* @param v
* @param dy
*/
private void top(View v, int dy) {
oriTop += dy;
if (oriTop < -offset) {
//對view邊界的處理,如果子view達(dá)到父控件的邊界,offset代表允許超出父控件多少
oriTop = -offset;
}
if (oriBottom - oriTop - 2 * offset < 200) {
oriTop = oriBottom - 2 * offset - 200;
}
}
/**
* 觸摸點為下邊緣
*
* @param v
* @param dy
*/
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;
}
}
/**
* 觸摸點為右邊緣
*
* @param v
* @param dx
*/
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;
}
}
/**
* 觸摸點為左邊緣
*
* @param v
* @param dx
*/
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;
}
}
/**
* 獲取觸摸點flag
*
* @param v
* @param x
* @param y
* @return
*/
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 < touchDistance && y < touchDistance) {
return LEFT_TOP;
}
if (y < touchDistance && right - left - x < touchDistance) {
return RIGHT_TOP;
}
if (x < touchDistance && bottom - top - y < touchDistance) {
return LEFT_BOTTOM;
}
if (right - left - x < touchDistance && bottom - top - y < touchDistance) {
return RIGHT_BOTTOM;
}
if (x < touchDistance) {
return LEFT;
}
if (y < touchDistance) {
return TOP;
}
if (right - left - x < touchDistance) {
return RIGHT;
}
if (bottom - top - y < touchDistance) {
return BOTTOM;
}
return CENTER;
}
/**
* 計算兩個手指間的距離
*
* @param event 觸摸事件
* @return 放回兩個手指之間的距離
*/
private float distance(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);//兩點間距離公式
}
}
總結(jié)
以上所述是小編給大家介紹的Android控件的縮放移動功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
Android百度地圖定位后獲取周邊位置的實現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了Android百度地圖定位后獲取周邊位置的實現(xiàn)代碼,準(zhǔn)確獲取周邊地理位置,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-01-01
Android之Intent附加數(shù)據(jù)的兩種實現(xiàn)方法
這篇文章主要介紹了Android之Intent附加數(shù)據(jù)的兩種實現(xiàn)方法,以實例形式較為詳細(xì)的分析了添加數(shù)據(jù)到Intent的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-09-09
Android 中使用ContentObserver模式獲取短信用正則自動填充驗證碼
這篇文章主要介紹了Android 中使用ContentObserver模式獲取短信用正則自動填充驗證碼,首先使用了ContentObserver監(jiān)聽短信,然后從短信中用正則的分組去拿到驗證碼,具體實現(xiàn)代碼大家參考下本文2017-02-02
Android設(shè)置桌面背景圖片的實現(xiàn)方法
有時候我們需要用android設(shè)置桌面背景圖片,這里簡單分享下,方便需要的朋友2013-06-06

