Я раздуваю макет, чтобы показать его на экране. Теперь я хочу частично переместить этот макет за пределы экрана. Я попробовал это, используя .animate().translationX(-500)
на надутом макете. Он сдвинулся с экрана именно так, как я хотел:
До:
После:
Но теперь у меня проблема в том, что область, которую изначально занимал макет, недоступна для кликов (например, нельзя прокручивать между домашними экранами, работает только за пределами области, отмеченной синим цветом).
Как я могу решить эту проблему, чтобы синяя область была кликабельной после перемещения, но оставшаяся область макета (красная область) все еще могла регистрировать клики (например, если я хотел переместить ее обратно с помощью onClickListener)? Я думаю, что мне нужно работать с функцией updateViewLayout()
функции windowManager
, но я не знаю, что я должен изменить в параметрах.
Редактировать 1:
Вот код. Перевод запускается кнопкой:
overlay.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#d8ff0000"
android:weightSum="1">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="245dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Lorem ipsum "
android:id="@+id/textView6"
android:layout_marginLeft="10dp" />
<Button
android:layout_width="55dp"
android:layout_height="wrap_content"
android:text="X"
android:id="@+id/button"
android:layout_gravity="center_horizontal|top"
android:layout_alignParentTop="true"
android:layout_toEndOf="@+id/textView6"
android:layout_marginStart="27dp" />
</RelativeLayout>
</LinearLayout>
Сервис, который раздувает макет:
OverlayService.java
public class FloatingMenu extends Service{
private WindowManager wm;
private LinearLayout ll;
private boolean isPushedToSide = true;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
wm = (WindowManager) getSystemService(WINDOW_SERVICE);
ll = new LinearLayout(this);
LinearLayout.LayoutParams llParameters = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
ll.setBackgroundColor(Color.argb(50, 255, 255, 255));
ll.setLayoutParams(llParameters);
final WindowManager.LayoutParams parameters = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_PHONE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);
parameters.gravity = Gravity.LEFT | Gravity.TOP;
LayoutInflater li = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
ll = (LinearLayout) li.inflate(R.layout.overlay, null);
final Button b = (Button) ll.findViewById(R.id.button);
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (isPushedToSide) {
ll.animate().translationX(0);
isPushedToSide = false;
}else {
ll.animate().translationX(-450);
isPushedToSide = true;
}
}
});
wm.addView(ll, parameters);
}
}
Редактировать 2:
Продолжая свои исследования, я обнаружил, что .animate().translationX()
перемещает только позицию, в которой отображается представление, а не само представление. Это также объясняет, почему после использования .animate().translationX()
событие onclick по-прежнему запускается в той же позиции, что и до «перемещения» макета.
Теперь мне нужно найти способ переместить реальный вид в желаемую позицию в сочетании с анимацией. Любые идеи, как это сделать?
Изменить 3: я нашел много сообщений с похожими проблемами, и если я прав, решение проблемы заключается в использовании ObjectAnimator
вместо .animate().translationX()
. Я попытался заменить эту часть в своем коде, чтобы onClickListener
теперь выглядело так:
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (isPushedToSide) {
//ll.animate().translationX(0);
ObjectAnimator.ofFloat(ll, "translationX", 0).setDuration(250).start();
isPushedToSide = false;
}else {
//ll.animate().translationX(-450);
ObjectAnimator.ofFloat(ll, "translationX", -450).setDuration(250).start();
isPushedToSide = true;
}
}
});
ll
— это растянутый мной LinearLayout, содержащий текст Lorem ipsum
и Button
. Опять же, сама анимация работает нормально, но ведет себя все так же. Мне все еще нужно щелкнуть исходное положение кнопки, чтобы запустить onClickListener
, а синяя область по-прежнему не активна.
Редактировать 4:
Испытывал предложение использовать.invalidate()
для обновления фактической позиции. Однако это не сработало. Хотя я не уверен, что использовал его правильно.
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (isPushedToSide) {
//ll.animate().translationX(0);
ObjectAnimator.ofFloat(ll, "translationX", 0).setDuration(250).start();
ll.invalidate();
isPushedToSide = false;
}else {
//ll.animate().translationX(-450);
ObjectAnimator.ofFloat(ll, "translationX", -450).setDuration(250).start();
ll.invalidate();
isPushedToSide = true;
}
}
});
Я также попытался изменить значение x для LayoutParams
и вызвать wm.updateViewLayou(ll, updatedParameters)
, что сработало нормально. Когда я переместил оверлей на 100 пикселей вправо, область, вызывающая onClickListener
, также сдвинулась на 100 пикселей вправо. Проблема в том, что я смог переместить наложение только в пределах реального экрана, и мне нужно переместить его за пределы экрана. Связал отрицательные значения, но это тоже не сработало.
По сути, мне нужна навигация по ящикам, но с ограниченной высотой (по крайней мере, я думаю, что мне это нужно). Посмотрим, смогу ли я заставить что-то работать должным образом.
Редактировать 5:
Исправил мой код так, что .inflate()
вызывается после завершения анимации, но все равно ведет себя так же:
ObjectAnimator anim = ObjectAnimator.ofFloat(ll, "translationX", 0).setDuration(250);
anim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {}
@Override
public void onAnimationEnd(Animator animator) {
b.invalidate();
text.invalidate();
frame.invalidate();
ll.invalidate();
}
@Override
public void onAnimationCancel(Animator animator) {}
@Override
public void onAnimationRepeat(Animator animator) {}
});
anim.start();
Я также записал два .gif, показывающих проблему. Я установил gravity
на CENTER
на втором.