Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/183.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在GridLayout中获得与GridView类似的选定子项_Java_Android_Android Adapter_Grid Layout_View Hierarchy - Fatal编程技术网

Java 如何在GridLayout中获得与GridView类似的选定子项

Java 如何在GridLayout中获得与GridView类似的选定子项,java,android,android-adapter,grid-layout,view-hierarchy,Java,Android,Android Adapter,Grid Layout,View Hierarchy,我想达到以下能力: 通过长时间单击GridLayout,每次仅在GridLayout中选择一个子View 单击GridLayout或可视化层次结构中的任何父级将取消选择所选子级视图(如果已选择) 问题在于注册视图时。仅长按Listener回调到子视图,单击时既不会调用父GridLayout,也不会调用任何祖先注册的回调(无论是视图。OnClickListener还是视图。onTouchEvent) 如何在GridLayout中获得与AdapterView.OnItemSelectedList

我想达到以下能力:

  • 通过长时间单击
    GridLayout
    ,每次仅在
    GridLayout
    中选择一个子
    View
  • 单击
    GridLayout
    或可视化层次结构中的任何父级将取消选择所选子级
    视图
    (如果已选择)
问题在于注册
视图时。仅长按Listener
回调到子
视图
,单击时既不会调用父
GridLayout
,也不会调用任何祖先注册的回调(无论是
视图。OnClickListener
还是
视图。onTouchEvent


如何在
GridLayout
中获得与
AdapterView.OnItemSelectedListener
AdapterView.OnItemLongClickListener
类似的选定子级并解决上述问题?

使用以下代码:

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);
        }
    });
int last_pos=-1;
网格布局;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gridLayout=(gridLayout)findViewById(R.id.gridLayout);
int child_count=gridLayout.getChildCount();

对于(int i=0;i使用以下代码:

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);
        }
    });
int last_pos=-1;
网格布局;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gridLayout=(gridLayout)findViewById(R.id.gridLayout);
int child_count=gridLayout.getChildCount();
对于(int i=0;i如何将“选定”视图存储为全局变量,并在其焦点改变时将其删除?通过使用
focusable
focusableInTouchMode
onClick
监听器,您可以得到正确的结果。我不确定这是最佳解决方案,但它可以工作

您需要什么:

  • 全局视图变量:选中的
    网格布局
    的子项长时间单击
  • (可选)自定义父容器作为任何
    视图组
    :它将在其所有子对象[*]上设置聚焦侦听器。在我的测试中,我使用了
    线性布局
    相对布局
[*]如果不使用可选的父自定义类,则必须在父视图组的所有子级上设置
android:focusableInTouchMode=“true”和
android:focusableInTouchMode=“true”
,并且必须设置
OnClickListener
才能调用
removeViewSelected()
单击父视图组时

  • 添加单击
    GridLayout
    子项的侦听器
    :更新所选视图
  • 实现一个焦点侦听器:如果选定视图失去焦点,它将删除该视图
它将处理父层次结构和子层次结构上的所有焦点更改状态,请参见输出:

我使用了以下模式:

CoordinatorLayout         --- simple root group
    ParentLayout          --- aka "parentlayout"
        Button            --- simple Button example
        GridLayout        --- aka "gridlayout"
    FloattingActionButton --- simple Button example
让我们在
活动中准备选定的
视图
及其更新方法

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
子项上,添加
单击
长单击
侦听器以更新或删除所选视图。我的视图是动态添加的
TextView
s,但您可以轻松创建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;
    }
});
在父容器上设置
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();
        }
    }
});
然后,可选的自定义
视图组
:它是可选的,因为您可以通过XML和
可单击的
侦听器动态设置
可聚焦的
状态,但对我来说似乎更容易。我使用以下自定义
作为父容器:

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
    }
}
公共类ParentLayout扩展了RelativeLayout实现View.OnClickListener{
公共父布局(上下文){
超级(上下文);
init();
}
公共父布局(上下文、属性集属性){
超级(上下文,attrs);
init();
}
公共父布局(上下文上下文、属性集属性、int-defStyleAttr){
super(上下文、attrs、defStyleAttr);
init();
}
//处理焦点并单击状态
公共void init(){
设置聚焦(真);
setFocusableInTouchMode(真);
setOnClickListener(此);
}
//当将所有子项放置在此
//布局,添加其可聚焦状态
@凌驾
仅受保护的void布局(布尔c、int l、int t、int r、int b){
超级在线布局(c、l、t、r、b);
最终整数计数=getChildCount();
for(int i=0;i
例如,这是我使用的布局:

<?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>

希望这会有用。

如何将“选定”视图存储为全局变量,并在其焦点改变时将其删除?通过使用
focusable
focusableInTouchMode
onClick
监听器,您可以获得正确的结果。我不确定这是最佳解决方案,但它是有效的

您需要什么:

  • 全局视图变量:选中的
    网格布局
    的子项长时间单击
  • (可选)自定义父容器作为任何
    视图组
    :它将在其所有子对象[*]上设置可聚焦的侦听器