我想要实现的是禁用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
,但保持可见?
注意:我想在片段中实现它。
答案 0 :(得分:6)
是的,可以在Spinner
中停用列表导航中使用的ActionBar
。但这不是一个简单的解决方案,而是一个黑客攻击。 ActionBar不提供对Spinner
视图的直接访问。不幸的是,Spinner
是在私有代码中创建的,没有任何id。
那么如何访问Spinner
实例?一种解决方案可能是通过Java反射API访问它,但我不建议这样做。
更好的解决方案是获取当前Activity
的根视图,遍历它的子视图(操作栏及其视图层次结构中存在的所有视图)并找到正确的Spinner
。由于操作栏中的Spinner
可能是您自己没有创建的唯一一个,因此您应该能够将其与其他人区分开来。
this SO question中描述了获取根View
。
遍历非常简单,请记住,如果您使用ActionBarSherlock,则必须查找IcsSpinner
而不是Spinner
(IcsSpinner
不会延伸来自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。