/*
* 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.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.ListView;
/**
* 用于显示绑定的类似数组、游标等数据源的项目列表的活动,提供了用户选择条目时的事件处理句柄。
* <p>
* ListActivity 内嵌了可以绑定到各种不同数据源,通常为数组或保存了检索结果的游标的
* {@link android.widget.ListView ListView} 对象。下面小节讨论了绑定、屏幕布局、
* 行布局等内容。
* <p>
* <strong>屏幕布局</strong>
* </p>
* <p>
* ListActivity 自带了一个对屏幕居中的全屏列表布局。 你可以通过在 onCreate() 中调用
* setContentView() 来设置自己的视图布局。 你的布局中必须包含一个 ID 为 "@android:id/list"
* (代码中为 {@link android.R.id#list})的 ListView 对象。</p>
* <p>
* 可选项,你的自定义视图可以包含另一个任意类型的视图对象,用于在列表视图为空时显示。
* 这个“空列表”提示的 ID 必须为“android:id/empty”。当空视图存在时,如果没有数据可显示,
* 列表视图会被隐藏起来。</p>
* <p>
* 接下来的代码演示了一个(丑陋的)自定义屏幕布局。
* 他拥有一个绿色背景的列表,和红色的“没有数据”消息。
* </p>
*
* <pre>
* <?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">
*
* <ListView android:id="@android:id/list"
* android:layout_width="match_parent"
* android:layout_height="match_parent"
* android:background="#00FF00"
* android:layout_weight="1"
* android:drawSelectorOnTop="false"/>
*
* <TextView android:id="@android:id/empty"
* android:layout_width="match_parent"
* android:layout_height="match_parent"
* android:background="#FF0000"
* android:text="没有数据"/>
* </LinearLayout>
* </pre>
*
* <p>
* <strong>行布局</strong>
* </p>
* <p>
* 你可以指定列表中个别行的布局。 你可以通过在活动内嵌的 ListAdapter 对象中指定布局资源来实现
* (ListAdapter 将数据绑定到 ListView;在后面详述)。</p>
* <p>
* ListAdapter 的构造方法需要一个用于指定每行的布局资源的参数。
* 它还有两个附加参数,用于指定那个字段与行布局资源中的那个对象关联。
* 这两个参数通常是并列数组。
* </p>
* <p>
* Android 提供了一些标准的行布局资源。 它们在 {@link android.R.layout} 类中,名字类似
* simple_list_item_1、simple_list_item_2、two_line_list_item 等。
* 接下来的 XML 布局是 two_line_list_item 的源代码,为每个列表项显示了上下两个数据字段。
* </p>
*
* <pre>
* <?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>
* </pre>
*
* <p>
* 你必须在布局中标识绑定到每个 TextView 的数据。下一节讨论其语法。
* </p>
* <p>
* <strong>绑定到数据</strong>
* </p>
* <p>
* 你可以通过实现了{@link android.widget.ListAdapter ListAdapter} 接口的类将 ListActivity
* 中的 ListView 对象绑定到数据。Android 提供了两个标准的列表适配器:
* {@link android.widget.SimpleAdapter SimpleAdapter} 用于静态数据(Map);
* {@link android.widget.SimpleCursorAdapter SimpleCursorAdapter} 用于代表查询结果的游标。
* </p>
* <p>
* 接下来的代码定制的 ListActivity,演示从联系人提供器中查询所有联系人,使用两行布局将 Name
* 和 Company 字段绑定到活动的 ListView 上。
* </p>
*
* <pre>
* public class MyListAdapter extends ListActivity {
*
* @Override
* protected void onCreate(Bundle savedInstanceState){
* super.onCreate(savedInstanceState);
*
* // We'll define a custom screen layout here (the one shown above), but
* // typically, you could just use the standard ListActivity layout.
* setContentView(R.layout.custom_list_activity_view);
*
* // Query for all people contacts using the {@link android.provider.Contacts.People} convenience class.
* // Put a managed wrapper around the retrieved cursor so we don't have to worry about
* // requerying or closing it as the activity changes state.
* mCursor = this.getContentResolver().query(People.CONTENT_URI, null, null, null, null);
* startManagingCursor(mCursor);
*
* // Now create a new list adapter bound to the cursor.
* // SimpleListAdapter is designed for binding to a Cursor.
* ListAdapter adapter = new SimpleCursorAdapter(
* this, // Context.
* android.R.layout.two_line_list_item, // Specify the row template to use (here, two columns bound to the two retrieved cursor
* rows).
* mCursor, // Pass in the cursor to bind to.
* new String[] {People.NAME, People.COMPANY}, // Array of cursor columns to bind to.
* new int[] {android.R.id.text1, android.R.id.text2}); // Parallel array of which template objects to bind to those columns.
*
* // Bind to our new adapter.
* setListAdapter(adapter);
* }
* }
* </pre>
*
* @see #setListAdapter
* @see android.widget.ListView
*/
public class ListActivity extends Activity {
/**
* This field should be made private, so it is hidden from the SDK.
* {@hide}
*/
protected ListAdapter mAdapter;
/**
* This field should be made private, so it is hidden from the SDK.
* {@hide}
*/
protected ListView mList;
private Handler mHandler = new Handler();
private boolean mFinishedStart = false;
private Runnable mRequestFocus = new Runnable() {
public void run() {
mList.focusableViewAvailable(mList);
}
};
/**
* 该方法在选中一个列表项时调用。 子类应该覆盖该方法。 子类要访问关联到选择条目的数据时,
* 可以调用 getListView().getItemAtPosition(position)。
*
* @param l 发生点击的 ListView
* @param v 发生点击的 ListView 中的视图
* @param position 视图在列表中的位置
* @param id 点击条目的数据行 ID
*/
protected void onListItemClick(ListView l, View v, int position, long id) {
}
/**
* 取保列表视图在活动恢复所有视图状态之前已经创建。
*
*@see Activity#onRestoreInstanceState(Bundle)
*/
@Override
protected void onRestoreInstanceState(Bundle state) {
ensureList();
super.onRestoreInstanceState(state);
}
/**
* @see Activity#onDestroy()
*/
@Override
protected void onDestroy() {
mHandler.removeCallbacks(mRequestFocus);
super.onDestroy();
}
/**
* 内容变更时更新屏幕状态(当前列表和其他视图)。
*
* @see Activity#onContentChanged()
*/
@Override
public void onContentChanged() {
super.onContentChanged();
View emptyView = findViewById(com.android.internal.R.id.empty);
mList = (ListView)findViewById(com.android.internal.R.id.list);
if (mList == null) {
throw new RuntimeException(
"Your content must have a ListView whose id attribute is " +
"'android.R.id.list'");
}
if (emptyView != null) {
mList.setEmptyView(emptyView);
}
mList.setOnItemClickListener(mOnClickListener);
if (mFinishedStart) {
setListAdapter(mAdapter);
}
mHandler.post(mRequestFocus);
mFinishedStart = true;
}
/**
* 为列表视图设置 ListAdapter。
*/
public void setListAdapter(ListAdapter adapter) {
synchronized (this) {
ensureList();
mAdapter = adapter;
mList.setAdapter(adapter);
}
}
/**
* 设置指定位置的适配器数据为当前选中列表项。
*
* @param position
*/
public void setSelection(int position) {
mList.setSelection(position);
}
/**
* 获取当前选中列表项的位置。
*/
public int getSelectedItemPosition() {
return mList.getSelectedItemPosition();
}
/**
* 获取当前选中列表项的游标行 ID。
*/
public long getSelectedItemId() {
return mList.getSelectedItemId();
}
/**
* 获取活动的 ListView 小部件。
*/
public ListView getListView() {
ensureList();
return mList;
}
/**
* 获取关联到该活动的 ListView 的 ListAdapter。
*/
public ListAdapter getListAdapter() {
return mAdapter;
}
private void ensureList() {
if (mList != null) {
return;
}
setContentView(com.android.internal.R.layout.list_content_simple);
}
private AdapterView.OnItemClickListener mOnClickListener = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id)
{
onListItemClick((ListView)parent, v, position, id);
}
};
}