我要实现以下能力:
每次单击View
时,只能选择一个子GridLayout
。
单击GridLayout
或视觉层次结构中的任何祖先父级,将取消选择所选子级View
(如果已选择)。
问题是,当将View.OnLongClickListener
回调注册到子View
时,单击父cc或任何祖先注册的回调(GridLayout
或View.OnClickListener
)都不会调用它们。
如何在与View.onTouchEvent
或GridLayout
相似的AdapterView.OnItemSelectedListener
内获取选定的孩子并解决上述问题?
最佳答案
将“选定”视图存储为全局变量,并在其焦点更改时将其删除怎么办?通过与focusable
,focusableInTouchMode
和onClick
侦听器一起播放,您可以获得正确的结果。我不确定这是否是最好的解决方案,但它是否有效。
您将需要什么:
全局View变量:长时间选中GridLayout
的子项,将其选中。
(可选)作为任何ViewGroup
的自定义父容器:它将在其所有子项[*]上设置可聚焦的侦听器。在测试中,我使用了LinearLayout
和RelativeLayout
。
[*]如果不使用可选的父级自定义类,则必须在父级ViewGroup的所有子级上设置android:focusable="true"
和android:focusableInTouchMode="true"
。而且,当单击父ViewGroup时,必须设置OnClickListener
才能调用removeViewSelected()
。
为GridLayout
子项添加Click侦听器:更新所选视图。
实现焦点侦听器:如果所选视图失去焦点,它将删除所选视图。
它将处理父级和子级层次结构上的所有焦点更改状态,请参见输出:
我使用以下模式:
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
侦听器以更新或删除所选视图。我的矿井是动态添加的,但您可以轻松地创建一个for循环来检索子矿井: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;
}
});
在父容器上设置
TextView
侦听器: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();
}
}
});
然后,可选的自定义
FocusChange
:这是可选的,因为您可以通过XML和ViewGroup
侦听器动态设置focusable
状态,但是对我来说似乎更容易。我使用以下自定义clickable
作为父容器: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>
希望这会有用。
关于java - 如何在类似于GridView的GridLayout中获取选定的子项,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41303999/