Android make view исчезнет, щелкнув за ним
У меня есть некоторые представления, которые я делаю видимыми при нажатии кнопки. Я хочу, чтобы они исчезли, если я нахожусь за пределами этих представлений.
Как это сделать на Android?
Кроме того, я понимаю, что кнопка "назад" также может помочь пользователям Android с этим - я могу использовать это как второстепенный способ закрыть представления, но некоторые из планшетов даже не используют кнопку "физический" назад больше, он был очень де-подчеркнул.
Ответы
Ответ 1
Легкий/глупый способ:
-
Создайте фиктивный пустой вид (скажем, ImageView без источника), заставьте его заполнить родительский
-
Если нажать, сделайте то, что хотите.
Вам нужно, чтобы корневой тег в вашем XML файле был RelativeLayout. Он будет содержать два элемента: ваш фиктивный вид (установите его положение на align the Parent Top
). Другой - это ваш первоначальный вид, содержащий представления и кнопку (это представление может быть LinearLayout или что бы вы ни делали), не забудьте установить его положение на align the Parent Top
)
Надеюсь, это поможет вам, удачи!
Ответ 2
Это старый вопрос, но я думал, что дам ответ, который не основан на событиях onTouch
. Как было предложено RedLeader, это также можно достичь, используя фокус-события. У меня был случай, когда мне нужно было показать и скрыть пучок кнопок, расположенных в пользовательском всплывающем окне, т.е. Все кнопки были помещены в один и тот же ViewGroup
. Некоторые вещи, которые вам нужно сделать, чтобы сделать эту работу:
-
Группа просмотра, которую вы хотите скрыть, должна иметь View.setFocusableInTouchMode(true)
. Это также можно установить в XML с помощью android:focusableintouchmode
.
-
Корень вашего корня, т.е. корень всего вашего макета, возможно, какой-то линейный или относительный макет, также должен быть способен фокусироваться в соответствии с № 1 выше
-
Когда отображается группа просмотра, вы вызываете View.requestFocus()
, чтобы дать ей фокус.
-
Группа просмотра должна либо переопределить View.onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect)
, либо реализовать свой собственный OnFocusChangeListener
и использовать View.setOnFocusChangeListener()
-
Когда пользователь выходит за пределы вашего фокуса просмотра, он переносится либо в корень представления (поскольку вы устанавливаете его как настраиваемый в # 2), либо в другое представление, которое по своей сути является фокусируемым (EditText
или аналогичным)
-
Когда вы обнаруживаете потерю фокуса, используя один из методов в # 4, вы знаете, что фокус перенесен на что-то вне вашей группы просмотра, и вы можете скрыть его.
Я предполагаю, что это решение не работает во всех сценариях, но оно работает в моем конкретном случае, и это звучит так, как будто оно может работать и для OP.
Ответ 3
Найдите прямоугольник представления, а затем определите, находится ли событие click вне представления.
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Rect viewRect = new Rect();
mTooltip.getGlobalVisibleRect(viewRect);
if (!viewRect.contains((int) ev.getRawX(), (int) ev.getRawY())) {
setVisibility(View.GONE);
}
return true;
}
Если вы хотите использовать другое событие касания, попробуйте
return super.dispatchTouchEvent(ev);
Ответ 4
Я искал способ закрыть мой взгляд, когда касался снаружи, и ни один из этих методов не соответствовал моим потребностям очень хорошо. Я нашел решение и просто разместил его здесь, если кто-то заинтересован.
У меня есть базовая активность, в которой почти все мои действия расширяются. В нем я:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (myViewIsVisible()){
closeMyView();
return true;
}
return super.dispatchTouchEvent(ev);
}
Итак, если мой вид виден, он просто закроется, и если нет, он будет вести себя как нормальное событие касания. Не уверен, что это лучший способ сделать это, но, похоже, это работает для меня.
Ответ 5
Мне нужна была особая способность не только удалять представление при нажатии на него, но также позволять клику перейти к обычному действию. Например, у меня есть отдельный layout, notification_bar.xml, который мне нужно динамически раздувать и добавлять к любой текущей активности, когда это необходимо.
Если я создаю оверлейный вид размера экрана для получения любых кликов за пределами вида notification_bar и удаляю оба эти представления одним кликом, родительский вид (основной вид активности) все равно не получил никаких кликов, это означает, что, когда панель notification_bar видима, для нажатия кнопки требуется два щелчка (один для отклонения вида notification_bar и один для нажатия кнопки).
Чтобы решить эту проблему, вы можете просто создать свою собственную DismissViewGroup, которая расширяет ViewGroup и переопределяет следующий метод:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
ViewParent parent = getParent();
if(parent != null && parent instanceof ViewGroup) {
((ViewGroup) parent).removeView(this);
}
return super.onInterceptTouchEvent(ev);
}
И тогда ваш динамически добавленный вид будет немного похож:
<com.example.DismissViewGroup android:id="@+id/touch_interceptor_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent" ...
<LinearLayout android:id="@+id/notification_bar_view" ...
Это позволит вам взаимодействовать с представлением, и в тот момент, когда вы выходите за пределы представления, вы оба отклоняете представление и обычно взаимодействуете с активностью.
Ответ 6
Внедрить onTouchListener()
. Убедитесь, что координаты касания находятся за пределами координат вашего вида.
Вероятно, есть какой-то способ сделать это с помощью onFocus()
и т.д. - Но я этого не знаю.
Ответ 7
Я создал пользовательскую ViewGroup для отображения информационного окна, привязанного к другому представлению (всплывающий шар).
Детский вид - это информационное окно, BalloonView - полноэкранный режим для абсолютного позиционирования ребенка и перехватывания касания.
public BalloonView(View anchor, View child) {
super(anchor.getContext());
//calculate popup position relative to anchor and do stuff
init(...);
//receive child via constructor, or inflate/create default one
this.child = child;
//this.child = inflate(...);
//this.child = new SomeView(anchor.getContext());
addView(child);
//this way I don't need to create intermediate ViewGroup to hold my View
//but it is fullscreen (good for dialogs and absolute positioning)
//if you need relative positioning, see @iturki answer above
((ViewGroup) anchor.getRootView()).addView(this);
}
private void dismiss() {
((ViewGroup) getParent()).removeView(this);
}
Обработать клики внутри дочернего элемента:
child.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//write your code here to handle clicks inside
}
});
Отклонить мой просмотр, щелкнув снаружи БЕЗ делегирования касания к базовому виду:
BalloonView.this.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
Отклонить мой взгляд, щелкнув снаружи С делегированием касания к базовому виду:
@Override
public boolean onTouchEvent(MotionEvent event) {
dismiss();
return false; //allows underlying View to handle touch
}
Отключить нажатие кнопки "Назад":
//do this in constructor to be able to intercept key
setFocusableInTouchMode(true);
requestFocus();
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
dismiss();
return true;
}
return super.onKeyPreIme(keyCode, event);
}
Ответ 8
поблагодарить @ituki за идею
FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/search_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#80000000"
android:clickable="true">
<LinearLayout
android:clickable="true" // not trigger
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="#FFF"
android:orientation="vertical"
android:padding="20dp">
...............
</LinearLayout>
</FrameLayout>
и java-код
mContainer = (View) view.findViewById(R.id.search_container);
mContainer.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
Log.d("aaaaa", "outsite");
return true;
}
return false;
}
});
он работает при касании вне LinearLayout