ListView用法总结
一:Adapter优化
什么是Adapter,可以先看看我的上一篇文章,Android开发——说说Adapter那点事 Adapter与View的连接主要依靠getView这个方法返回我们需要的自定义view。ListView是Android app中一个最最最常用的控件了,所以如何让ListView流畅运行,获取良好的用户体验是非常重要的。对ListView优化就是对Adapter中的getView方法进行优化。09年的Google IO大会给出的优化建议如下:
@Override public View getView(int position, View convertView, ViewGroup parent) { Log.d("MyAdapter", "Position:" + position + "---" + String.valueOf(System.currentTimeMillis())); ViewHolder holder; if (convertView == null) { final LayoutInflater inflater = (LayoutInflater) mContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.list_item_icon_text, null); holder = new ViewHolder(); holder.icon = (ImageView) convertView.findViewById(R.id.icon); holder.text = (TextView) convertView.findViewById(R.id.text); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.icon.setImageResource(R.drawable.icon); holder.text.setText(mData[position]); return convertView; } static class ViewHolder { ImageView icon; TextView text; } 1: @Override public View getView(int position, View convertView, ViewGroup parent) { Log.d("MyAdapter", "Position:" + position + "---" + String.valueOf(System.currentTimeMillis())); final LayoutInflater inflater = (LayoutInflater) mContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); View v = inflater.inflate(R.layout.list_item_icon_text, null); ((ImageView) v.findViewById(R.id.icon)).setImageResource(R.drawable.icon); ((TextView) v.findViewById(R.id.text)).setText(mData[position]); return v; }
<?xml version="1.0" encoding="utf-8"?><RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><RelativeLayoutandroid:id="@+id/listHeader"android:background="@drawable/jbshape"android:layout_alignParentTop="true"android:gravity="center_horizontal"android:layout_width="fill_parent"android:layout_height="wrap_content"><TextViewandroid:text="IdeasAndroid 列表演示"android:textColor="#000000"android:textSize="18dip"android:layout_width="wrap_content"android:layout_height="wrap_content" /></RelativeLayout><RelativeLayoutandroid:id="@+id/listFooter"android:background="@drawable/jbshape"android:gravity="center_horizontal"android:layout_alignParentBottom="true"android:layout_width="fill_parent"android:layout_height="wrap_content"><Buttonandroid:id="@+id/prePage"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="上一页" android:layout_alignParentLeft="true" /><Buttonandroid:layout_width="wrap_content"android:layout_gravity="right"android:layout_height="wrap_content"android:text="下一页"android:layout_toRightOf="@id/prePage" /></RelativeLayout><ListViewandroid:id="@+id/myListView"android:layout_width="fill_parent"android:layout_height="fill_parent"android:layout_below="@id/listHeader"android:layout_above="@id/listFooter" /></RelativeLayout>
<?xml version="1.0" encoding="utf-8"?><shapexmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"><gradientandroid:startColor="#509245"android:centerColor="#3e8532" android:endColor="#509245"android:type="linear"android:angle="90" android:centerX="0.5"android:centerY="0.5" /><paddingandroid:left="7dp"android:top="7dp"android:right="7dp" android:bottom="7dp" /><cornersandroid:radius="4dp" /></shape>

<?xml version="1.0" encoding="utf-8"?><RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"><Buttonandroid:id="@+id/btn_1"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="click_1"android:layout_alignParentLeft="true"android:layout_alignParentBottom="true" /><Buttonandroid:id="@+id/btn_0"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="click_0"android:layout_above="@id/btn_1"android:layout_alignParentLeft="true" /><ListViewandroid:id="@+id/listview"android:layout_width="fill_parent"android:layout_height="fill_parent"android:layout_above="@id/btn_0"android:layout_alignParentLeft="true"android:layout_alignParentTop="true" /></RelativeLayout>

<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="wrap_content"android:background="#555555"android:paddingLeft="10dip"><TextViewandroid:id="@+id/group_list_item_text"android:layout_width="wrap_content"android:layout_height="20dip"android:textColor="#ffffff"android:gravity="center_vertical" /></LinearLayout>
<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="horizontal"android:layout_width="fill_parent"android:layout_height="wrap_content"android:padding="5dip"> <!-- 图片和文字 --> <!-- 随便放了一张图片,稍微美化一下 --><ImageViewandroid:src="@drawable/icon"android:layout_width="wrap_content"android:layout_height="wrap_content" /><TextViewandroid:id="@+id/group_list_item_text"android:layout_width="wrap_content"android:layout_height="fill_parent"android:paddingLeft="5dip"android:gravity="center_vertical" /></LinearLayout>
<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"> <!--简单的列表显示--><ListViewandroid:id="@+id/group_list"android:layout_width="fill_parent"android:layout_height="fill_parent"android:cacheColorHint="#00000000" /></LinearLayout>
package com.magus.list;import java.util.ArrayList;import java.util.List;import android.app.Activity;import android.content.Context;import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.ArrayAdapter;import android.widget.ListView;import android.widget.TextView;public class MainActivity extends Activity {private GroupListAdapter adapter = null;private ListView listView = null;private List<String> list = new ArrayList<String>();private List<String> listTag = new ArrayList<String>();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.group_list_activity);setData();adapter = new GroupListAdapter(this, list, listTag);listView = (ListView) findViewById(R.id.group_list);listView.setAdapter(adapter);}public void setData() {list.add("A");listTag.add("A");for (int i = 0; i < 2; i++) {list.add("阿凡达" + i);}list.add("B");listTag.add("B");for (int i = 0; i < 2; i++) {list.add("比特风暴" + i);}list.add("C");listTag.add("C");for (int i = 0; i < 30; i++) {list.add("查理风云" + i);}}private static class GroupListAdapter extends ArrayAdapter<String> {private List<String> listTag = null;public GroupListAdapter(Context context, List<String> objects,List<String> tags) {super(context, 0, objects);this.listTag = tags;}@Overridepublic boolean isEnabled(int position) {if (listTag.contains(getItem(position))) {return false;}return super.isEnabled(position);}public View getView(int position, View convertView, ViewGroup parent) {View view = convertView;if (listTag.contains(getItem(position))) {view = LayoutInflater.from(getContext()).inflate(R.layout.group_list_item_tag, null);} else {view = LayoutInflater.from(getContext()).inflate(R.layout.group_list_item, null);}//getItem(position) 得到的是list里面String,String str = getItem(position);System.out.println("getItem(position)="+str);TextView textView = (TextView) view.findViewById(R.id.group_list_item_text);textView.setText(getItem(position));return view;}}}
<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><HorizontalScrollViewandroid:id="@+id/HorizontalScrollView01"android:layout_height="fill_parent"android:layout_width="fill_parent"><ListViewandroid:id="@+id/ListView01"android:layout_height="wrap_content"android:layout_width="wrap_content" /></HorizontalScrollView></LinearLayout>
package com.magus.listview; import java.util.List; import android.content.Context; import android.graphics.Color; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; public class TableAdapter extends BaseAdapter { private Context context; private List<TableRow> table; public TableAdapter(Context context, List<TableRow> table) { this.context = context; this.table = table; } @Override public int getCount() { return table.size(); } @Override public long getItemId(int position) { return position; } public TableRow getItem(int position) { return table.get(position); } public View getView(int position, View convertView, ViewGroup parent) { TableRow tableRow = table.get(position); return new TableRowView(this.context, tableRow); } /** * TableRowView 实现表格行的样式 * @author hellogv */ class TableRowView extends LinearLayout { public TableRowView(Context context, TableRow tableRow) { super(context); this.setOrientation(LinearLayout.HORIZONTAL); for (int i = 0; i < tableRow.getSize(); i++) {//逐个格单元添加到行 TableCell tableCell = tableRow.getCellValue(i); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( tableCell.width, tableCell.height);//按照格单元指定的大小设置空间 layoutParams.setMargins(0, 0, 1, 1);//预留空隙制造边框 if (tableCell.type == TableCell.STRING) {//如果格单元是文本内容 TextView textCell = new TextView(context); textCell.setLines(1); textCell.setGravity(Gravity.CENTER); textCell.setBackgroundColor(Color.BLACK);//背景黑色 textCell.setText(String.valueOf(tableCell.value)); addView(textCell, layoutParams); } else if (tableCell.type == TableCell.IMAGE) {//如果格单元是图像内容 ImageView imgCell = new ImageView(context); imgCell.setBackgroundColor(Color.BLACK);//背景黑色 imgCell.setImageResource((Integer) tableCell.value); addView(imgCell, layoutParams); } } this.setBackgroundColor(Color.WHITE);//背景白色,利用空隙来实现边框 } } /** * TableRow 实现表格的行 * @author hellogv */ static public class TableRow { private TableCell[] cell; public TableRow(TableCell[] cell) { this.cell = cell; } public int getSize() { return cell.length; } public TableCell getCellValue(int index) { if (index >= cell.length) return null; return cell[index]; } } /** * TableCell 实现表格的格单元 * @author hellogv */ static public class TableCell { static public final int STRING = 0; static public final int IMAGE = 1; public Object value; public int width; public int height; private int type; public TableCell(Object value, int width, int height, int type) { this.value = value; this.width = width; this.height = height; this.type = type; } } } package com.magus.listview; import java.util.ArrayList; import com.magus.listview.TableAdapter.TableCell;import com.magus.listview.TableAdapter.TableRow;import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import android.widget.LinearLayout.LayoutParams; import android.widget.Toast; /** * @author hellogv */ public class testMyListView extends Activity { /** Called when the activity is first created. */ ListView lv; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); this.setTitle("ListView自适应实现表格---hellogv"); lv = (ListView) this.findViewById(R.id.ListView01); ArrayList<TableRow> table = new ArrayList<TableRow>(); TableCell[] titles = new TableCell[5];// 每行5个单元 int width = this.getWindowManager().getDefaultDisplay().getWidth()/titles.length; // 定义标题 for (int i = 0; i < titles.length; i++) { titles[i] = new TableCell("标题" + String.valueOf(i), width + 8 * i, LayoutParams.FILL_PARENT, TableCell.STRING); } table.add(new TableRow(titles)); // 每行的数据 TableCell[] cells = new TableCell[5];// 每行5个单元 for (int i = 0; i < cells.length - 1; i++) { cells[i] = new TableCell("No." + String.valueOf(i), titles[i].width, LayoutParams.FILL_PARENT, TableCell.STRING); } cells[cells.length - 1] = new TableCell(R.drawable.icon, titles[cells.length - 1].width, LayoutParams.WRAP_CONTENT, TableCell.IMAGE); // 把表格的行添加到表格 for (int i = 0; i < 12; i++) table.add(new TableRow(cells)); TableAdapter tableAdapter = new TableAdapter(this, table); lv.setAdapter(tableAdapter); lv.setOnItemClickListener(new ItemClickEvent()); } class ItemClickEvent implements AdapterView.OnItemClickListener { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { Toast.makeText(testMyListView.this, "选中第"+String.valueOf(arg2)+"行", 500).show(); } } } 

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" ><ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" android:indeterminateOnly="true" /><TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Loading please wait..." /></LinearLayout>
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ListView android:id="@+id/list" android:layout_width="fill_parent" android:layout_height="fill_parent" /></LinearLayout>
package com.ql.app;/* * Copyright (C) 2010 Makas Tzavellas * * 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. */import com.ql.service.AbstractPageableAdapter;import com.ql.service.DataLoaderHandler;import android.app.Activity;import android.content.Context;import android.os.Bundle;import android.view.View;import android.view.ViewGroup;import android.widget.ListView;import android.widget.TextView;/** * Sample Activity that contains the Pageable list view. * @author Makas Tzavellas (makas dot tzavellas at gmail dot com) * */public class SampleActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ListView listView = (ListView)findViewById(R.id.list); SampleDataLoaderHandler handler = new SampleDataLoaderHandler(); PageableAdapter adapter = new PageableAdapter(listView, this, R.layout.loading, handler); listView.setAdapter(adapter); // Set the adapter as the on scroll listener. // It is done here just incase the activity or other class needs to listen to onScroll event too. listView.setOnScrollListener(adapter); } /** * Sample Pageable adapter that extends {@link AbstractPageableAdapter} * @author Makas Tzavellas (makas dot tzavellas at gmail dot com) * */ private class PageableAdapter extends AbstractPageableAdapter<String> { public PageableAdapter(ListView listView, Context context, int loadingViewResourceId, DataLoaderHandler<String> handler) { super(listView, context, loadingViewResourceId, handler); } public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = getLayoutInflater().inflate(android.R.layout.simple_list_item_1, parent, false); } //((TextView)convertView).setText(getItem(position).toString()); ((TextView)convertView).setText(getItem(position).toString()+"哈哈无敌小胖胖"); return convertView; } }}package com.ql.app;/* * Copyright (C) 2010 Makas Tzavellas * * 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. */import android.os.AsyncTask;import java.util.ArrayList;import com.ql.service.DataLoaderHandler;import com.ql.service.DataResponseHandler;/** * Sample implementation of the {@link DataLoaderHandler} * @author Makas Tzavellas (makas dot tzavellas at gmail dot com) * */public class SampleDataLoaderHandler implements DataLoaderHandler<String>, DataResponseHandler<SampleDataResult<String>> { private static final int MAX_SIZE_PER_PAGE = 10; private static final int MAX_ITEMS = 51; private boolean mLoading; private ArrayList<String> mValues = new ArrayList<String>(); private DataLoadedCallback<String> mCallback; private int mMaxItems; public int getMaxItems() { return mMaxItems; } public void getNext(DataLoadedCallback<String> callback) { mLoading = true; mCallback = callback; new SampleBackgroundTask(this).execute(mValues.size()); } public void getValues(DataLoadedCallback<String> callback) { if (mValues.isEmpty()) { // No data has been loaded before. // Load the initial data which includes the max size. mLoading = true; mCallback = callback; new SampleFirstBackgroundTask(this).execute(); } else { callback.dataLoaded(mValues); } } public boolean isLoading() { return mLoading; } public void resultAvailable(int status, SampleDataResult<String> result) { mLoading = false; if (mMaxItems == 0) mMaxItems = result.maxItems; mValues.addAll(result.values); mCallback.dataLoaded(result.values); } /** * Sample implementation when loading the data the first time. * @author Makas Tzavellas (makas dot tzavellas at gmail dot com) * */ private static class SampleFirstBackgroundTask extends AsyncTask<Void, Void, SampleDataResult<String>> { private DataResponseHandler<SampleDataResult<String>> mResponseHandler; private SampleFirstBackgroundTask(DataResponseHandler<SampleDataResult<String>> responseHandler) { mResponseHandler = responseHandler; } @Override protected SampleDataResult<String> doInBackground(Void... params) { // Put whatever info ArrayList<String> values = new ArrayList<String>(MAX_SIZE_PER_PAGE); for (int i = 0; i < MAX_SIZE_PER_PAGE; i++) { values.add("" + i); } SampleDataResult<String> result = new SampleDataResult<String>(); // Since this is loaded the first time, the max item should be made available. result.maxItems = MAX_ITEMS; result.values = values; try { // Pause for 5 seconds to simulate "busy" state. Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } return result; } @Override protected void onPostExecute(SampleDataResult<String> result) { mResponseHandler.resultAvailable(0, result); } } /** * Sample implementation that "downloads" more data. * @author Makas Tzavellas (makas dot tzavellas at gmail dot com) * */ private class SampleBackgroundTask extends AsyncTask<Integer, Void, SampleDataResult<String>> { private DataResponseHandler<SampleDataResult<String>> mResponseHandler; private SampleBackgroundTask(DataResponseHandler<SampleDataResult<String>> responseHandler) { mResponseHandler = responseHandler; } @Override protected SampleDataResult<String> doInBackground(Integer... params) { int currentSize = params[0]; ArrayList<String> values = new ArrayList<String>(MAX_SIZE_PER_PAGE); int maxSize = currentSize + MAX_SIZE_PER_PAGE; if (maxSize > MAX_ITEMS) maxSize = MAX_ITEMS; for (int i = currentSize; i < maxSize; i++) { values.add("" + i); } SampleDataResult<String> result = new SampleDataResult<String>(); result.values = values; try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } return result; } @Override protected void onPostExecute(SampleDataResult<String> result) { mResponseHandler.resultAvailable(0, result); } }}package com.ql.app;/* * Copyright (C) 2010 Makas Tzavellas * * 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. */import java.util.ArrayList;/** * Sample class that contains the download info. * @author Makas Tzavellas (makas dot tzavellas at gmail dot com) * * @param <T> */public class SampleDataResult<T> { public int maxItems; public ArrayList<T> values;}package com.ql.service;/* * Copyright (C) 2010 Makas Tzavellas * * 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. */import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.widget.AbsListView;import android.widget.BaseAdapter;import android.widget.ListView;import java.util.ArrayList;import com.ql.service.DataLoaderHandler.DataLoadedCallback;/** * Abstract adapter which will display the "busy" view as footer when a background download occurs. * Also calls the {@link DataLoaderHandler} for its initial values as well as subsequent items as * the user scrolls to the end. * * @author Makas Tzavellas (makas dot tzavellas at gmail dot com) * * @param <T> */public abstract class AbstractPageableAdapter<T> extends BaseAdapter implements AbsListView.OnScrollListener, DataLoadedCallback<T> { private DataLoaderHandler<T> mDataLoaderHandler; private ListView mListView; private View mLoadingView; private Context mContext; private ArrayList<T> mList = new ArrayList<T>(); /** * * @param listView The list view that this adapter will be added to. * @param context The activity context. * @param loadingViewResourceId The layout to use when displaying the "busy" status * @param handler The handler to use when loading more data to the list view. */ public AbstractPageableAdapter(ListView listView, Context context, int loadingViewResourceId, DataLoaderHandler<T> handler) { mContext = context; mDataLoaderHandler = handler; mListView = listView; mLoadingView = LayoutInflater.from(context).inflate(loadingViewResourceId, null); showLoading(true); mDataLoaderHandler.getValues(this); } /** * The {@link Context} passed in the constructor. * @return */ public final Context getContext() { return mContext; } public final int getCount() { return mList.size(); } public Object getItem(int position) { return mList.get(position); } public long getItemId(int position) { return position; } public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // Nothing to do I suppose... } public void onScrollStateChanged(final AbsListView view, final int scrollState) { switch (scrollState) { case SCROLL_STATE_IDLE: { final int maxItems = mDataLoaderHandler.getMaxItems(); final int first = mListView.getFirstVisiblePosition(); final int count = mListView.getChildCount(); final int total = getCount(); if (first + count < total || mDataLoaderHandler.isLoading()) return; if (total < maxItems) { showLoading(true); mDataLoaderHandler.getNext(this); } break; } } } private void showLoading(boolean show) { if (show) mListView.addFooterView(mLoadingView); else mListView.removeFooterView(mLoadingView); } public void dataLoaded(ArrayList<T> values) { ArrayList<T> list = mList; for (T value : values) { list.add(value); } showLoading(false); notifyDataSetChanged(); } }package com.ql.service;/* * Copyright (C) 2010 Makas Tzavellas * * 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. */import java.util.ArrayList;/** * * The implementation of the interface is responsible to load data in the background. * * @author Makas Tzavellas (makas dot tzavellas at gmail dot com) * * @param <T> */public interface DataLoaderHandler<T> { /** * The maximum item that can be loaded. * This method should probably only be called after the initial download has occured. * @return The max item available. */ int getMaxItems(); /** * Returns values that has been loaded or may trigger the download of the first batch. * @param callback The callback to notify when data is available. */ void getValues(DataLoadedCallback<T> callback); /** * Returns the next batch of data. * @param callback The callback to notify when data is available. */ void getNext(DataLoadedCallback<T> callback); /** * True if the implementation is busy loading data in the background. * @return */ boolean isLoading(); /** * The implementation of this interface will be called when the data has been downloaded. * * @author Makas Tzavellas (makas dot tzavellas at gmail dot com) * * @param <T> */ interface DataLoadedCallback<T> { /** * Notifies the implementation that the download has completed with a list of values. * @param values The new values downloaded. */ void dataLoaded(ArrayList<T> values); }}package com.ql.service;/* * Copyright (C) 2010 Makas Tzavellas * * 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. *//** * Default interface to use when receiving a response from server. * * @author Makas Tzavellas (makas dot tzavellas at gmail dot com) * * @param <T> */public interface DataResponseHandler<T> { /** * Notify the implementation that response is available. * @param status The status of the download. Whether it was successful or failed. * @param result The result of the download if any. */ void resultAvailable(int status, T result);}String[] mStrings = { "aaaa", "bbbb", "cccc" };ListView listView = (ListView) findViewById(R.id.list);listView.setAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, mStrings));<ListView android:id="@+id/list" android:layout_width="fill_parent"android:layout_height="wrap_content" android:background="@layout/list_corner_1"android:layout_weight="1.0" />
<?xml version="1.0" encoding="UTF-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle"><gradient android:startColor="#CCCCFF" android:endColor="#99CCFF"android:angle="90" /><corners android:bottomRightRadius="10dp"android:bottomLeftRadius="10dp" android:topLeftRadius="10dp"android:topRightRadius="10dp" /></shape>


<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="wrap_content"><TextViewxmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/city_list_item_city_index"android:layout_width="fill_parent"android:layout_height="wrap_content"android:paddingLeft="14dip"android:paddingRight="14dip"android:gravity="center_vertical"android:background="#FFc0c0c0"android:textColor="#FF545454"android:textSize="18dip" /></LinearLayout>
<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="wrap_content"><TextViewxmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/city_list_item_city"android:layout_width="fill_parent"android:layout_height="44dip"android:paddingLeft="14dip"android:paddingRight="14dip"android:gravity="center_vertical"android:checkMark="?android:attr/listChoiceIndicatorSingle"android:textColor="#FF333333"android:textSize="18dip" /></LinearLayout>
<?xml version="1.0" encoding="utf-8"?><CheckedTextViewxmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/city_list_item"android:layout_width="fill_parent"android:layout_height="44dip"android:paddingLeft="14dip"android:paddingRight="14dip"android:gravity="center_vertical"android:checkMark="?android:attr/listChoiceIndicatorSingle"android:textColor="#FF333333"android:textSize="18dip" />
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@color/white" android:orientation="vertical" android:padding="5dip" > <EditText android:id="@+id/edit_filter" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="@drawable/input" android:hint="@string/str_region_filter" /> <ListView android:id="@+id/list_view" android:layout_width="fill_parent" android:layout_height="wrap_content" android:cacheColorHint="#00000000" android:dividerHeight="1dip" /></LinearLayout>
<?xml version="1.0" encoding="utf-8"?><!--Copyright (C) 2006 The Android Open Source Project Licensed under theApache License, Version 2.0 (the "License"); you may not use this fileexcept in compliance with the License. You may obtain a copy of theLicense at http://www.apache.org/licenses/LICENSE-2.0 Unless requiredby applicable law or agreed to in writing, software distributed underthe License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES ORCONDITIONS OF ANY KIND, either express or implied. See the License forthe specific language governing permissions and limitations under theLicense.--><TextViewxmlns:android="http://schemas.android.com/apk/res/android"android:textSize="50sp"android:textColor="#5B5B5B5B"android:background="@drawable/bg_city_select_list_index"android:minWidth="70dip"android:maxWidth="70dip"android:padding="10dip"android:gravity="center" />
<?xml version="1.0" encoding="utf-8" ?><resources><color name="white">#FFFFFF</color><!--白色 --><color name="twhite">#7FFFFFFF</color><!--白色 --><color name="ivory">#FFFFF0</color><!--象牙色 --><color name="lightyellow">#FFFFE0</color><!--亮黄色 --><color name="yellow">#FFFF00</color><!--黄色 --><color name="snow">#FFFAFA</color><!--雪白色 --><color name="floralwhite">#FFFAF0</color><!--花白色 --><color name="lemonchiffon">#FFFACD</color><!--柠檬绸色 --><color name="cornsilk">#FFF8DC</color><!--米绸色 --><color name="seashell">#FFF5EE</color><!--海贝色 --><color name="lavenderblush">#FFF0F5</color><!--淡紫红 --><color name="papayawhip">#FFEFD5</color><!--番木色 --><color name="blanchedalmond">#FFEBCD</color><!--白杏色 --><color name="mistyrose">#FFE4E1</color><!--浅玫瑰色 --><color name="bisque">#FFE4C4</color><!--桔黄色 --><color name="moccasin">#FFE4B5</color><!--鹿皮色 --><color name="navajowhite">#FFDEAD</color><!--纳瓦白 --><color name="peachpuff">#FFDAB9</color><!--桃色 --><color name="gold">#FFD700</color><!--金色 --><color name="pink">#FFC0CB</color><!--粉红色 --><color name="lightpink">#FFB6C1</color><!--亮粉红色 --><color name="orange">#FFA500</color><!--橙色 --><color name="lightsalmon">#FFA07A</color><!--亮肉色 --><color name="darkorange">#FF8C00</color><!--暗桔黄色 --><color name="coral">#FF7F50</color><!--珊瑚色 --><color name="hotpink">#FF69B4</color><!--热粉红色 --><color name="tomato">#FF6347</color><!--西红柿色 --><color name="orangered">#FF4500</color><!--红橙色 --><color name="deeppink">#FF1493</color><!--深粉红色 --><color name="fuchsia">#FF00FF</color><!--紫红色 --><color name="magenta">#FF00FF</color><!--红紫色 --><color name="red">#FF0000</color><!--红色 --><color name="oldlace">#FDF5E6</color><!--老花色 --><color name="lightgoldenrodyellow">#FAFAD2</color><!--亮金黄色 --><color name="linen">#FAF0E6</color><!--亚麻色 --><color name="antiquewhite">#FAEBD7</color><!--古董白 --><color name="salmon">#FA8072</color><!--鲜肉色 --><color name="ghostwhite">#F8F8FF</color><!--幽灵白 --><color name="mintcream">#F5FFFA</color><!--薄荷色 --><color name="whitesmoke">#F5F5F5</color><!--烟白色 --><color name="beige">#F5F5DC</color><!--米色 --><color name="wheat">#F5DEB3</color><!--浅黄色 --><color name="sandybrown">#F4A460</color><!--沙褐色 --><color name="azure">#F0FFFF</color><!--天蓝色 --><color name="honeydew">#F0FFF0</color><!--蜜色 --><color name="aliceblue">#F0F8FF</color><!--艾利斯兰 --><color name="khaki">#F0E68C</color><!--黄褐色 --><color name="lightcoral">#F08080</color><!--亮珊瑚色 --><color name="palegoldenrod">#EEE8AA</color><!--苍麒麟色 --><color name="violet">#EE82EE</color><!--紫罗兰色 --><color name="darksalmon">#E9967A</color><!--暗肉色 --><color name="lavender">#E6E6FA</color><!--淡紫色 --><color name="lightcyan">#E0FFFF</color><!--亮青色 --><color name="burlywood">#DEB887</color><!--实木色 --><color name="plum">#DDA0DD</color><!--洋李色 --><color name="gainsboro">#DCDCDC</color><!--淡灰色 --><color name="crimson">#DC143C</color><!--暗深红色 --><color name="palevioletred">#DB7093</color><!--苍紫罗兰色 --><color name="goldenrod">#DAA520</color><!--金麒麟色 --><color name="orchid">#DA70D6</color><!--淡紫色 --><color name="thistle">#D8BFD8</color><!--蓟色 --><color name="lightgray">#D3D3D3</color><!--亮灰色 --><color name="lightgrey">#D3D3D3</color><!--亮灰色 --><color name="tan">#D2B48C</color><!--茶色 --><color name="chocolate">#D2691E</color><!--巧可力色 --><color name="peru">#CD853F</color><!--秘鲁色 --><color name="indianred">#CD5C5C</color><!--印第安红 --><color name="mediumvioletred">#C71585</color><!--中紫罗兰色 --><color name="silver">#C0C0C0</color><!--银色 --><color name="darkkhaki">#BDB76B</color><!--暗黄褐色 --><color name="rosybrown">#BC8F8F</color><!--褐玫瑰红 --><color name="mediumorchid">#BA55D3</color><!--中粉紫色 --><color name="darkgoldenrod">#B8860B</color><!--暗金黄色 --><color name="firebrick">#B22222</color><!--火砖色 --><color name="powderblue">#B0E0E6</color><!--粉蓝色 --><color name="lightsteelblue">#B0C4DE</color><!--亮钢兰色 --><color name="paleturquoise">#AFEEEE</color><!--苍宝石绿 --><color name="greenyellow">#ADFF2F</color><!--黄绿色 --><color name="lightblue">#ADD8E6</color><!--亮蓝色 --><color name="darkgray">#A9A9A9</color><!--暗灰色 --><color name="darkgrey">#A9A9A9</color><!--暗灰色 --><color name="brown">#A52A2A</color><!--褐色 --><color name="sienna">#A0522D</color><!--赭色 --><color name="darkorchid">#9932CC</color><!--暗紫色 --><color name="palegreen">#98FB98</color><!--苍绿色 --><color name="darkviolet">#9400D3</color><!--暗紫罗兰色 --><color name="mediumpurple">#9370DB</color><!--中紫色 --><color name="lightgreen">#90EE90</color><!--亮绿色 --><color name="darkseagreen">#8FBC8F</color><!--暗海兰色 --><color name="saddlebrown">#8B4513</color><!--重褐色 --><color name="darkmagenta">#8B008B</color><!--暗洋红 --><color name="darkred">#8B0000</color><!--暗红色 --><color name="blueviolet">#8A2BE2</color><!--紫罗兰蓝色 --><color name="lightskyblue">#87CEFA</color><!--亮天蓝色 --><color name="skyblue">#87CEEB</color><!--天蓝色 --><color name="gray">#808080</color><!--灰色 --><color name="olive">#808000</color><!--橄榄色 --><color name="purple">#800080</color><!--紫色 --><color name="maroon">#800000</color><!--粟色 --><color name="aquamarine">#7FFFD4</color><!--碧绿色 --><color name="chartreuse">#7FFF00</color><!--黄绿色 --><color name="lawngreen">#7CFC00</color><!--草绿色 --><color name="mediumslateblue">#7B68EE</color><!--中暗蓝色 --><color name="lightslategray">#778899</color><!--亮蓝灰 --><color name="lightslategrey">#778899</color><!--亮蓝灰 --><color name="slategray">#708090</color><!--灰石色 --><color name="slategrey">#708090</color><!--灰石色 --><color name="olivedrab">#6B8E23</color><!--深绿褐色 --><color name="slateblue">#6A5ACD</color><!--石蓝色 --><color name="dimgray">#696969</color><!--暗灰色 --><color name="dimgrey">#696969</color><!--暗灰色 --><color name="mediumaquamarine">#66CDAA</color><!--中绿色 --><color name="cornflowerblue">#6495ED</color><!--菊兰色 --><color name="cadetblue">#5F9EA0</color><!--军兰色 --><color name="darkolivegreen">#556B2F</color><!--暗橄榄绿 --><color name="indigo">#4B0082</color><!--靛青色 --><color name="mediumturquoise">#48D1CC</color><!--中绿宝石 --><color name="darkslateblue">#483D8B</color><!--暗灰蓝色 --><color name="steelblue">#4682B4</color><!--钢兰色 --><color name="royalblue">#4169E1</color><!--皇家蓝 --><color name="turquoise">#40E0D0</color><!--青绿色 --><color name="mediumseagreen">#3CB371</color><!--中海蓝 --><color name="limegreen">#32CD32</color><!--橙绿色 --><color name="darkslategray">#2F4F4F</color><!--暗瓦灰色 --><color name="darkslategrey">#2F4F4F</color><!--暗瓦灰色 --><color name="seagreen">#2E8B57</color><!--海绿色 --><color name="forestgreen">#228B22</color><!--森林绿 --><color name="lightseagreen">#20B2AA</color><!--亮海蓝色 --><color name="dodgerblue">#1E90FF</color><!--闪兰色 --><color name="midnightblue">#191970</color><!--中灰兰色 --><color name="aqua">#00FFFF</color><!--浅绿色 --><color name="cyan">#00FFFF</color><!--青色 --><color name="springgreen">#00FF7F</color><!--春绿色 --><color name="lime">#00FF00</color><!--酸橙色 --><color name="mediumspringgreen">#00FA9A</color><!--中春绿色 --><color name="darkturquoise">#00CED1</color><!--暗宝石绿 --><color name="deepskyblue">#00BFFF</color><!--深天蓝色 --><color name="darkcyan">#008B8B</color><!--暗青色 --><color name="teal">#008080</color><!--水鸭色 --><color name="green">#008000</color><!--绿色 --><color name="darkgreen">#006400</color><!--暗绿色 --><color name="blue">#0099FF</color><!--蓝色 --><color name="mediumblue">#0000CD</color><!--中兰色 --><color name="darkblue">#00008B</color><!--暗蓝色 --><color name="navy">#000080</color><!--海军色 --><color name="black">#000000</color><!--黑色 --><color name="downloadbar">#525552</color></resources>
<?xml version="1.0" encoding="utf-8"?><resources> <string name="hello">Hello World, EX02_ListviewAlphabeticalIndexActivity!</string> <string name="app_name">EX02_ListviewAlphabeticalIndex</string> <string name="str_region_filter">请输入城市首字母</string></resources>
<?xml version="1.0" encoding="utf-8"?><manifestxmlns:android="http://schemas.android.com/apk/res/android"package="com.magus.listview"android:versionCode="1"android:versionName="1.0"><uses-sdkandroid:minSdkVersion="8" /><applicationandroid:icon="@drawable/icon"android:label="@string/app_name"><activityandroid:configChanges="orientation|keyboardHidden"android:label="@string/app_name"android:name="CitySelectActivity"android:screenOrientation="portrait"android:windowSoftInputMode="stateHidden|adjustUnspecified"><intent-filter><actionandroid:name="android.intent.action.MAIN" /><categoryandroid:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>
package com.magus.listview;import java.util.ArrayList;public class City {private String cityId;private String cityName;private String cityPinyin;private int cityType;public static final int TYPE_CITY_HOT = 0; // 热门城市public static final int TYPE_CITY_NORMAL = 1;// 普通城市City() {}City(String cityid, String ciryname, String citypinyin, int citytype) {cityId = cityid;cityName = ciryname;cityPinyin = citypinyin;cityType = citytype;}City(String ciryname, String citypinyin, int citytype) {cityId = "";cityName = ciryname;cityPinyin = citypinyin;cityType = citytype;}public String getCityId() {return cityId;}public void setCityId(String cityId) {this.cityId = cityId;}public String getCityName() {return cityName;}public void setCityName(String cityName) {this.cityName = cityName;}public String getCityPinyin() {return cityPinyin;}public void setCityPinyin(String cityPinyin) {this.cityPinyin = cityPinyin;}public int getCityType() {return cityType;}public void setCityType(int cityType) {this.cityType = cityType;}public static ArrayList<City> getCityList() {ArrayList<City> cityList = new ArrayList<City>();// 热门城市City mCity;// AmCity = new City("安顺", "AS", TYPE_CITY_NORMAL);cityList.add(mCity);mCity = new City("安徽", "AH", TYPE_CITY_NORMAL);cityList.add(mCity);// BmCity = new City("包头", "BT", TYPE_CITY_NORMAL);cityList.add(mCity);mCity = new City("滨州", "BZ", TYPE_CITY_NORMAL);cityList.add(mCity);// CmCity = new City("长春", "CC", TYPE_CITY_NORMAL);cityList.add(mCity);mCity = new City("常德", "CD", TYPE_CITY_NORMAL);cityList.add(mCity);mCity = new City("从化", "CH", TYPE_CITY_NORMAL);cityList.add(mCity);mCity = new City("重庆", "CQ", TYPE_CITY_NORMAL);cityList.add(mCity);mCity = new City("常熟", "CS", TYPE_CITY_NORMAL);cityList.add(mCity);mCity = new City("常州", "CZ", TYPE_CITY_NORMAL);cityList.add(mCity);mCity = new City("郴州", "CZ", TYPE_CITY_NORMAL);cityList.add(mCity);// DmCity = new City("丹东", "DD", TYPE_CITY_NORMAL);cityList.add(mCity);mCity = new City("大连", "DL", TYPE_CITY_NORMAL);cityList.add(mCity);mCity = new City("大庆", "DQ", TYPE_CITY_NORMAL);cityList.add(mCity);mCity = new City("德州", "DZ", TYPE_CITY_NORMAL);cityList.add(mCity);return cityList;}}package com.magus.listview;import java.util.ArrayList;import java.util.List;public class Utils {/** * 处理城市列表,加入开头字幕索引 * * @author johnson 安顺 北京 ==加工==> A 安顺 B 北京 * **/public static ArrayList<City> rebuildList(List<City> mList) {String cityPinyin = "";String indexPinyin = "0";final ArrayList<City> buildList = new ArrayList<City>();for (City city : mList) {cityPinyin = city.getCityPinyin().substring(0, 1);if (!cityPinyin.equals(indexPinyin)) {indexPinyin = cityPinyin;buildList.add(addCityIndex(indexPinyin));buildList.add(city);} else {buildList.add(city);}}return buildList;}/** * 开头字幕索引 * * @author johnson */public static City addCityIndex(String str) {return new City("-"+ str, str, City.TYPE_CITY_NORMAL);}}package com.magus.listview;import java.util.ArrayList;import android.app.Activity;import android.content.Context;import android.graphics.PixelFormat;import android.os.Bundle;import android.os.Handler;import android.text.Editable;import android.text.TextWatcher;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.view.WindowManager;import android.view.WindowManager.LayoutParams;import android.widget.AbsListView;import android.widget.AdapterView;import android.widget.BaseAdapter;import android.widget.EditText;import android.widget.ListView;import android.widget.TextView;import android.widget.Toast;/** * * 城市选择 activity * * @author Johnson * */public class CitySelectActivity extends Activity implementsListView.OnScrollListener {// 城市选择private ListView listView;private ArrayList<City> listBasicData = new ArrayList<City>();// 存放原始数据;private ArrayList<City> list = new ArrayList<City>();// 存放临时数据private LayoutInflater mInflater;private RemoveWindow mRemoveWindow = new RemoveWindow();private WindowManager mWindowManager;private TextView mDialogText;private boolean mShowing;private boolean mReady;private String mPrevLetter = "";private EditText filterEdit;Handler mHandler = new Handler();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); //原始数据listBasicData = City.getCityList();//初始化显示数据加入字幕索引iteminitShowData();this.setContentView(R.layout.city_select);mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);listView = (ListView) findViewById(R.id.list_view);final myAdapter adapter = new myAdapter();listView.setAdapter(adapter);listView.setItemsCanFocus(false);listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);// 设置单选模型listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view,int position, long id) {Toast.makeText(getApplicationContext(), list.get(position).getCityName(), Toast.LENGTH_SHORT).show();}});filterEdit = (EditText) findViewById(R.id.edit_filter);filterEdit.addTextChangedListener(new TextWatcher() {public void onTextChanged(CharSequence s, int start, int before,int count) {}public void beforeTextChanged(CharSequence s, int start, int count,int after) {}public void afterTextChanged(Editable s) {final String txt = s.toString().toLowerCase();if (list != null) {list.clear();if (listBasicData != null && listBasicData.size() > 0) {for (City mCity : listBasicData) {String pinyin = mCity.getCityPinyin();String name = mCity.getCityName();if (pinyin.startsWith(txt)|| pinyin.startsWith(txt.toLowerCase())|| pinyin.startsWith(txt.toUpperCase())|| (name.indexOf(txt) != -1)) {list.add(mCity);}}if ("".equals(txt)) {//当字母过滤框内容为空重新初始化数据initShowData();}if ("".equals(txt)) {mReady = true;} else {mReady = false;}// List数据变化时, 刷新Dialog// dialog.notifyDataSetChanged();adapter.notifyDataSetChanged();}}}});initIndexTextView();}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {int visibleItemIndex = firstVisibleItem;// int visibleItemIndex = firstVisibleItem + (visibleItemCount / 2 - 1);if (mReady) {City city = (City) list.get(visibleItemIndex);String firstLetter = city.getCityPinyin();System.out.println("@" + firstLetter);if (firstLetter.equals("-")) {firstLetter = firstLetter.substring(1, 2);} else {firstLetter = firstLetter.substring(0, 1);}if (!mShowing && firstLetter.equals(mPrevLetter)) {mShowing = true;mDialogText.setVisibility(View.VISIBLE);}mDialogText.setTextSize(40);mDialogText.setText(firstLetter);mHandler.removeCallbacks(mRemoveWindow);mHandler.postDelayed(mRemoveWindow, 1000);mPrevLetter = firstLetter;}}@Overridepublic void onScrollStateChanged(AbsListView arg0, int arg1) {// TODO Auto-generated method stub}private void removeWindow() {if (mShowing) {mShowing = false;mDialogText.setVisibility(View.INVISIBLE);}}private final class RemoveWindow implements Runnable {public void run() {removeWindow();}}@Overrideprotected void onResume() {super.onResume();mReady = true;}@Overrideprotected void onPause() {super.onPause();removeWindow();mReady = false;}@Overrideprotected void onDestroy() {super.onDestroy();if (mWindowManager != null) {mWindowManager.removeView(mDialogText);}mReady = false;}class myAdapter extends BaseAdapter {View convertView;City city;@Overridepublic boolean isEnabled(int position) {if (city != null) {return !city.getCityName().startsWith("-");} else {return true;}}@Overridepublic int getCount() {// TODO Auto-generated method stubreturn list.size();}@Overridepublic Object getItem(int position) {// TODO Auto-generated method stubreturn list.get(position);}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn position;}@Overridepublic View getView(int position, View convertVie, ViewGroup arg2) {// TODO Auto-generated method stubconvertView = convertVie;TextView tv;city = (City) list.get(position);if (city.getCityName().startsWith("-")) {convertView = mInflater.inflate(R.layout.city_list_item_city_index, null);tv = (TextView) convertView.findViewById(R.id.city_list_item_city_index);tv.setText(city.getCityName().substring(1,city.getCityName().length()));} else {convertView = mInflater.inflate(R.layout.city_list_item_city,null);tv = (TextView) convertView.findViewById(R.id.city_list_item_city);tv.setText(city.getCityName());}return convertView;}}/** * 初始化用于显示的数据 * * @author johnson * * */public void initShowData() {list.clear();list = Utils.rebuildList(listBasicData);}/** * 初始化程序列表索引IndexTextView * * @author johnson * */ public void initIndexTextView() {mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);listView.setOnScrollListener(this);mDialogText = (TextView) mInflater.inflate(R.layout.list_position, null);mDialogText.setVisibility(View.INVISIBLE);mHandler.post(new Runnable() {public void run() {mReady = true;WindowManager.LayoutParams lp = new WindowManager.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT,WindowManager.LayoutParams.TYPE_APPLICATION_STARTING,WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,PixelFormat.TRANSLUCENT);mWindowManager.addView(mDialogText, lp);}});}}
package com.zhou.activity;import android.app.ExpandableListActivity;import android.os.Bundle;import android.view.ContextMenu;import android.view.Gravity;import android.view.MenuItem;import android.view.View;import android.view.ViewGroup;import android.view.ContextMenu.ContextMenuInfo;import android.widget.AbsListView;import android.widget.BaseExpandableListAdapter;import android.widget.ExpandableListAdapter;import android.widget.ExpandableListView;import android.widget.TextView;import android.widget.Toast;import android.widget.ExpandableListView.ExpandableListContextMenuInfo;public class ExpandableList extends ExpandableListActivity {//声明adapterprivate ExpandableListAdapter mAdapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//设这标题setTitle("可扩展的列表");//实例化adaptermAdapter = new MyExpandableListAdapter();//为列表设置adaptersetListAdapter(mAdapter);//为list注册context菜单registerForContextMenu(this.getExpandableListView());}@Overridepublic boolean onChildClick(ExpandableListView parent, View v,int groupPosition, int childPosition, long id) {Toast.makeText(this, " 组元素索引: " + groupPosition + " 子元素索引: " + childPosition, Toast.LENGTH_SHORT).show();return super.onChildClick(parent, v, groupPosition, childPosition, id);}@Overridepublic void onGroupExpand(int groupPosition) {Toast.makeText(this, " 组元素索引: " + groupPosition, Toast.LENGTH_SHORT).show();super.onGroupExpand(groupPosition);}@Overridepublic void onCreateContextMenu(ContextMenu menu, View v,ContextMenuInfo menuInfo) {menu.setHeaderTitle("上下文菜单");menu.add(0, 0, 0, "单击我");}// 单击上下文菜单后的逻辑@Overridepublic boolean onContextItemSelected(MenuItem item) {ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) item.getMenuInfo();String title = ((TextView) info.targetView).getText().toString();int type = ExpandableListView.getPackedPositionType(info.packedPosition);if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {int groupPos = ExpandableListView.getPackedPositionGroup(info.packedPosition);int childPos = ExpandableListView.getPackedPositionChild(info.packedPosition);Toast.makeText(this, title + " 组元素索引: " + groupPos + " 子元素索引: " + childPos, Toast.LENGTH_SHORT).show();return true;} else if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {int groupPos = ExpandableListView.getPackedPositionGroup(info.packedPosition);Toast.makeText(this, title + " 组元素索引: " + groupPos, Toast.LENGTH_SHORT).show();return true;}return false;}//自定义Adapterpublic class MyExpandableListAdapter extends BaseExpandableListAdapter {// 父列表数据private String[] groups = { "吉林省", "辽宁省", "黑龙江省","山东省" };// 子列表数据private String[][] children = {{ "长春市" },{ "沈阳市", "铁岭市" },{ "哈尔滨市", "齐齐哈尔市", "牡丹江市" },{ "济南市", "青岛市", "淄博市", "潍坊市" }};@Overridepublic Object getChild(int groupPosition, int childPosition) {return children[groupPosition][childPosition];}@Overridepublic long getChildId(int groupPosition, int childPosition) {return childPosition;}@Overridepublic int getChildrenCount(int groupPosition) {return children[groupPosition].length;}// 取子列表中的某一项的 View@Overridepublic View getChildView(int groupPosition, int childPosition,boolean isLastChild, View convertView, ViewGroup parent) {TextView textView = getGenericView();textView.setText(getChild(groupPosition, childPosition).toString());return textView;}@Overridepublic Object getGroup(int groupPosition) {return groups[groupPosition];}@Overridepublic int getGroupCount() {return groups.length;}@Overridepublic long getGroupId(int groupPosition) {return groupPosition;}// 取父列表中的某一项的 View@Overridepublic View getGroupView(int groupPosition, boolean isExpanded,View convertView, ViewGroup parent) {TextView textView = getGenericView();textView.setText(getGroup(groupPosition).toString());return textView;}@Overridepublic boolean hasStableIds() {return true;}@Overridepublic boolean isChildSelectable(int groupPosition, int childPosition) {return true;}// 获取某一项的 View 的逻辑private TextView getGenericView() {AbsListView.LayoutParams lp = new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, 48);TextView textView = new TextView(ExpandableList.this);textView.setLayoutParams(lp);textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);textView.setPadding(32, 0, 0, 0);return textView;}}} 感谢分享