[英]How to get selected child in GridLayout similar to GridView
I want to achieve the following abilities: 我要实现以下能力:
View
inside a GridLayout
each time by long clicking it. GridLayout
选择一个子View
。 GridLayout
or any ancestor parent in the visual hierarchy will deselected selected child View
if one already selected. GridLayout
还是在视觉层次有父父将取消选择的子View
如果已经选定。 The problem is when when registering a View.OnLongClickListener
callback to child View
, neither parent GridLayout
nor any ancestor registered callbacks (either View.OnClickListener
or View.onTouchEvent
) called when clicking on them. 问题是,当将
View.OnLongClickListener
回调注册到子View
时,单击它们时,父GridLayout
或任何祖先注册的回调( View.OnClickListener
或View.onTouchEvent
)都View.OnClickListener
被调用。
How can I get a selected child inside a GridLayout
similar to either AdapterView.OnItemSelectedListener
or AdapterView.OnItemLongClickListener
and solve the above mentioned problem? 如何在与
AdapterView.OnItemSelectedListener
或AdapterView.OnItemLongClickListener
相似的GridLayout
获取选定的子AdapterView.OnItemLongClickListener
并解决上述问题?
What about storing a "selected" view as a global variable, and removing it when its focus changes? 将“选定”视图存储为全局变量,并在其焦点更改时将其删除怎么办? By playing with
focusable
, focusableInTouchMode
and onClick
listeners, you could have the right results. 通过使用
focusable
, focusableInTouchMode
和onClick
侦听器,您可以获得正确的结果。 I'm not sure that's the best solution, but it works. 我不确定这是否是最好的解决方案,但它是否有效。
What you will need: 您将需要什么:
- A global View variable : the
GridLayout
's child long clicked, as selected.全局View变量 :长时间选中
GridLayout
的子级。- (optional) A custom parent container as any
ViewGroup
: it will set the focusable listeners on all its children [*] .(可选)与任何
ViewGroup
一样的自定义父容器 :它将在其所有子级[*]上设置可聚焦的侦听器。 In my tests, I used aLinearLayout
and aRelativeLayout
.在测试中,我使用了
LinearLayout
和RelativeLayout
。
[*] If you don't use the optional parent custom Class, you have to set android:focusable="true"
and android:focusableInTouchMode="true"
on all children of the parent ViewGroup. [*]如果您不使用可选的父级自定义类,则必须在父级ViewGroup的所有子级上设置
android:focusable="true"
和android:focusableInTouchMode="true"
。 And you'll have to set OnClickListener
in order to call removeViewSelected()
when the parent ViewGroup is clicked. 而且,您必须设置
OnClickListener
才能在单击父ViewGroup时调用removeViewSelected()
。
- Adding Click listeners for
GridLayout
children: which updates the selected view.为
GridLayout
子级添加Click侦听器:更新所选视图。- Implementing a Focus listener : which removes the selected view if it's losing focus.
实现Focus侦听器 :如果所选视图失去焦点,则将其删除。
It will handle all focus change state on parent and child hierarchy, see the output: 它将处理父级和子级层次结构上的所有焦点更改状态,请参见输出:
I used the following pattern: 我使用以下模式:
CoordinatorLayout --- simple root group
ParentLayout --- aka "parentlayout"
Button --- simple Button example
GridLayout --- aka "gridlayout"
FloattingActionButton --- simple Button example
Let's preparing the selected View
and its update methods in the Activity
: 让我们在
Activity
准备选定的View
及其更新方法:
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();
}
On each GridLayout
child, add the Click
and LongClick
listeners to update or remove the selected view. 在每个
GridLayout
子级上,添加Click
和LongClick
侦听器以更新或删除所选视图。 Mine were TextView
s added dynamically, but you could easily create a for-loop to retrieve the children: 我的是动态添加的
TextView
,但是您可以轻松创建一个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;
}
});
Set the FocusChange
listener on the parent container: 在父容器上设置
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();
}
}
});
Then, the optional custom ViewGroup
: it's optional because you could set the focusable
state by XML and the clickable
listener dynamically, but it seems easier to me. 然后,可选的自定义
ViewGroup
:这是可选的,因为您可以通过XML和clickable
侦听器动态设置focusable
状态,但对我来说似乎更容易。 I used this following custom Class
as parent container: 我使用以下自定义
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
}
}
For example, this is the layout I used: 例如,这是我使用的布局:
<?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>
Hope this will be useful. 希望这会有用。
Use the following code : 使用以下代码:
int last_pos = -1;
GridLayout gridLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gridLayout = (GridLayout) findViewById(R.id.gridLayout);
int child_count = gridLayout.getChildCount();
for(int i =0;i<child_count;i++){
gridLayout.getChildAt(i).setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
//Deselect previous
if(last_pos!=-1) gridLayout.getChildAt(last_pos).setSelected(false);
//Select the one you clicked
view.setSelected(true);
last_pos = gridLayout.indexOfChild(view);
return false;
}
});
}
//Remove focus if the parent is clicked
gridLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
gridLayout.getChildAt(last_pos).setSelected(false);
}
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.