1

I got a popup window that is generated with the help of WindowManager and with these params (as you can find in other stackoverflow questions):

new WindowManager.LayoutParams(
  ViewGroup.LayoutParams.WRAP_CONTENT,
  ViewGroup.LayoutParams.WRAP_CONTENT,
  WindowManager.LayoutParams.TYPE_PHONE,
  WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
  PixelFormat.TRANSLUCENT
)

My question is similar to this one: Android: Drag View outside screen and also similar to this one: Dragging a view outside of RelativeLayout

The difference is that the WindowManager.LayoutParams do not include any kind of margins, therefore it is not possible to use the margin tricks with relative layout etc.

Any idea on how I could drag the view outside of the android screen boundaries?

Thank you

Edit:
As you asked here is the related code that does the dragging for the time being

view.setOnTouchListener(new OnTouchListener {
  def onTouch(view: View, motionEvent: MotionEvent): Boolean = {
    val x = motionEvent.getRawX.toInt
    val y = motionEvent.getRawY.toInt

    motionEvent.getAction & MotionEvent.ACTION_MASK match {
      case MotionEvent.ACTION_DOWN =>
        val params = view.getLayoutParams.asInstanceOf[WindowManager.LayoutParams]

        xDelta = x - params.x

        yDelta = y - params.y

      case MotionEvent.ACTION_UP =>
        draggingOn = false

      case MotionEvent.ACTION_MOVE =>
        if (draggingOn) {
          val params = view.getLayoutParams.asInstanceOf[WindowManager.LayoutParams]

          params.x = x - xDelta

          params.y = y - yDelta

          //view.setLayoutParams(params)
          windowManager.updateViewLayout(view, params)

          //log log "current x is: " + x

          //log log "current y is: " + y
        } else {
          //nop
        }

      case _ =>
      //case MotionEvent.ACTION_POINTER_DOWN =>
      //case MotionEvent.ACTION_POINTER_UP =>
    }

    false
  }
})

above code is in scala but I guess you will not have any hard time reading it

Community
  • 1
  • 1
George Pligoropoulos
  • 2,919
  • 3
  • 33
  • 65
  • Any idea on how I could drag the view outside of the android screen boundaries? Does this mean your screen should grow horizontally/vertically as you drag? – Parth Kapoor Jun 20 '14 at 09:44
  • No no, nothing special. I just want to drag the view and while dragging the view should be able to appear half way inside screen and half way outside screen for example. Current behaviour is that the view is bounded and cannot move further than the edges of the screen – George Pligoropoulos Jun 20 '14 at 09:55
  • Are you dragging using onDrag interface? Please post your code – Parth Kapoor Jun 20 '14 at 09:58
  • Sure! here is the new code! – George Pligoropoulos Jun 20 '14 at 10:16
  • Let we have a screen-region marked by (0,0),(100,0),(100,100) & (100,0). Now your code effectively sets the dragged views position to be (50,110) or (-10,90). Theoretically it should work how you intend it to, but android some how overrides your values and makes (50,110) to be (50,100) and (-10,90) to be (0,90) so that screen-region boundaries are maintained. I assume there must be a good enough reason to enforce such restrictions. – Parth Kapoor Jun 20 '14 at 10:24
  • We cannot find any reason good enough for android to have these restrictions in general. Let's say that we want to dismiss the view not by clicking but by a gesture. We need to swipe the view off the screen. How can we achieve this nice effect if we cannot move it like we wish? – George Pligoropoulos Jun 20 '14 at 10:36

3 Answers3

1

Edit : I found an easier solution : Just call :

setClippingEnabled(false);

and the following code works without the margins trick :

window.update(mOffsetX, mOffsetY, -1, -1, true);

Old response :

You cannot set an X position outside of the screen or set a margin on a PopupWindow layout params.

As a workaround, I use :

case MotionEvent.ACTION_DOWN:
    mOrgX = (int) event.getRawX();
    break;

case MotionEvent.ACTION_MOVE:
    mOffsetX = (int) event.getRawX() - mOrgX;
    window.update(mOffsetX, mOffsetY, -1, -1, true);

As I said before you cannot change the PopupWindow margins but you can change the content view margins.

When the offsetX is larger than the starting X position of the popup, I start to change view margins

if (mStartingWindowPosition + mOffsetX <= 0 
         || mWindowWith + mOffsetX > mScreenWidth) {

    int delta = 0;
    if (mOffsetX > 0) {
        delta = window.getContentView().getWidth() + mOffsetX - mScreenWidth;
    }
    else {
        delta = mStartingWindowPosition + mOffsetX;
    }
    params.rightMargin = -delta;
    params.leftMargin = delta;
}

with :

if (mWindowWith == 0) {
    mWindowWith = window.getContentView().getWidth();
    mStartingWindowPosition = mScreenWidth / 2 - mWindowWith / 2;  // my window is X centered
}
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams)    window.getContentView().getLayoutParams();

For me, it did the job

Tested on 4.X and 5.0 devices

Note : This code is not in production right now, so I don't know if there are side effects

Arnaud
  • 531
  • 4
  • 6
0

Let your Dragged view is 20X20 and the entire screen is 100X100. Developing this effect that you wish can be done on following lines:

  1. Detect the state when your dragged view cannot be contained in the screen boundaries Let current Drag position is (50,90), this will mean 10 units of your view should not be visible(vertically). On detecting this, you should set marginY = +10 units.

  2. Similarly if Drag position is (-10,-15), this will mean 10 units of your view should not be visible(Horizonally) and 15 units(vertically). On detecting this, you should set marginY = -15 units and marginX= -10 units.

The thing to keep in mind is that the dimensions must be in same units. Hope this provides some assistance.

Parth Kapoor
  • 1,494
  • 12
  • 23
  • Could you provide some source code in your answer? In which classes does these properties/methods `marginX` and `marginY` belong exactly? I cannot find anything like than inside `WindowManager.LayoutParams` or inside `View`. Thank you – George Pligoropoulos Jun 20 '14 at 14:52
0

Just use the flag FLAG_LAYOUT_NO_LIMITS in your LayoutParams:

new WindowManager.LayoutParams(
    ViewGroup.LayoutParams.WRAP_CONTENT,
    ViewGroup.LayoutParams.WRAP_CONTENT,
    WindowManager.LayoutParams.TYPE_PHONE,
    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
        | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
    PixelFormat.TRANSLUCENT
)
Anton Volodin
  • 51
  • 1
  • 2