之前就有寫過這種小Demo,那裏是使用setLayoutParams給控件設置新座標的方式完成的,有興趣讀者可以參考博客:Android簡易實戰教程--第四十九話《滿屏拖動的控件》
本篇小Demo,使用另一種實現方式同樣完成類似的功能。
在開始之前,你需要複習一下有關座標的知識:
int getLeft()
得到當前視圖左頂點相對父視圖的X軸座標
int getTop()
得到當前視圖左頂點相對父視圖的Y軸座標
int getRight()
得到當前視圖右下角點相對父視圖的X軸座標
int getBottom()
得到當前視圖右下角點相對父視圖的Y軸座標
layout(int left, int top, int right, int bottom) :
動態指定當前視圖在父視圖中的定位, 參數爲相對父視圖的座標
ViewParent getParent() :
得到當前View的父視圖對象
getX(): 得到控件相對自己座標X值
getY(): 得到控件相對自己座標Y值
getRawX(): 得到控件相對父容器座標X值
getRawY(): 得到控件相對父容器座標Y值
這個東西很簡單,直接上Demo代碼:
寫的很詳細,相信沒有什麼問題。咱們再看看代碼:
public class MainActivity extends AppCompatActivity
implements View.OnTouchListener {
private ImageView mImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.iv_main);
mImageView.setOnTouchListener(this);
}
int lastX;//用於保存上一次事件的座標。
int lastY;
//v----ImageView對象
@Override
public boolean onTouch(View v, MotionEvent event) {
//任何事件都會觸發這裏。包括按下、移動
int eventX = (int) event.getRawX();
int eventY = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//按下執行這裏,按下移動,這裏只執行一次。獲取剛剛按下位置座標
lastX = eventX;
lastY = eventY;
break;
case MotionEvent.ACTION_MOVE:
//先獲取偏移距離:此時的eventX與上邊的eventX不是一個值
int dx = eventX - lastX;
int dy = eventY - lastY;
//計算控件最新座標
int left = mImageView.getLeft() + dx;
int top = mImageView.getTop() + dy;
int right = mImageView.getRight() + dx;
int bottom = mImageView.getBottom() + dy;
//重新設置控件在父組件中的位置。參數是當前控件的四個座標值
mImageView.layout(left, top, right, bottom);
//最後重新給lastX,lastY賦值。記錄最後一次的值
lastX = eventX;
lastY = eventY;
break;
default:
break;
}
//表示我(圖片控件),消費事件
return true;
}
}
運行程序結果如下:
上面圖片完成了基本拖動功能,但是還是存在問題的。我們不希望它拖出屏幕,那麼邏輯就需要做如下修改:
拖動到屏幕左右上下位置時候,控制不越界。
public class MainActivity extends AppCompatActivity implements View.OnTouchListener {
private ImageView mImageView;
private RelativeLayout mParentView;
private int mParentRight;
private int mParentBottom;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.iv_main);
//獲取控件父親組件的實例
mParentView = (RelativeLayout) mImageView.getParent();
mImageView.setOnTouchListener(this);
}
//兩個變量,用於存儲上一次事件的座標
int lastX;
int lastY;
//v----ImageView對象
@Override
public boolean onTouch(View v, MotionEvent event) {
//任何事件都會觸發這裏。包括按下、移動
int eventX = (int) event.getRawX();
int eventY = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(mParentBottom == 0){
//在onCreate方法中獲取到的座標值是0,0。這是由於繪圖生命週期的原因。onDraw等方法
mParentRight = mParentView.getRight();
mParentBottom = mParentView.getBottom();
}
//按下執行這裏,按下移動,這裏只執行一次。獲取剛剛按下位置座標
lastX = eventX;
lastY = eventY;
case MotionEvent.ACTION_MOVE:
//先獲取偏移距離:此時的eventX與上邊的eventX不是一個值
int dx = eventX - lastX;
int dy = eventY - lastY;
//計算控件最新座標
int left = mImageView.getLeft() + dx;
int top = mImageView.getTop() + dy;
int right = mImageView.getRight() + dx;
int bottom = mImageView.getBottom() + dy;
//限制座標
if (left < 0) {
//控件右邊座標也要設置,否則會讓圖片越變越小
right += -left;
left = 0;
}
if(top<0){
//控件底部座標也要設置,否則會讓圖片越變越小
bottom += -top;
top = 0;
}
if(bottom > mParentBottom){
top -= (bottom - mParentBottom);
bottom = mParentBottom;
}
if(right > mParentRight){
left -= (right - mParentRight);
right = mParentRight;
}
//重新設置控件在父組件中的位置。參數是當前控件的四個座標值
mImageView.layout(left, top, right, bottom);
//最後重新給lastX,lastY賦值。記錄最後一次的值
lastX = eventX;
lastY = eventY;
break;
default:
break;
}
//表示我(圖片控件),消費事件。所有的MotionEvent交給我自己處理
return true;
}
}
通過mParentView = (RelativeLayout) mImageView.getParent();得到父組件控件的實例。在MotionEvent.ACTION_DOWN:按下的時候,拿到服務組件的座標;注意在onCreate方法中獲取到的座標值是[0,0],這是由於繪圖機制以及生命週期有關,還沒有在屏幕上繪製完畢的原因。但是當我們進行事件點擊的時候,肯定全部繪製完畢了。通過如下代碼,控制不超出屏幕:
//限制座標
if (left < 0) {
//控件右邊座標也要設置,否則會讓圖片越變越小
right += -left;
left = 0;
}
if(top<0){
//控件底部座標也要設置,否則會讓圖片越變越小
bottom += -top;
top = 0;
}
if(bottom > mParentBottom){
top -= (bottom - mParentBottom);
bottom = mParentBottom;
}
if(right > mParentRight){
left -= (right - mParentRight);
right = mParentRight;
}
現在再一次運行程序:
我們發現,這時候拖動的控件是不會超出屏幕的。
喜歡我的朋友可以關注我博客,有問題大家一起交流。也可以動手微信掃描下方二維碼查看更多安卓文章:
打開微信搜索公衆號 Android程序員開發指南 或者手機掃描下方二維碼 在公衆號閱讀更多Android文章。
微信公衆號圖片: