Android进阶:实现联系人列表滑动显示提示信息 以及弹出选择菜单

转自http://blog.****.net/wanglong0537/archive/2011/05/12/6414248.aspx

经常看到一些Contact类的软件软件联系人列表在滚动时会在屏幕中间弹出一个提示信息,就是当前位置的联系人序号之类的,尝试实现了一下

先看效果:

Android进阶:实现联系人列表滑动显示提示信息 以及弹出选择菜单Android进阶:实现联系人列表滑动显示提示信息 以及弹出选择菜单

中间弹出的就是一个类似于Overlay的层

布局文件 pop_overlay.xml

<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:textSize="70sp" android:textColor="#99ff00ff" android:background="#99fff34f" android:minWidth="80dip" android:maxWidth="80dip" android:padding="10dip" android:gravity="center" />

在onCreate方法中加载这个View并且通过addView加入到Activity中

//滚动时弹出的提示框 txtOverlay = (TextView) LayoutInflater.from(this).inflate(R.layout.pop_overlay, null); // 默认设置为不可见。 txtOverlay.setVisibility(View.INVISIBLE); WindowManager.LayoutParams lp = new WindowManager.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_APPLICATION, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT); windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); windowManager.addView(txtOverlay, lp);

然后可以通过实现 ListView.OnScrollListener接口来重写 onScroll 和 onScrollStateChanged方法


boolean visible; @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { Log.i("bb", "onScroll"); Log.i("bb", "visible:"+visible); int index = cursor.getColumnIndex("display_name"); if (visible) { cursor.moveToPosition(firstVisibleItem); String firstChar = Pinyin4j.getFirstChar(cursor.getString(index)); txtOverlay.setText(firstChar); txtOverlay.setVisibility(View.VISIBLE); } } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { visible = true; Log.i("bb", "onScrollStateChanged"); //在onScrollStateChanged (AbsListView view, int scrollState) 中,scrollState有三种状态, //分别是开始滚动(SCROLL_STATE_FLING ),正在滚动(SCROLL_STATE_TOUCH_SCROLL ), 已经停止(SCROLL_STATE_IDLE ), if (scrollState == ListView.OnScrollListener.SCROLL_STATE_IDLE) { txtOverlay.setVisibility(View.INVISIBLE); visible = false; } }

这两个方法的调用时机是不同的,可以自己打印看一下

这里显示的是用户中文名的首字母 通过pingyin4j.jar来实现的 可以下载来试下 还可以设置一些参数的

下面是调试代码:

import java.util.HashSet; import java.util.Set; import net.sourceforge.pinyin4j.PinyinHelper; import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType; import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; import net.sourceforge.pinyin4j.format.HanyuPinyinToneType; import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType; import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; public class Pinyin4j { /** * 字符串集合转换字符串(逗号分隔) */ public static String makeStringByStringSet(Set<String> stringSet) { StringBuilder str = new StringBuilder(); int i = 0; for (String s : stringSet) { if (i == stringSet.size() - 1) { str.append(s); } else { str.append(s + ","); } i++; } return str.toString().toLowerCase(); } /** * 获取拼音集合 */ public static Set<String> getPinyin(String src) { if (src != null && !src.trim().equalsIgnoreCase("")) { char[] srcChar; srcChar = src.toCharArray(); // 汉语拼音格式输出类 HanyuPinyinOutputFormat hanYuPinOutputFormat = new HanyuPinyinOutputFormat(); // 输出设置,大小写,音标方式等 hanYuPinOutputFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE); hanYuPinOutputFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE); hanYuPinOutputFormat.setVCharType(HanyuPinyinVCharType.WITH_V); String[][] temp = new String[src.length()][]; for (int i = 0; i < srcChar.length; i++) { char c = srcChar[i]; // 是中文或者a-z或者A-Z转换拼音(我的需求,是保留中文或者a-z或者A-Z) if (String.valueOf(c).matches("[//u4E00-//u9FA5]+")) { try { temp[i] = PinyinHelper.toHanyuPinyinStringArray( srcChar[i], hanYuPinOutputFormat); } catch (BadHanyuPinyinOutputFormatCombination e) { e.printStackTrace(); } } else if (((int) c >= 65 && (int) c <= 90) || ((int) c >= 97 && (int) c <= 122)) { temp[i] = new String[] { String.valueOf(srcChar[i]) }; } else { temp[i] = new String[] { "" }; } } String[] pingyinArray = Exchange(temp); Set<String> pinyinSet = new HashSet<String>(); for (int i = 0; i < pingyinArray.length; i++) { pinyinSet.add(pingyinArray[i]); } return pinyinSet; } return null; } /** * 递归 */ public static String[] Exchange(String[][] strJaggedArray) { String[][] temp = DoExchange(strJaggedArray); return temp[0]; } /** * 递归 */ private static String[][] DoExchange(String[][] strJaggedArray) { int len = strJaggedArray.length; if (len >= 2) { int len1 = strJaggedArray[0].length; int len2 = strJaggedArray[1].length; int newlen = len1 * len2; String[] temp = new String[newlen]; int Index = 0; for (int i = 0; i < len1; i++) { for (int j = 0; j < len2; j++) { temp[Index] = strJaggedArray[0][i] + strJaggedArray[1][j]; Index++; } } String[][] newArray = new String[len - 1][]; for (int i = 2; i < len; i++) { newArray[i - 1] = strJaggedArray[i]; } newArray[0] = temp; return DoExchange(newArray); } else { return strJaggedArray; } } public static String getFirstChar(String str) { return makeStringByStringSet(getPinyin(str)).substring(0, 1); } /** * @param args */ public static void main(String[] args) { String str = "测试"; System.out.println(makeStringByStringSet(getPinyin(str))); } }

下面看弹出菜单的创建

//监听条目单击事件 listView.setOnItemClickListener(new OnItemClickListener(){ @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { TextView tv = (TextView)view.findViewById(R.id.phonename); Toast.makeText(ListViewDemo.this, tv.getText(), Toast.LENGTH_LONG).show(); } }); listView.setOnItemLongClickListener(new OnItemLongClickListener(){ @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { Toast.makeText(ListViewDemo.this, "长按一次", Toast.LENGTH_LONG).show(); return false;//如果返回true 就不会调用下面onCreateContextMenu事件 } }); //长按弹出菜单选项的点击选择事件监听 final OnMenuItemClickListener mOnMenuItemClickListener = new OnMenuItemClickListener(){ @Override public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { case 0: Toast.makeText(ListViewDemo.this, "test1", Toast.LENGTH_LONG).show(); break; case 1: Toast.makeText(ListViewDemo.this, "test2", Toast.LENGTH_LONG).show(); break; case 2: Toast.makeText(ListViewDemo.this, "test3", Toast.LENGTH_LONG).show(); break; case 3: Toast.makeText(ListViewDemo.this, "test4", Toast.LENGTH_LONG).show(); break; } return false; } }; //监听长按事件 长按时弹出选择菜单 listView.setOnCreateContextMenuListener(new OnCreateContextMenuListener(){ @Override public void onCreateContextMenu(ContextMenu menu, View view,ContextMenuInfo arg2) { menu.setHeaderTitle("提示框"); menu.add(0, 0, 0, "test1").setOnMenuItemClickListener(mOnMenuItemClickListener); menu.add(0, 1, 1, "test2").setOnMenuItemClickListener(mOnMenuItemClickListener); menu.add(0, 2, 2, "test3").setOnMenuItemClickListener(mOnMenuItemClickListener); menu.add(0, 3, 3, "test4").setOnMenuItemClickListener(mOnMenuItemClickListener); } });

效果如上图,这里就有ListView种的几个点击事件


首先是单击事件 通过setOnItemClickListener 来监听


长按事件 通过 setOnItemLongClickListener 来监听 如果是长按就可以通过setOnCreateContextMenuListener这个事件来创建弹出菜单,注意如果要通过这种方式创建菜单需要在onItemLongClick方法中返回false

通过setOnCreateContextMenuListener事件来监听弹出菜单的点击事件

总之这里有N多的事件

还有一点看一下ListView的每个条目Item实现点击切换底色的效果

如图

Android进阶:实现联系人列表滑动显示提示信息 以及弹出选择菜单

点击是底色变成如果的颜色


这个可以在Item的布局文件中实现 来看布局文件 listviewdemoitem.xml

<?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" android:background="#ffffff" > <RelativeLayout android:layout_width="wrap_content" android:layout_height="fill_parent" android:background="@drawable/listview_selected" android:padding="6px" > <TextView android:id="@+id/phonename" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textSize="20px" android:textColor="#000000" /> <TextView android:layout_below="@id/phonename" android:id="@+id/phonenumber" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textSize="16px" android:textColor="#000000" /> <ImageView android:layout_alignParentRight="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/menu_city_manager" android:layout_gravity="right" /> </RelativeLayout> </LinearLayout>

外面是一个LinerLayout 作为底色 防止滚动的时候底色变成黑色

里面用一个RelativeLayout实现了布局调整,它的android:background="@drawable/listview_selected" 属性通过一个Selector

来实现焦点 点击等操作时的背景切换

<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" android:drawable="@drawable/list_selector_background_pressed" /> </selector>

这里简单实现了一下,还可以有其他的设置 譬如 android:state_focus等