Как я могу перетащить всплывающее окно за пределы экрана в Android?

У меня появилось всплывающее окно, созданное с помощью WindowManager и с этими параметрами (как вы можете найти в других вопросах stackoverflow):

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

Мой вопрос похож на этот: Android: перетаскивание внешнего экрана, а также похоже на вот этот: Перетаскивание представления за пределы RelativeLayout

Разница в том, что WindowManager.LayoutParams не включает никаких полей, поэтому невозможно использовать трюки с полями с относительным расположением и т. д.

Любая идея о том, как я могу перетащить представление за пределы экрана Android?

Спасибо

Изменить:
Как вы и просили, вот связанный код, который на данный момент выполняет перетаскивание.

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
  }
})

приведенный выше код написан на scala, но я думаю, вам не составит труда его прочитать


person George Pligoropoulos    schedule 20.06.2014    source источник
comment
Любая идея о том, как я могу перетащить представление за пределы экрана Android? Означает ли это, что ваш экран должен увеличиваться по горизонтали/вертикали при перетаскивании?   -  person Parth Kapoor    schedule 20.06.2014
comment
Нет-нет, ничего особенного. Я просто хочу перетащить вид, и при перетаскивании вид должен иметь возможность отображаться наполовину внутри экрана и наполовину вне экрана, например. Текущее поведение заключается в том, что представление ограничено и не может двигаться дальше краев экрана.   -  person George Pligoropoulos    schedule 20.06.2014
comment
Вы перетаскиваете с помощью интерфейса onDrag? Пожалуйста, опубликуйте свой код   -  person Parth Kapoor    schedule 20.06.2014
comment
Конечно! вот новый код!   -  person George Pligoropoulos    schedule 20.06.2014
comment
Пусть у нас есть область экрана, отмеченная (0,0), (100,0), (100,100) и (100,0). Теперь ваш код фактически устанавливает положение перетаскиваемых представлений равным (50,110) или (-10,90). Теоретически это должно работать так, как вы предполагали, но Android каким-то образом переопределяет ваши значения и делает (50,110) равным (50,100) и (-10,90) равным (0,90), чтобы границы области экрана сохранялись. Я предполагаю, что должна быть достаточно веская причина для введения таких ограничений.   -  person Parth Kapoor    schedule 20.06.2014
comment
Мы не можем найти достаточно веских причин для того, чтобы Android имел эти ограничения в целом. Допустим, мы хотим закрыть вид не щелчком, а жестом. Нам нужно смахнуть изображение с экрана. Как мы можем добиться этого прекрасного эффекта, если мы не можем двигать его так, как нам хочется?   -  person George Pligoropoulos    schedule 20.06.2014


Ответы (3)


Пусть ваш перетаскиваемый вид 20X20, а весь экран 100X100. Разработка этого эффекта, который вы хотите, может быть выполнена в следующих строках:

  1. Определите состояние, когда ваш перетаскиваемый вид не может содержаться в границах экрана. Пусть текущая позиция перетаскивания равна (50,90), это будет означать, что 10 единиц вашего вида не должны быть видны (по вертикали). Обнаружив это, вы должны установить marginY = +10 единиц.

  2. Точно так же, если положение перетаскивания равно (-10,-15), это будет означать, что 10 единиц вашего вида не должны быть видны (по горизонтали) и 15 единиц (по вертикали). Обнаружив это, вы должны установить marginY = -15 единиц и marginX = -10 единиц.

Следует помнить, что размеры должны быть в одних и тех же единицах. Надеюсь, это поможет.

person Parth Kapoor    schedule 20.06.2014
comment
Не могли бы вы предоставить исходный код в своем ответе? К каким именно классам относятся эти свойства/методы marginX и marginY? Я не могу найти ничего подобного, чем внутри WindowManager.LayoutParams или внутри View. Спасибо - person George Pligoropoulos; 20.06.2014

Изменить: я нашел более простое решение: просто позвоните:

setClippingEnabled(false);

и следующий код работает без трюка с полями:

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

Старый ответ:

Вы не можете установить положение X за пределами экрана или установить поле в параметрах макета PopupWindow.

В качестве обходного пути я использую:

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);

Как я уже говорил, вы не можете изменить поля PopupWindow, но вы можете изменить поля представления содержимого.

Когда offsetX больше, чем начальная позиция X всплывающего окна, я начинаю изменять поля просмотра.

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;
}

с участием :

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();

Для меня это сделало работу

Протестировано на устройствах 4.X и 5.0

Примечание. Этот код сейчас не работает, поэтому я не знаю, есть ли побочные эффекты

person Arnaud    schedule 17.12.2014

Просто используйте флаг FLAG_LAYOUT_NO_LIMITS в ваших 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
)
person Anton Volodin    schedule 20.05.2020