насчет сохранения «выбранного» вида как глобальные переменные, и удалить его, когда его фокус меняется? Играя с focusable
, focusableInTouchMode
и onClick
слушателей, вы сможете выбрать нужный результат. Я не уверен, что это лучшее решение, но оно работает.
Что вам понадобится:
- глобальная переменная Посмотреть: ребенок
GridLayout
«s долго щелкнул, как выбрано.
- (опционально)Пользовательский родительский контейнер как любой
ViewGroup
: он установит фокусируемые слушателей на всех своих детей [*]. В моих тестах я использовал LinearLayout
и RelativeLayout
.
[*] Если вы не используете дополнительный родительский пользовательский класс, вы должны установить android:focusable="true"
и android:focusableInTouchMode="true"
на всех детей материнской ViewGroup. И вам нужно будет установить OnClickListener
, чтобы позвонить removeViewSelected()
при щелчке по родительской группе ViewGroup.
- Добавление Нажмите слушателей для
GridLayout
детей: обновляющий выбранный вид.
- Реализация Фокус-слушатель: удаляет выбранный вид, если он теряет фокус.
Он будет обрабатывать все состояния изменения фокуса на родителя и иерархии ребенка, увидеть выход:
я использовал следующую схему:
CoordinatorLayout --- simple root group
ParentLayout --- aka "parentlayout"
Button --- simple Button example
GridLayout --- aka "gridlayout"
FloattingActionButton --- simple Button example
Давайте его получения выбранный View
и его методы обновления в Activity
:
private View selectedView;
...
private void setViewSelected(View view) {
removeViewSelected();
selectedView = view;
if (selectedView != null) {
// change to a selected background for example
selectedView.setBackgroundColor(
ContextCompat.getColor(this, R.color.colorAccent));
}
}
private View getViewSelected() {
if (selectedView != null) {
return selectedView;
}
return null;
}
private void removeViewSelected() {
if (selectedView != null) {
// reset the original background for example
selectedView.setBackgroundResource(R.drawable.white_with_borders);
selectedView = null;
}
// clear and reset the focus on the parent
parentlayout.clearFocus();
parentlayout.requestFocus();
}
На каждом GridLayout
ребенка, добавьте Click
и LongClick
слушателей, чтобы обновить или удалить выбранный вид. Mine были TextView
s добавлены динамически, но вы можете легко создать для цикла, чтобы получить детей:
TextView tv = new TextView(this);
...
gridlayout.addView(tv);
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
removeViewSelected();
}
});
tv.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
setViewSelected(view);
return true;
}
});
Установите FocusChange
слушателем на родительском контейнере:
parentlayout.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean hasFocus) {
View viewSelected = getViewSelected();
// if the selected view exists and it lost focus
if (viewSelected != null && !viewSelected.hasFocus()) {
// remove it
removeViewSelected();
}
}
});
Затем дополнительный пользовательский ViewGroup
: это необязательно, потому что вы можете установить состояние focusable
по XML и прослушивателю clickable
динамически, но мне кажется, что это проще. Я использовал этот следующий обычай Class
как родительский контейнер:
public class ParentLayout extends RelativeLayout implements View.OnClickListener {
public ParentLayout(Context context) {
super(context);
init();
}
public ParentLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ParentLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
// handle focus and click states
public void init() {
setFocusable(true);
setFocusableInTouchMode(true);
setOnClickListener(this);
}
// when positioning all children within this
// layout, add their focusable state
@Override
protected void onLayout(boolean c, int l, int t, int r, int b) {
super.onLayout(c, l, t, r, b);
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
child.setFocusable(true);
child.setFocusableInTouchMode(true);
}
// now, even the Button has a focusable state
}
// handle the click events
@Override
public void onClick(View view) {
// clear and set the focus on this viewgroup
this.clearFocus();
this.requestFocus();
// now, the focus listener in Activity will handle
// the focus change state when this layout is clicked
}
}
Например, это макет я использовал:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout ...>
<com.app.ParentLayout
android:id="@+id/parent_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal">
<Button
android:id="@+id/sample_button"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:text="A Simple Button"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"/>
<android.support.v7.widget.GridLayout
android:id="@+id/grid_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_above="@id/sample_button" .../>
</com.app.ParentLayout>
<android.support.design.widget.FloatingActionButton .../>
</android.support.design.widget.CoordinatorLayout>
Надеется, что это будет полезно.
Большое спасибо за ваш подробный ответ. После реализации вашего решения _without_ реализации ** ParentLayout ** (1. Использовал экземпляр 'ViewGroup' и раздул XML вместо' ParentLayout' 2. Объявил настройки в завышенном XML вместо внутренних 'onLayout' и' init' методов 3. Зарегистрировал и обработанный 'View.OnClickListener' с расширенным экземпляром' ViewGroup' вместо 'ParentLayout'), кажется, что для того, чтобы _избрать уже выбранный дочерний элемент с помощью щелчка на макете, вам необходимо ** двойное касание ** макет вместо * * одиночный touch ** it. Вы знаете, как его решить? – Eido95
@ Eido95, я внес изменения, чтобы использовать непосредственно «LinearLayout», писать «focusable», «focusableInTouchMode» для детей в XML, а также пытаться использовать «RelativeLayout», создавать 'OnClickListener' на' LinearLayout' вызове 'removeViewSelected() '... все работает так, как ожидалось ** с одним касанием **. Не могли бы вы установить некоторые «Журналы», чтобы увидеть, вызвано ли все? Возможно, см. Этот [связанный вопрос] (http://stackoverflow.com/questions/16792238/onclicklistener-not-triggered-for-custom-view). Если вы не нашли, разместите свой код на Pastebin и свяжите его; Я мог бы проверить это. У меня нет проблем без использования пользовательского класса. – Fllo
Я прочитал вашу связанную с этим проблему, но, к сожалению, она не решила мою проблему. Я загрузил [часть моего кода] (http://pastebin.com/YtdqL4Zp) (6 файлов), который имеет отношение к моему вопросу, поэтому вы можете легко создать его и воспроизвести проблему, о которой я упомянул в своем предыдущем комментарии. Также я выделил соответствующие строки кода, которые выводят журналы, чтобы узнать, какой метод вызван. – Eido95