/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.app; import android.database.Cursor; import android.os.Bundle; import java.util.List; import android.view.ContextMenu; import android.view.View; import android.view.ContextMenu.ContextMenuInfo; import android.view.View.OnCreateContextMenuListener; import android.widget.ExpandableListAdapter; import android.widget.ExpandableListView; import android.widget.SimpleCursorTreeAdapter; import android.widget.SimpleExpandableListAdapter; import android.widget.AdapterView.AdapterContextMenuInfo; import java.util.Map; /** * An activity that displays an expandable list of items by binding to a data * source implementing the ExpandableListAdapter, and exposes event handlers * when the user selects an item. *

* ExpandableListActivity hosts a * {@link android.widget.ExpandableListView ExpandableListView} object that can * be bound to different data sources that provide a two-levels of data (the * top-level is group, and below each group are children). Binding, screen * layout, and row layout are discussed in the following sections. *

* Screen Layout *

*

* ExpandableListActivity has a default layout that consists of a single, * full-screen, centered expandable list. However, if you desire, you can * customize the screen layout by setting your own view layout with * setContentView() in onCreate(). To do this, your own view MUST contain an * ExpandableListView object with the id "@android:id/list" (or * {@link android.R.id#list} if it's in code) *

* Optionally, your custom view can contain another view object of any type to * display when the list view is empty. This "empty list" notifier must have an * id "android:empty". Note that when an empty view is present, the expandable * list view will be hidden when there is no data to display. *

* The following code demonstrates an (ugly) custom screen layout. It has a list * with a green background, and an alternate red "no data" message. *

* *
 * <?xml version="1.0" encoding="UTF-8"?>
 * <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 *         android:orientation="vertical"
 *         android:layout_width="match_parent" 
 *         android:layout_height="match_parent"
 *         android:paddingLeft="8dp"
 *         android:paddingRight="8dp">
 * 
 *     <ExpandableListView android:id="@id/android:list"
 *               android:layout_width="match_parent" 
 *               android:layout_height="match_parent"
 *               android:background="#00FF00"
 *               android:layout_weight="1"
 *               android:drawSelectorOnTop="false"/>
 * 
 *     <TextView android:id="@id/android:empty"
 *               android:layout_width="match_parent" 
 *               android:layout_height="match_parent"
 *               android:background="#FF0000"
 *               android:text="No data"/>
 * </LinearLayout>
 * 
* *

* Row Layout *

* The {@link ExpandableListAdapter} set in the {@link ExpandableListActivity} * via {@link #setListAdapter(ExpandableListAdapter)} provides the {@link View}s * for each row. This adapter has separate methods for providing the group * {@link View}s and child {@link View}s. There are a couple provided * {@link ExpandableListAdapter}s that simplify use of adapters: * {@link SimpleCursorTreeAdapter} and {@link SimpleExpandableListAdapter}. *

* With these, you can specify the layout of individual rows for groups and * children in the list. These constructor takes a few parameters that specify * layout resources for groups and children. It also has additional parameters * that let you specify which data field to associate with which object in the * row layout resource. The {@link SimpleCursorTreeAdapter} fetches data from * {@link Cursor}s and the {@link SimpleExpandableListAdapter} fetches data * from {@link List}s of {@link Map}s. *

*

* Android provides some standard row layout resources. These are in the * {@link android.R.layout} class, and have names such as simple_list_item_1, * simple_list_item_2, and two_line_list_item. The following layout XML is the * source for the resource two_line_list_item, which displays two data * fields,one above the other, for each list row. *

* *
 * <?xml version="1.0" encoding="utf-8"?>
 * <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 *     android:layout_width="match_parent"
 *     android:layout_height="wrap_content"
 *     android:orientation="vertical">
 * 
 *     <TextView android:id="@+id/text1"
 *         android:textSize="16sp"
 *         android:textStyle="bold"
 *         android:layout_width="match_parent"
 *         android:layout_height="wrap_content"/>
 * 
 *     <TextView android:id="@+id/text2"
 *         android:textSize="16sp"
 *         android:layout_width="match_parent"
 *         android:layout_height="wrap_content"/>
 * </LinearLayout>
 * 
* *

* You must identify the data bound to each TextView object in this layout. The * syntax for this is discussed in the next section. *

*

* Binding to Data *

*

* You bind the ExpandableListActivity's ExpandableListView object to data using * a class that implements the * {@link android.widget.ExpandableListAdapter ExpandableListAdapter} interface. * Android provides two standard list adapters: * {@link android.widget.SimpleExpandableListAdapter SimpleExpandableListAdapter} * for static data (Maps), and * {@link android.widget.SimpleCursorTreeAdapter SimpleCursorTreeAdapter} for * Cursor query results. *

* * @see #setListAdapter * @see android.widget.ExpandableListView */ public class ExpandableListActivity extends Activity implements OnCreateContextMenuListener, ExpandableListView.OnChildClickListener, ExpandableListView.OnGroupCollapseListener, ExpandableListView.OnGroupExpandListener { ExpandableListAdapter mAdapter; ExpandableListView mList; boolean mFinishedStart = false; /** * Override this to populate the context menu when an item is long pressed. menuInfo * will contain an {@link android.widget.ExpandableListView.ExpandableListContextMenuInfo} * whose packedPosition is a packed position * that should be used with {@link ExpandableListView#getPackedPositionType(long)} and * the other similar methods. *

* {@inheritDoc} */ @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { } /** * Override this for receiving callbacks when a child has been clicked. *

* {@inheritDoc} */ public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { return false; } /** * Override this for receiving callbacks when a group has been collapsed. */ public void onGroupCollapse(int groupPosition) { } /** * Override this for receiving callbacks when a group has been expanded. */ public void onGroupExpand(int groupPosition) { } /** * Ensures the expandable list view has been created before Activity restores all * of the view states. * *@see Activity#onRestoreInstanceState(Bundle) */ @Override protected void onRestoreInstanceState(Bundle state) { ensureList(); super.onRestoreInstanceState(state); } /** * Updates the screen state (current list and other views) when the * content changes. * * @see Activity#onContentChanged() */ @Override public void onContentChanged() { super.onContentChanged(); View emptyView = findViewById(com.android.internal.R.id.empty); mList = (ExpandableListView)findViewById(com.android.internal.R.id.list); if (mList == null) { throw new RuntimeException( "Your content must have a ExpandableListView whose id attribute is " + "'android.R.id.list'"); } if (emptyView != null) { mList.setEmptyView(emptyView); } mList.setOnChildClickListener(this); mList.setOnGroupExpandListener(this); mList.setOnGroupCollapseListener(this); if (mFinishedStart) { setListAdapter(mAdapter); } mFinishedStart = true; } /** * Provide the adapter for the expandable list. */ public void setListAdapter(ExpandableListAdapter adapter) { synchronized (this) { ensureList(); mAdapter = adapter; mList.setAdapter(adapter); } } /** * Get the activity's expandable list view widget. This can be used to get the selection, * set the selection, and many other useful functions. * * @see ExpandableListView */ public ExpandableListView getExpandableListView() { ensureList(); return mList; } /** * Get the ExpandableListAdapter associated with this activity's * ExpandableListView. */ public ExpandableListAdapter getExpandableListAdapter() { return mAdapter; } private void ensureList() { if (mList != null) { return; } setContentView(com.android.internal.R.layout.expandable_list_content); } /** * Gets the ID of the currently selected group or child. * * @return The ID of the currently selected group or child. */ public long getSelectedId() { return mList.getSelectedId(); } /** * Gets the position (in packed position representation) of the currently * selected group or child. Use * {@link ExpandableListView#getPackedPositionType}, * {@link ExpandableListView#getPackedPositionGroup}, and * {@link ExpandableListView#getPackedPositionChild} to unpack the returned * packed position. * * @return A packed position representation containing the currently * selected group or child's position and type. */ public long getSelectedPosition() { return mList.getSelectedPosition(); } /** * Sets the selection to the specified child. If the child is in a collapsed * group, the group will only be expanded and child subsequently selected if * shouldExpandGroup is set to true, otherwise the method will return false. * * @param groupPosition The position of the group that contains the child. * @param childPosition The position of the child within the group. * @param shouldExpandGroup Whether the child's group should be expanded if * it is collapsed. * @return Whether the selection was successfully set on the child. */ public boolean setSelectedChild(int groupPosition, int childPosition, boolean shouldExpandGroup) { return mList.setSelectedChild(groupPosition, childPosition, shouldExpandGroup); } /** * Sets the selection to the specified group. * @param groupPosition The position of the group that should be selected. */ public void setSelectedGroup(int groupPosition) { mList.setSelectedGroup(groupPosition); } }