Can I turn off ActionBar Spinner navigation?

I want to achieve that to disconnect all elements on ActionBar, except for one. I have a custom ActionBar with Menu , several TextViews , one Button and Spinner from ListNavigation. Spinner created due to bar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); in the following way:

  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; } }); 

I want to disable Spinner so that it is inactive, but it still displays with the last item selected before disabling it. In short, I need something like bar.getNavigationSpinner.setEnabled(false) if it existed. Question: is there any workaround? If not, is there a way to disable the whole ActionBar but keep it visible?

Note. I want to achieve this in a fragment.

+4
source share
3 answers

Yes, you can disable the Spinner used in list navigation in ActionBar . But this is not a simple solution, but a hack. ActionBar does not provide direct access to the Spinner view. Unfortunately, Spinner is created in personal code without any identifier.

So how to access a Spinner instance? One solution might be to access it through the Java reflection API, but I would not recommend this.

The best solution is to get the root view for the current Activity , cross its child views (the action bar and all its views are present in the view hierarchy) and find the correct Spinner . Since the Spinner in the action bar is apparently the only one that you did not create yourself, you should be able to distinguish it from others.

Getting the root of the View described in this SO question .

The workaround is quite simple, just keep in mind that if you use ActionBarSherlock , you need to look for IcsSpinner instead of Spinner ( IcsSpinner not distributed by 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; } 

The findListNavigationSpinner function must be implemented in such a way that you can distinguish other spinners. If you are not using any Spinner (or any view derived from it), the returned list should contain only one element.

The code above describes how to get a Spinner in an Activity . Naturally, you should not disconnect Spinner from within Fragment . A fragment has a link to its activity, so an action can issue code to a fragment through some interface.

+6
source

The above code does not work with Action Bar protection (v7 support library) . I needed to enable / disable the spinner of my application (API 2.2) using this support library, but I noticed that the class name is SpinnerICS instead of Spinner .

Full package name

 android.support.v7.internal.widget.SpinnerICS 

Due to this class it is not visible and cannot be imported into my code, I can not use:

 if (child instanceof SpinnerICS) ... 

So, I solved the problem using getClass().getName . Therefore, the code for enabling / disabling the counter using the Action Bar (v7) compatibility support library will look like this:

 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; } 

In addition, I changed the findListNavigationSpinner method to check if the spinner list contains ArrayIndexOutOfBoundsException elements. Since I have only one spinner in my application (in the Action Bar command), so my code is this (you have to adapt it if you have more than one counter):

 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; } 
+1
source

This can be simplified by noting that the ActionBar (and Spinner) is between the root view and the content (with id == android.R.id.content). Thus, you can implement a width search and return the first Spinner that you find, no longer adding to the queue after you click the view with id == android.R.id.content.

Or do a depth search, but stop the recursion when you click on the view with id == android.R.id.content, since Spinner is not there.

Therefore, there is no need to maintain any list, just return the first Spinner found.

+1
source

Source: https://habr.com/ru/post/1445506/


All Articles