Custom Spinners/drop down menu

Cole picture Cole · Mar 23, 2012 · Viewed 25.9k times · Source

In the app Astrid Tasks, there is a button. When you press the button, a drop down menu comes up.

enter image description here

enter image description here

It's basically a spinner but in a drop-down-list form.

Does anyone know how to do something similar? Is this a widget I just don't see?

Answer

sboz88 picture sboz88 · Mar 24, 2012

As the original author of this (I'm one of the primary Android developers for Astrid) I'd be happy to share how Astrid does it. I'll post the basics here, but you can find more details at our github repo (https://github.com/todoroo/astrid). The basic idea is to extend GreenDroid's QuickActionWidget as hanry suggests. The subclass looks something like:

public class MenuPopover extends QuickActionWidget {

    protected DisplayMetrics metrics;
    protected LinearLayout content;

    public MenuPopover(Context context) {
        super(context);
        setContentView(R.layout.my_layout);

        content = (LinearLayout) getContentView().findViewById(R.id.content);
        metrics = context.getResources().getDisplayMetrics();

        setFocusable(true);
        setTouchable(true);
    }

    @Override
    protected void populateQuickActions(List<QuickAction> quickActions) {
        // Do nothing
    }

    @Override
    protected void onMeasureAndLayout(Rect anchorRect, View contentView) {
        contentView.setLayoutParams(new     FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,     ViewGroup.LayoutParams.WRAP_CONTENT));
        contentView.measure(MeasureSpec.makeMeasureSpec(getScreenWidth(),     MeasureSpec.EXACTLY),
                ViewGroup.LayoutParams.WRAP_CONTENT);

        int rootHeight = contentView.getMeasuredHeight();

        int offsetY = getArrowOffsetY();
        int dyTop = anchorRect.top;
        int dyBottom = getScreenHeight() - anchorRect.bottom;

        boolean onTop = (dyTop > dyBottom);
        int popupY = (onTop) ? anchorRect.top - rootHeight + offsetY : anchorRect.bottom -  offsetY;

        setWidgetSpecs(popupY, onTop);
    }
}

The layout file my_layout.xml is pretty simple:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingLeft="10dip">

        <LinearLayout
                android:id="@+id/content"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/gdi_arrow_up"
                android:orientation="vertical"/>

        <ImageView
            android:id="@+id/gdi_arrow_up"
            android:layout_width="27dip"
            android:layout_height="27dip"
            android:layout_marginLeft="-10dip"
            android:scaleType="fitCenter"
            android:layout_marginBottom="-8dip"
            android:src="?attr/asListArrowUp" />

        <ImageView
            android:id="@+id/gdi_arrow_down"
            android:layout_width="27dip"
            android:layout_height="27dip"
            android:scaleType="fitCenter"
            android:layout_marginBottom="-8dip"
            android:layout_below="@android:id/list"/>

        </RelativeLayout>
</FrameLayout>

Then, you can just add a simple helper method to the popover class to add views (i.e. rows, with optional listeners) to the main body of the popover:

public void addViewToContent(View v, OnClickListener listener) {
    content.addView(v);
    if (listener != null) {
        v.setOnClickListener(listener);
    }
}

After creating an instance of the popup, you can show it by calling

menuPopover.show(anchorView);

This is a somewhat simplified version -- in practice, we attach some addition information, listeners, etc. to those views to make them actually do things when clicked. If you want, you can check out the full code at https://github.com/todoroo/astrid -- the class is com.todoroo.astrid.ui.MainMenuPopover.

Thanks for using Astrid!