拖动Imageview时会移出屏幕

时间:2016-04-04 12:29:48

标签: android drag ontouchlistener

我想在拖动时实现可移动的imageView。拖动工作完全没问题。但是当我拖到最后,imageView会离开屏幕。 如何才能在屏幕内移动图像视图?

这是我的OnTouch listerner:

public boolean onTouch(View view, MotionEvent event) {
    switch (event.getActionMasked()) {
      case MotionEvent.ACTION_DOWN:
        dX = view.getX() - event.getRawX();
        dY = view.getY() - event.getRawY();
        lastAction = MotionEvent.ACTION_DOWN;
        break;

      case MotionEvent.ACTION_MOVE:
        view.setY(event.getRawY() + dY);
        view.setX(event.getRawX() + dX);
        lastAction = MotionEvent.ACTION_MOVE;
        break;

      case MotionEvent.ACTION_UP:
        if (lastAction == MotionEvent.ACTION_DOWN)
          Toast.makeText(DraggableView.this, "Clicked!", Toast.LENGTH_SHORT).show();
        break;

      default:
        return false;
    }
    return true;
  }

这是我的布局。布局包含一个scrollview及其子项,以及我想要拖动的imageview。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clickable="true" >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical" >

            <TextView
                android:layout_width="match_parent"
                android:layout_height="400dp"
                android:background="#ff0000"
                android:gravity="center"
                android:text="View 1"
                android:textColor="#000"
                android:textSize="100dp" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="400dp"
                android:background="#00ff00"
                android:text="View 2"
                android:textColor="#000"
                android:textSize="100dp" />  
        </LinearLayout>
    </ScrollView>

    <ImageView
        android:id="@+id/draggable_view"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_gravity="bottom|right"
        android:layout_marginBottom="20dp"
        android:layout_marginEnd="20dp"
        android:background="@drawable/icon" />

</FrameLayout>

2 个答案:

答案 0 :(得分:3)

花了更多时间,最后找到最佳解决方案。

将我的OnTouch listerner部分修改为:

 DisplayMetrics displaymetrics = new DisplayMetrics();
 getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
 screenHight = displaymetrics.heightPixels;
 screenWidth = displaymetrics.widthPixels;

  @SuppressLint("NewApi") @Override
  public boolean onTouch(View view, MotionEvent event) {


       float newX, newY;

    switch (event.getActionMasked()) {
      case MotionEvent.ACTION_DOWN:

        dX = view.getX() - event.getRawX();
        dY = view.getY() - event.getRawY();
        lastAction = MotionEvent.ACTION_DOWN;
        break;

      case MotionEvent.ACTION_MOVE:

          newX = event.getRawX() + dX;
          newY = event.getRawY() + dY;

      // check if the view out of screen
          if ((newX <= 0 || newX >= screenWidth-view.getWidth()) || (newY <= 0 || newY >= screenHight-view.getHeight()))
          {
              lastAction = MotionEvent.ACTION_MOVE;
              break;      
          }

        view.setX(newX);
        view.setY(newY);

        lastAction = MotionEvent.ACTION_MOVE;

        break;

      case MotionEvent.ACTION_UP:
        if (lastAction == MotionEvent.ACTION_DOWN)
          Toast.makeText(DraggableView.this, "Clicked!", Toast.LENGTH_SHORT).show();
        break;

      default:
        return false;
    }
    return true;
  }

它完美地工作:)

答案 1 :(得分:1)

经过大量研究,我找到了最好的稳健解决方案。以下代码非常适合我将 ImageView 或任何视图保持在屏幕边界内。 使用ACTION_MOVE

中的代码
val pointerIndex = event.findPointerIndex(activePointerId)
if (pointerIndex == -1) return false

val (x, y) = event.getX(pointerIndex) to event.getY(pointerIndex)

posX += x - lastTouchX
posY += y - lastTouchY

// The BOUNDS_PADDING can be any value you like (Ex: 50)
val leftBound = -screenWidth + BOUNDS_PADDING
val rightBound = screenWidth - BOUNDS_PADDING
val downBound = -screenHeight + BOUNDS_PADDING
val upBound = screenHeight - BOUNDS_PADDING

if (posX <= leftBound) {
    // Left Bound Reached while Dragging. So reset view position to be within bounds
    posX = leftBound.toFloat()
}

if (posX >= rightBound) {
   // Right Bound Reached while Dragging. So reset view position to be within bounds
   posX = rightBound.toFloat()
}

if (posY <= downBound) {
   // Bottom Bound Reached while Dragging. So reset view position to be within bounds
   posY = downBound.toFloat()
}

if (posY >= upBound) {
   // Top Bound Reached while Dragging. So reset view position to be within bounds
   posY = upBound.toFloat()
}

binding.imageView.x = posX
binding.imageView.y = posY

lastTouchX = x
lastTouchY = y

您可以使用以下方法获取屏幕宽度和高度

// Get Device Display Height and Width
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    val wm = windowManager.currentWindowMetrics
    val insets = wm.windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.systemBars())
    screenWidth = wm.bounds.width() - insets.left - insets.right
    screenHeight = wm.bounds.height() - insets.bottom - insets.top
} else {
    val dm = DisplayMetrics()
    windowManager.defaultDisplay.getMetrics(dm)
    screenWidth = dm.widthPixels
    screenHeight = dm.heightPixels
}