Steven Schoen
Steven Schoen

Reputation: 4386

How can I add spinner functionality to my ListView items?

I have a custom list adapter. Here it is:

public class FilesAdapter extends ArrayAdapter<PutioFileLayout> {

    Context context;
    int layoutResourceId;
    List<PutioFileLayout> data = null;

    public FilesAdapter(Context context, int layoutResourceId, List<PutioFileLayout> data) {
        super(context, layoutResourceId, data);
        this.layoutResourceId = layoutResourceId;
        this.context = context;
        this.data = data;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View row = convertView;
        FileHolder holder = null;

        if (row == null) {
            LayoutInflater inflater = ((Activity) context).getLayoutInflater();
            row = inflater.inflate(layoutResourceId, parent, false);

            holder = new FileHolder();
            holder.textName = (TextView) row.findViewById(R.id.text_fileListName);
            holder.textDescription = (TextView) row.findViewById(R.id.text_fileListDesc);
            holder.imgIcon = (ImageView) row.findViewById(R.id.img_fileIcon);

            row.setTag(holder);
        } else {
            holder = (FileHolder) row.getTag();
        }

        PutioFileLayout file = data.get(position);
        holder.textName.setText(file.name);
        holder.textDescription.setText(file.description);
        holder.imgIcon.setImageResource(file.icon);

        return row;
    }

    static class FileHolder {
        TextView textName;
        TextView textDescription;
        ImageView imgIcon;
    }
}

Pretty short and sweet. I have Spinners in my layout for each row, and I want the user to be able to click them, and get a contextual menu for each item. How can I implement this in my adapter?

My row.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="64dp" >

    <ImageView
        android:id="@+id/img_fileIcon"
        android:layout_width="36dp"
        android:layout_height="36dp"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:scaleType="fitCenter"
        android:src="@drawable/ic_launcher" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_toRightOf="@id/img_fileIcon"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/text_fileListName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="12dp"
            android:layout_marginTop="12dp"
            android:ellipsize="end"
            android:maxLines="1"
            android:text="File name"
            android:textAppearance="?android:attr/textAppearanceMedium" />

        <FrameLayout
            android:id="@+id/descriptionFrame"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="12dp"
            android:layout_marginRight="30dp" >

            <TextView
                android:id="@+id/text_fileListDesc"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="File description" />
        </FrameLayout>
    </LinearLayout>

    <Spinner
        android:id="@+id/item_fileSpinner"
        android:layout_width="44dp"
        android:layout_height="match_parent"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:background="@drawable/spinner_background_ab_putio" />

</RelativeLayout>

Upvotes: 3

Views: 5243

Answers (2)

Shark
Shark

Reputation: 6620

why can't you use createContextMenu() ? in case you can, override onContextCreate() and add your view IDs there....

I don't have sample code atm, but I will when i get to the office on monday. Really, context menus are the easiest way to do it.

Then again, tim's idea seems to have did the trick.

EDIT: as promised on monday, sample code.

res\menu\context_menu.xml -- note that you can change this name.

<item
    android:id="@+id/context_menu_call"
    android:title="@string/context_menu_call"/>
<item
    android:id="@+id/context_menu_video_call"
    android:title="@string/context_menu_video_call"/>
<item
    android:id="@+id/context_menu_send_im"
    android:title="@string/context_menu_send_im"/>
<item
    android:id="@+id/context_menu_call_number"
    android:title="@string/context_menu_call_number"/>
<item
    android:id="@+id/context_menu_view_profile"
    android:title="@string/context_menu_view_profile"/>

then in code

   @Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
{
    super.onCreateContextMenu(menu, v, menuInfo);
    MenuInflater inflater = getMenuInflater();
    switch (v.getId())
    {
        case R.id.listConversations:        //mainContactList from initMainLayoutElements()
            contextList = mainContactList;
            inflater.inflate(R.menu.context_menu, menu);
            break;
        case R.id.listContacts:             //chatContacts from initChatLayoutElements()
            contextList = chatContactList;
            inflater.inflate(R.menu.context_menu, menu);
            break;
        case R.id.listContactsManagement:       //contactList from initContactLayoutElements()
            contextList = contactMgmtList;
            inflater.inflate(R.menu.context_menu, menu);
            break;

        case R.id.btn_sms_settings:
            inflater.inflate(R.menu.sms_menu, menu);
            break;
    }
}

now that we defined how to open context menus, we need to define what the actual items do...

  @Override
public boolean onContextItemSelected(MenuItem item)
{
    item.getMenuInfo();

    switch (item.getItemId())
    {
        case R.id.context_menu_call:
            onCallStartFromContextMenu(false);
            return true;

        case R.id.context_menu_video_call:
            onCallStartFromContextMenu(true);
            return true;

        case R.id.context_menu_send_im:
            layoutState(LayoutState.CHAT);
            Log.d(TAG, "Preparing chat session from context menu for " + getChattersFromList(contextList).toString());
            chatSource = ChatSource.FROM_CONTEXT_MENU;
            prepareChatSessionWith(getChattersFromList(contextList).toArray(new String[getChatterCount(contextList)]));
            return true;

        case R.id.context_menu_call_number:
            Buddy selectedBuddy = (Buddy) contextList.getAdapter().getItem(contextList.getSelectedItemPosition());
            lastCaller = selectedBuddy.toString();
            showAlternateCallDialog(selectedBuddy, !selectedBuddy.getNumberHome().isEmpty(),
                    !selectedBuddy.getNumberMobile().isEmpty(), !selectedBuddy.getNumberOffice().isEmpty());
            return true;

        case R.id.context_menu_view_profile:
            //              Buddy who = buddyAdapter.getItem(listConversations.getSelectedItemPosition());
            Buddy who = (Buddy) contextList.getAdapter().getItem(contextList.getSelectedItemPosition());
            Log.d(TAG, "viewing profile " + who.toString());
            lastProfileName = who.getIdentity();
            showProfileScreen(who);
            return true;
            //transfers

        default:
            contextList = null;
            return super.onContextItemSelected(item);
    }
}

don't forget to register the component to the context menu 'listener'. These are actual ListView references.

    registerForContextMenu(mainContactList);
    registerForContextMenu(chatContactList);

and finally, the only thing left is OPENING the context menus for items...

 chatContactList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener()
    {
        @Override
        public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id)
        {
            Log.d(TAG, "chatContacts.onItemLongClick fired!");
            chatContactList.setItemChecked(position, true);
            openContextMenu(chatContactList);
            return true;
        }
    });

  mainContactList.setOnItemLongClickListener(new ListView.OnItemLongClickListener()
    {
        @Override
        public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id)
        {
            Log.d(TAG, "mainContactList.onItemLongClick fired!!!");
            mainContactList.setItemChecked(position, true);
            openContextMenu(mainContactList);
            return false;
        }
    });

i prefer using context menus on LongClick instead of just onItemClicked because you might wanna do something on clicking (like, file selection and stuff) and offer less-accessed functionalities on a long click like rename / delete etc

so there you go. context menus are easy ;)

Upvotes: 2

FoamyGuy
FoamyGuy

Reputation: 46856

Inside your getView() method get a reference to the spinner like this:

Spinner spn = row.findViewById(R.id.item_fileSpinner);

once you have the reference you can set its items by creating a SpinnerAdapter with all of your values and set it with

spn.setAdapater(mSpinAdapter);

I can give you a more specific example of how you'd create and fill your adapter if you can tell me what data you are hoping to fill the spinner with.

then all thats left is to set an OnItemSelectedListener, which you can do like this.

spn.setOnItemSelectedListner(new OnItemSelectedListener(){

    public void onItemSelected(AdapterView<?> parent, View view, int spnPosition, long id){
        //Do something
    }
});

Note the use of spnPosition in the onItemSelected callback. If you use position then you will no longer have access to the getView() parameter position so use a different name so that you can access both/either if needbe.

Upvotes: 2

Related Questions