Hi there !

I spent a bit of time trying to create a spinner that would have some
disabled items, and finally found a SOLUTION ! Yay !

Romain pointed in the right direction, BUT it's not that easy.

If one try to create a specific adapter for the spinner, for
instance :

ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item,filters) {
  public boolean isEnabled(int position) {
    // Specific code to decide whether it's enabled or not
  }
  public boolean areAllItemsEnabled() {
    return false;
  }
};
spinner.setAdapter(spinnerAdapter);
=> DOESN'T work yet

When you click on a spinner, it opens a dialog with the items feeded
from the adapter.

BUT the adapter is wrapped by the spinner class into a DropDownAdapter
(private class inside the spinner class).

This wrapper delegates almost all method calls, except...

public boolean areAllItemsEnabled() {
  return true;
}

public boolean isEnabled(int position) {
  return true;
}

I don't know if there's a real reason for that. The delegate is
wrapped as as SpinnerAdapter, which doesn't hold those methods.

So the solution was pretty simple thought a bit dirty : extends
Spinner, override performClick() (this is were the adapter is
wrapped), and basically do the same thing as a spinner, but with a
patched DropDownAdapter :

/**
 * A patcher spinner so that the wrapping drop down adapter delegates
 * areAllItemsEnabled and isEnabled calls to the wrapped adapter.
 */
public class PatchedSpinner extends Spinner {

    public PatchedSpinner(Context context, AttributeSet attrs, int
defStyle) {
        super(context, attrs, defStyle);
    }
    public PatchedSpinner(Context context) {
        super(context);
    }
    public PatchedSpinner(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    public boolean performClick() {

        // boolean handled = super.performClick(); => this line
removed, we do not want to delegate the click to the spinner.

        Context context = getContext();

        final DropDownAdapter adapter = new DropDownAdapter(getAdapter
());

        CharSequence mPrompt = getPrompt();

        AlertDialog.Builder builder = new AlertDialog.Builder
(context);
        if (mPrompt != null) {
            builder.setTitle(mPrompt);
        }
        builder.setSingleChoiceItems(adapter, getSelectedItemPosition
(), this).show();

        return true;
    }

    private static class DropDownAdapter implements ListAdapter,
SpinnerAdapter {
        private SpinnerAdapter mAdapter;

        public DropDownAdapter(SpinnerAdapter adapter) {
            mAdapter = adapter;
        }

        public int getCount() {
            return mAdapter == null ? 0 : mAdapter.getCount();
        }

        public Object getItem(int position) {
            return mAdapter == null ? null : mAdapter.getItem
(position);
        }

        public long getItemId(int position) {
            return mAdapter == null ? -1 : mAdapter.getItemId
(position);
        }

        public View getView(int position, View convertView, ViewGroup
parent) {
            return getDropDownView(position, convertView, parent);
        }

        public View getDropDownView(int position, View convertView,
ViewGroup parent) {
            return mAdapter == null ? null : mAdapter.getDropDownView
(position, convertView, parent);
        }

        public boolean hasStableIds() {
            return mAdapter != null && mAdapter.hasStableIds();
        }

        public void registerDataSetObserver(DataSetObserver observer)
{
            if (mAdapter != null) {
                mAdapter.registerDataSetObserver(observer);
            }
        }

        public void unregisterDataSetObserver(DataSetObserver
observer) {
            if (mAdapter != null) {
                mAdapter.unregisterDataSetObserver(observer);
            }
        }

        // PATCHED
        public boolean areAllItemsEnabled() {
            if (mAdapter instanceof BaseAdapter) {
                return ((BaseAdapter) mAdapter).areAllItemsEnabled();
            } else {
                return true;
            }
        }

        // PATCHED
        public boolean isEnabled(int position) {
            if (mAdapter instanceof BaseAdapter) {
                return ((BaseAdapter) mAdapter).isEnabled(position);
            } else {
                return true;
            }
        }

        public int getItemViewType(int position) {
            return 0;
        }

        public int getViewTypeCount() {
            return 1;
        }

        public boolean isEmpty() {
            return getCount() == 0;
        }
    }

}

If you think I'm doing things wrong, please let me know. This patched
spinner suits my needs.

Cheers,
Piwaï

PS : BTW, merci Romain pour le hint dans la bonne direction.


On Dec 15 2009, 7:54 am, Romain Guy <[email protected]> wrote:
> I just linked to it. ListAdapter.isEnabled(int).
>
>
>
> On Mon, Dec 14, 2009 at 10:49 PM, rexowner <[email protected]> wrote:
> > Thank you for your reply.
>
> > None of the 2 Class methods or 8 inherited methods on the page cited
> > appear to have
> > anything to do with disabling items in the list.  None of the
> > subclasses
> > appear to have a way to do this either.
>
> > Maybe I am dense, but it is not at all clear how to do this.
>
> > On Dec 13, 2:10 pm, Romain Guy <[email protected]> wrote:
> >> This is performed by the 
> >> adapter:http://d.android.com/reference/android/widget/ListAdapter.html#isEnab...)
>
> >> On Fri, Dec 11, 2009 at 4:50 PM, rexowner <[email protected]> wrote:
> >> > I also want to do this, and after hunting around for half a day, have
> >> > not found a way to do it,
> >> > and am moving on to some other priorities.
>
> >> > I also would be very interested in this useful behavior.
>
> >> > Sorry I can't be of more help, but if you find a way, please post.
>
> >> > Thanks!
>
> >> > On Dec 10, 4:36 pm, Keith Wiley <[email protected]> wrote:
> >> >> How do Idisable(gray out, make unselectable) an item in aSpinner?
> >> >> I tried calling View.disable() on the associated child of theSpinner,
> >> >> but it remains black text (not gray) and selectable.
>
> >> >> There must be some way of showing but leaving unselectable certain
> >> >> items in aspinner, right?  This is a standard "menu" behavior that
> >> >> goes back decades.  Android permits it, right?  I want the user to see
> >> >> that certain options are possible under certain circumstances even if
> >> >> they are impossible at the immediate moment...exactly the way items in
> >> >> the main Android menu-button invoked menu can be visible but
> >> >> unselectable.
>
> >> >> Thanks a lot.  I'm sure I'm just missing something obvious here.
>
> >> >> Cheers!
>
> >> > --
> >> > You received this message because you are subscribed to the Google
> >> > Groups "Android Developers" group.
> >> > To post to this group, send email to [email protected]
> >> > To unsubscribe from this group, send email to
> >> > [email protected]
> >> > For more options, visit this group at
> >> >http://groups.google.com/group/android-developers?hl=en
>
> >> --
> >> Romain Guy
> >> Android framework engineer
> >> [email protected]
>
> >> Note: please don't send private questions to me, as I don't have time
> >> to provide private support.  All such questions should be posted on
> >> public forums, where I and others can see and answer them
>
> > --
> > You received this message because you are subscribed to the Google
> > Groups "Android Developers" group.
> > To post to this group, send email to [email protected]
> > To unsubscribe from this group, send email to
> > [email protected]
> > For more options, visit this group at
> >http://groups.google.com/group/android-developers?hl=en
>
> --
> Romain Guy
> Android framework engineer
> [email protected]
>
> Note: please don't send private questions to me, as I don't have time
> to provide private support.  All such questions should be posted on
> public forums, where I and others can see and answer them

-- 
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

Reply via email to