我可以禁用ActionBar的导航Spinner吗?

时间:2012-11-12 12:38:52

标签: android android-actionbar

我想要实现的是禁用ActionBar上的所有项目,除了一项。我有一个自定义ActionBar Menu,多个TextViews,一个Button和一个来自ListNavigation的Spinner。 Spinner是由bar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);创建的,如下所示:

    SpinnerAdapter spinnerAdapter = new ArrayAdapter<String>(this.getActivity(), R.layout.action_bar_spinner, names);
    // "listener" for spinner
    bar.setListNavigationCallbacks(spinnerAdapter, new OnNavigationListener() {
        @Override
        public boolean onNavigationItemSelected(int position, long itemId) {
            // do some stuff

            return true;
        }
    });

我想要禁用Spinner,以便它处于非活动状态,但在禁用它之前仍然可以看到最后一项。简而言之,如果它存在,我需要bar.getNavigationSpinner.setEnabled(false)之类的内容。问题是:有某种解决方法吗?如果没有,是否有办法禁用整个ActionBar,但保持可见?

注意:我想在片段中实现它。

3 个答案:

答案 0 :(得分:6)

是的,可以在Spinner中停用列表导航中使用的ActionBar。但这不是一个简单的解决方案,而是一个黑客攻击。 ActionBar不提供对Spinner视图的直接访问。不幸的是,Spinner是在私有代码中创建的,没有任何id。

那么如何访问Spinner实例?一种解决方案可能是通过Java反射API访问它,但我不建议这样做。

更好的解决方案是获取当前Activity的根视图,遍历它的子视图(操作栏及其视图层次结构中存在的所有视图)并找到正确的Spinner。由于操作栏中的Spinner可能是您自己没有创建的唯一一个,因此您应该能够将其与其他人区分开来。

this SO question中描述了获取根View

遍历非常简单,请记住,如果您使用ActionBarSherlock,则必须查找IcsSpinner而不是SpinnerIcsSpinner不会延伸来自Spinner)。

private View findActionBarSpinner() {
    View rootView = findViewById(android.R.id.content).getRootView();
    List<View> spinners = traverseViewChildren( (ViewGroup) rootView );
    return findListNavigationSpinner(spinners); // implement according to your layouts
}

private List<View> traverseViewChildren(ViewGroup parent) {
    List<View> spinners = new ArrayList<View>();
    for (int i = 0; i < parent.getChildCount(); i++) {
        View child = parent.getChildAt(i);
        if (child instanceof Spinner) {
            spinners.add( child );
        } else if (child instanceof IcsSpinner) { // add this if you are using ActionBarSherlock
            spinners.add( child );
        } else if (child instanceof ViewGroup) {
            spinners.addAll( traverseViewChildren( (ViewGroup) child ) );
        }
    }
    return spinners;
}

函数findListNavigationSpinner应该以能够区分其他微调器的方式实现。如果您没有使用任何Spinner(或从中派生的任何视图),则返回的列表应仅包含一个项目。

上面的代码介绍了如何在Spinner中获取Activity。当然,从Spinner中禁用Fragment并不是一个问题。片段引用了它的活动,因此活动可以通过某个接口将代码暴露给片段。

答案 1 :(得分:1)

上述代码不适用于 Action Bar compat(v7支持库)。我需要使用此支持库启用/禁用我的应用程序(API 2.2)的操作栏微调器,但我注意到该类的名称为SpinnerICS而不是Spinner

完整的包名称是

android.support.v7.internal.widget.SpinnerICS

由于此类不可见且无法在我的代码中导入,我无法使用:

if (child instanceof SpinnerICS) ...

所以最后我用getClass().getName解决了我的问题。因此,使用Action Bar compat支持库(v7)启用/禁用微调器的代码将是:

private List<View> traverseViewChildren(ViewGroup parent) {
    List<View> spinners = new ArrayList<View>();
    for (int i = 0; i < parent.getChildCount(); i++) {
        View child = parent.getChildAt(i);

        String className = child.getClass().getName();
        if (child instanceof Spinner || className.equals("android.support.v7.internal.widget.SpinnerICS")) {
            spinners.add( child );
        } else if (child instanceof ViewGroup) {
            spinners.addAll( traverseViewChildren( (ViewGroup) child ) );
        }
    }
    return spinners;
}

此外,我修改了我的findListNavigationSpinner方法,以检查微调器列表是否包含阻止ArrayIndexOutOfBoundsException的元素。因为我的应用程序中只有一个微调器(在Action Bar compat中),所以我的代码就是这个(如果你有多个微调器,你应该调整它):

private View findListNavigationSpinner(List<View> spinners) {
    // We only have one spinner in the app
    View result = null;
    if (spinners != null && spinners.size() > 0) {
         result = spinners.get(0);
    }
    return result;
}

答案 2 :(得分:1)

可以通过注意ActionBar(和Spinner)位于根视图和内容之间(使用id == android.R.id.content)来简化。因此,您可以实现广度优先搜索并返回您找到的第一个Spinner,一旦您使用id == android.R.id.content命中视图,就不再添加到队列中。

或者进行深度优先搜索,但是当你使用id == android.R.id.content点击视图时停止递归,因为Spinner不包含在那里。

所以没有必要维护任何列表,只需返回找到的第一个Spinner。