我們可以監聽,按下到拖動的XY,來通過layout方法改變View的位置
我們也可以寫一個接口,動態的改變view的位置,比如加入重力傳感器。
package com.example.lianxi.ui;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ImageView;
/**
*隨意拖動的view
*/
@SuppressLint("AppCompatCustomView")
public class ThumbImageView extends ImageView {
private int width; // 測量寬度 FreeView的寬度
private int height; // 測量高度 FreeView的高度
private int maxWidth; // 最大寬度 window 的寬度
private int maxHeight; // 最大高度 window 的高度
private Context context;
private float downX; //點擊時的x座標
private float downY; // 點擊時的y座標
//是否拖動標識
private boolean isDrag = false;
// 處理點擊事件和滑動時間衝突時使用 返回是否拖動標識
public boolean isDrag() {
return isDrag;
}
// 初始化屬性
public ThumbImageView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 獲取屏寬高 和 可是適用範圍 (我的需求是可在屏幕內拖動 不超出範圍 也不需要隱藏)
width = getMeasuredWidth();
height = getMeasuredHeight();
maxWidth = 1440; // 如果是父控件裏的話這裏需要專門提供獲取寬度的方法
maxHeight = width;// 如果活動的高度設置爲和本孔家的高度一樣的話那麼就只能橫向滑動
}
// 獲取狀態欄高度
public int getStatusBarHeight() {
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
return getResources().getDimensionPixelSize(resourceId);
}
// 獲取導航欄高度
public int getNavigationBarHeight() {
int rid = getResources().getIdentifier("config_showNavigationBar", "bool", "android");
if (rid != 0) {
int resourceId = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
return context.getResources().getDimensionPixelSize(resourceId);
} else
return 0;
}
/**
* 處理事件分發
*
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
if (this.isEnabled()) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: // 點擊動作處理 每次點擊時將拖動狀態改爲 false 並且記錄下點擊時的座標 downX downY
isDrag = false;
downX = event.getX(); // 點擊觸屏時的x座標 用於離開屏幕時的x座標作計算
downY = event.getY(); // 點擊觸屏時的y座標 用於離開屏幕時的y座標作計算
break;
case MotionEvent.ACTION_MOVE: // 滑動動作處理 記錄離開屏幕時的 moveX moveY 用於計算距離 和 判斷滑動事件和點擊事件 並作出響應
final float moveX = event.getX() - downX;
final float moveY = event.getY() - downY;
int l, r, t, b; // 上下左右四點移動後的偏移量
//計算偏移量 設置偏移量 = 3 時 爲判斷點擊事件和滑動事件的峯值
if (Math.abs(moveX) > 3 || Math.abs(moveY) > 3) { // 偏移量的絕對值大於 3 爲 滑動時間 並根據偏移量計算四點移動後的位置
l = (int) (getLeft() + moveX);
r = l + width;
t = (int) (getTop() + moveY);
b = t + height;
//不劃出邊界判斷,最大值爲邊界值
// 如果你的需求是可以劃出邊界 此時你要計算可以劃出邊界的偏移量 最大不能超過自身寬度或者是高度 如果超過自身的寬度和高度 view 劃出邊界後 就無法再拖動到界面內了 注意
if (l < 0) { // left 小於 0 就是滑出邊界 賦值爲 0 ; right 右邊的座標就是自身寬度 如果可以劃出邊界 left right top bottom 最小值的絕對值 不能大於自身的寬高
l = 0;
r = l + width;
} else if (r > maxWidth) { // 判斷 right 並賦值
r = maxWidth;
l = r - width;
}
if (t < 0) { // top
t = 0;
b = t + height;
} else if (b > maxHeight) { // bottom
b = maxHeight;
t = b - height;
}
this.layout(l, t, r, b); // 重置view在layout 中位置
isDrag = true; // 重置 拖動爲 true
} else {
isDrag = false; // 小於峯值3時 爲點擊事件
}
break;
case MotionEvent.ACTION_UP: // 不處理
setPressed(false);
break;
case MotionEvent.ACTION_CANCEL: // 不處理
setPressed(false);
break;
}
return true;
}
return false;
}
}