Android之联系人PinnedHeaderListView使用

来源:互联网 发布:淘宝咸鱼官方下载 编辑:程序博客网 时间:2024/04/30 22:18

Android联系人中的ListView是做得比较独特的,但是源码写得比较复制,当我们想使用他的时候再从源码中提取,实属不易啊,而且容易出错,这几天,我把他提取出来了,写成一个简单的例子,一是给自己备忘,而是跟大家分享一下,好了,先来看看效果图:

   


首先是封装好的带头部的PinnedHeaderListView:

[java] view plaincopy
  1. public class PinnedHeaderListView extends ListView {  
  2.   
  3.     public interface PinnedHeaderAdapter {  
  4.         public static final int PINNED_HEADER_GONE = 0;  
  5.         public static final int PINNED_HEADER_VISIBLE = 1;  
  6.         public static final int PINNED_HEADER_PUSHED_UP = 2;  
  7.   
  8.         int getPinnedHeaderState(int position);  
  9.   
  10.         void configurePinnedHeader(View header, int position, int alpha);  
  11.     }  
  12.   
  13.     private static final int MAX_ALPHA = 255;  
  14.   
  15.     private PinnedHeaderAdapter mAdapter;  
  16.     private View mHeaderView;  
  17.     private boolean mHeaderViewVisible;  
  18.     private int mHeaderViewWidth;  
  19.     private int mHeaderViewHeight;  
  20.   
  21.     public PinnedHeaderListView(Context context) {  
  22.         super(context);  
  23.     }  
  24.   
  25.     public PinnedHeaderListView(Context context, AttributeSet attrs) {  
  26.         super(context, attrs);  
  27.     }  
  28.   
  29.     public PinnedHeaderListView(Context context, AttributeSet attrs,  
  30.             int defStyle) {  
  31.         super(context, attrs, defStyle);  
  32.     }  
  33.     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {  
  34.         super.onLayout(changed, left, top, right, bottom);  
  35.         if (mHeaderView != null) {  
  36.             mHeaderView.layout(00, mHeaderViewWidth, mHeaderViewHeight);  
  37.             configureHeaderView(getFirstVisiblePosition());  
  38.         }  
  39.     }  
  40.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  41.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  42.         if (mHeaderView != null) {  
  43.             measureChild(mHeaderView, widthMeasureSpec, heightMeasureSpec);  
  44.             mHeaderViewWidth = mHeaderView.getMeasuredWidth();  
  45.             mHeaderViewHeight = mHeaderView.getMeasuredHeight();  
  46.         }  
  47.     }  
  48.     public void setPinnedHeaderView(View view) {  
  49.         mHeaderView = view;  
  50.         if (mHeaderView != null) {  
  51.             setFadingEdgeLength(0);  
  52.         }  
  53.         requestLayout();  
  54.     }  
  55.     public void setAdapter(ListAdapter adapter) {  
  56.         super.setAdapter(adapter);  
  57.         mAdapter = (PinnedHeaderAdapter)adapter;  
  58.     }  
  59.   
  60.     public void configureHeaderView(int position) {  
  61.         if (mHeaderView == null) {  
  62.             return;  
  63.         }  
  64.         int state = mAdapter.getPinnedHeaderState(position);  
  65.         switch (state) {  
  66.         case PinnedHeaderAdapter.PINNED_HEADER_GONE: {  
  67.             mHeaderViewVisible = false;  
  68.             break;  
  69.         }  
  70.   
  71.         case PinnedHeaderAdapter.PINNED_HEADER_VISIBLE: {  
  72.             mAdapter.configurePinnedHeader(mHeaderView, position, MAX_ALPHA);  
  73.             if (mHeaderView.getTop() != 0) {  
  74.                 mHeaderView.layout(00, mHeaderViewWidth, mHeaderViewHeight);  
  75.             }  
  76.             mHeaderViewVisible = true;  
  77.             break;  
  78.         }  
  79.   
  80.         case PinnedHeaderAdapter.PINNED_HEADER_PUSHED_UP: {  
  81.             View firstView = getChildAt(0);  
  82.             int bottom = firstView.getBottom();  
  83.             int headerHeight = mHeaderView.getHeight();  
  84.             int y;  
  85.             int alpha;  
  86.             if (bottom < headerHeight) {  
  87.                 y = (bottom - headerHeight);  
  88.                 alpha = MAX_ALPHA * (headerHeight + y) / headerHeight;  
  89.             } else {  
  90.                 y = 0;  
  91.                 alpha = MAX_ALPHA;  
  92.             }  
  93.             mAdapter.configurePinnedHeader(mHeaderView, position, alpha);  
  94.             if (mHeaderView.getTop() != y) {  
  95.                 mHeaderView.layout(0, y, mHeaderViewWidth, mHeaderViewHeight  
  96.                         + y);  
  97.             }  
  98.             mHeaderViewVisible = true;  
  99.             break;  
  100.         }  
  101.         }  
  102.     }  
  103.   
  104.     protected void dispatchDraw(Canvas canvas) {  
  105.         super.dispatchDraw(canvas);  
  106.         if (mHeaderViewVisible) {  
  107.             drawChild(canvas, mHeaderView, getDrawingTime());  
  108.         }  
  109.     }  
  110. }  


然后是旁边那个快速导航BladeView(刀锋):

[java] view plaincopy
  1. public class BladeView extends View {  
  2.     private OnItemClickListener mOnItemClickListener;  
  3.     String[] b = { "#""A""B""C""D""E""F""G""H""I""J""K",  
  4.             "L""M""N""O""P""Q""R""S""T""U""V""W""X",  
  5.             "Y""Z" };  
  6.     int choose = -1;  
  7.     Paint paint = new Paint();  
  8.     boolean showBkg = false;  
  9.     private PopupWindow mPopupWindow;  
  10.     private TextView mPopupText;  
  11.     private Handler handler = new Handler();  
  12.   
  13.     public BladeView(Context context, AttributeSet attrs, int defStyle) {  
  14.         super(context, attrs, defStyle);  
  15.     }  
  16.   
  17.     public BladeView(Context context, AttributeSet attrs) {  
  18.         super(context, attrs);  
  19.     }  
  20.   
  21.     public BladeView(Context context) {  
  22.         super(context);  
  23.     }  
  24.   
  25.     @Override  
  26.     protected void onDraw(Canvas canvas) {  
  27.         super.onDraw(canvas);  
  28.         if (showBkg) {  
  29.             canvas.drawColor(Color.parseColor("#00000000"));  
  30.         }  
  31.   
  32.         int height = getHeight();  
  33.         int width = getWidth();  
  34.         int singleHeight = height / b.length;  
  35.         for (int i = 0; i < b.length; i++) {  
  36.             paint.setColor(Color.BLACK);  
  37.             paint.setTypeface(Typeface.DEFAULT_BOLD);  
  38.             paint.setFakeBoldText(true);  
  39.             paint.setAntiAlias(true);  
  40.             if (i == choose) {  
  41.                 paint.setColor(Color.parseColor("#3399ff"));  
  42.             }  
  43.             float xPos = width / 2 - paint.measureText(b[i]) / 2;  
  44.             float yPos = singleHeight * i + singleHeight;  
  45.             canvas.drawText(b[i], xPos, yPos, paint);  
  46.             paint.reset();  
  47.         }  
  48.   
  49.     }  
  50.   
  51.     @Override  
  52.     public boolean dispatchTouchEvent(MotionEvent event) {  
  53.         final int action = event.getAction();  
  54.         final float y = event.getY();  
  55.         final int oldChoose = choose;  
  56.         final int c = (int) (y / getHeight() * b.length);  
  57.   
  58.         switch (action) {  
  59.         case MotionEvent.ACTION_DOWN:  
  60.             showBkg = true;  
  61.             if (oldChoose != c) {  
  62.                 if (c > 0 && c < b.length) {  
  63.                     performItemClicked(c);  
  64.                     choose = c;  
  65.                     invalidate();  
  66.                 }  
  67.             }  
  68.   
  69.             break;  
  70.         case MotionEvent.ACTION_MOVE:  
  71.             if (oldChoose != c) {  
  72.                 if (c > 0 && c < b.length) {  
  73.                     performItemClicked(c);  
  74.                     choose = c;  
  75.                     invalidate();  
  76.                 }  
  77.             }  
  78.             break;  
  79.         case MotionEvent.ACTION_UP:  
  80.             showBkg = false;  
  81.             choose = -1;  
  82.             dismissPopup();  
  83.             invalidate();  
  84.             break;  
  85.         }  
  86.         return true;  
  87.     }  
  88.   
  89.     private void showPopup(int item) {  
  90.         if (mPopupWindow == null) {  
  91.             handler.removeCallbacks(dismissRunnable);  
  92.             mPopupText = new TextView(getContext());  
  93.             mPopupText.setBackgroundColor(Color.GRAY);  
  94.             mPopupText.setTextColor(Color.CYAN);  
  95.             mPopupText.setTextSize(50);  
  96.             mPopupText.setGravity(Gravity.CENTER_HORIZONTAL  
  97.                     | Gravity.CENTER_VERTICAL);  
  98.             mPopupWindow = new PopupWindow(mPopupText, 100100);  
  99.         }  
  100.   
  101.         String text = "";  
  102.         if (item == 0) {  
  103.             text = "#";  
  104.         } else {  
  105.             text = Character.toString((char) ('A' + item - 1));  
  106.         }  
  107.         mPopupText.setText(text);  
  108.         if (mPopupWindow.isShowing()) {  
  109.             mPopupWindow.update();  
  110.         } else {  
  111.             mPopupWindow.showAtLocation(getRootView(),  
  112.                     Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL, 00);  
  113.         }  
  114.     }  
  115.   
  116.     private void dismissPopup() {  
  117.         handler.postDelayed(dismissRunnable, 800);  
  118.     }  
  119.   
  120.     Runnable dismissRunnable = new Runnable() {  
  121.   
  122.         @Override  
  123.         public void run() {  
  124.             // TODO Auto-generated method stub  
  125.             if (mPopupWindow != null) {  
  126.                 mPopupWindow.dismiss();  
  127.             }  
  128.         }  
  129.     };  
  130.   
  131.     public boolean onTouchEvent(MotionEvent event) {  
  132.         return super.onTouchEvent(event);  
  133.     }  
  134.   
  135.     public void setOnItemClickListener(OnItemClickListener listener) {  
  136.         mOnItemClickListener = listener;  
  137.     }  
  138.   
  139.     private void performItemClicked(int item) {  
  140.         if (mOnItemClickListener != null) {  
  141.             mOnItemClickListener.onItemClick(b[item]);  
  142.             showPopup(item);  
  143.         }  
  144.     }  
  145.   
  146.     public interface OnItemClickListener {  
  147.         void onItemClick(String s);  
  148.     }  
  149.   
  150. }  



接下来就是使用了,先在布局文件中声明activity_main.xml:

[html] view plaincopy
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     tools:context=".MainActivity" >  
  6.   
  7.     <com.way.view.PinnedHeaderListView  
  8.         android:id="@+id/friends_display"  
  9.         android:layout_width="fill_parent"  
  10.         android:layout_height="fill_parent"  
  11.         android:cacheColorHint="#00000000"  
  12.         android:divider="@null"  
  13.         android:footerDividersEnabled="false"  
  14.         android:headerDividersEnabled="false" />  
  15.   
  16.     <com.way.view.BladeView  
  17.         android:id="@+id/friends_myletterlistview"  
  18.         android:layout_width="30dip"  
  19.         android:layout_height="fill_parent"  
  20.         android:layout_alignParentRight="true"  
  21.         android:background="#00000000" />  
  22.   
  23. </RelativeLayout>  

然后是一个独立Adapter,这次我没有作为内部类放在MainActivity中:

[java] view plaincopy
  1. public class FriendsAdapter extends BaseAdapter implements SectionIndexer,  
  2.         PinnedHeaderAdapter, OnScrollListener {  
  3.     private int mLocationPosition = -1;  
  4.     private String[] mDatas;  
  5.     // 首字母集  
  6.     private List<String> mFriendsSections;  
  7.     private List<Integer> mFriendsPositions;  
  8.     private LayoutInflater inflater;  
  9.   
  10.     public FriendsAdapter(Context context,String[] datas, List<String> friendsSections,  
  11.             List<Integer> friendsPositions) {  
  12.         // TODO Auto-generated constructor stub  
  13.         inflater = LayoutInflater.from(context);  
  14.         mDatas = datas;  
  15.         mFriendsSections = friendsSections;  
  16.         mFriendsPositions = friendsPositions;  
  17.     }  
  18.   
  19.     @Override  
  20.     public int getCount() {  
  21.         // TODO Auto-generated method stub  
  22.         return mDatas.length;  
  23.     }  
  24.   
  25.     @Override  
  26.     public Object getItem(int position) {  
  27.         // TODO Auto-generated method stub  
  28.         return mDatas[position];  
  29.     }  
  30.   
  31.     @Override  
  32.     public long getItemId(int position) {  
  33.         // TODO Auto-generated method stub  
  34.         return position;  
  35.     }  
  36.   
  37.     @Override  
  38.     public View getView(int position, View convertView, ViewGroup parent) {  
  39.         // TODO Auto-generated method stub  
  40.         int section = getSectionForPosition(position);  
  41.         if (convertView == null) {  
  42.             convertView = inflater.inflate(R.layout.listview_item, null);  
  43.         }  
  44.         LinearLayout mHeaderParent = (LinearLayout) convertView  
  45.                 .findViewById(R.id.friends_item_header_parent);  
  46.         TextView mHeaderText = (TextView) convertView  
  47.                 .findViewById(R.id.friends_item_header_text);  
  48.         if (getPositionForSection(section) == position) {  
  49.             mHeaderParent.setVisibility(View.VISIBLE);  
  50.             mHeaderText.setText(mFriendsSections.get(section));  
  51.         } else {  
  52.             mHeaderParent.setVisibility(View.GONE);  
  53.         }  
  54.         TextView textView = (TextView) convertView  
  55.                 .findViewById(R.id.friends_item);  
  56.         textView.setText(mDatas[position]);  
  57.         return convertView;  
  58.     }  
  59.   
  60.     @Override  
  61.     public void onScrollStateChanged(AbsListView view, int scrollState) {  
  62.         // TODO Auto-generated method stub  
  63.   
  64.     }  
  65.   
  66.     @Override  
  67.     public void onScroll(AbsListView view, int firstVisibleItem,  
  68.             int visibleItemCount, int totalItemCount) {  
  69.         // TODO Auto-generated method stub  
  70.         if (view instanceof PinnedHeaderListView) {  
  71.             ((PinnedHeaderListView) view).configureHeaderView(firstVisibleItem);  
  72.         }  
  73.     }  
  74.   
  75.     @Override  
  76.     public int getPinnedHeaderState(int position) {  
  77.         int realPosition = position;  
  78.         if (realPosition < 0  
  79.                 || (mLocationPosition != -1 && mLocationPosition == realPosition)) {  
  80.             return PINNED_HEADER_GONE;  
  81.         }  
  82.         mLocationPosition = -1;  
  83.         int section = getSectionForPosition(realPosition);  
  84.         int nextSectionPosition = getPositionForSection(section + 1);  
  85.         if (nextSectionPosition != -1  
  86.                 && realPosition == nextSectionPosition - 1) {  
  87.             return PINNED_HEADER_PUSHED_UP;  
  88.         }  
  89.         return PINNED_HEADER_VISIBLE;  
  90.     }  
  91.   
  92.     @Override  
  93.     public void configurePinnedHeader(View header, int position, int alpha) {  
  94.         // TODO Auto-generated method stub  
  95.         int realPosition = position;  
  96.         int section = getSectionForPosition(realPosition);  
  97.         String title = (String) getSections()[section];  
  98.         ((TextView) header.findViewById(R.id.friends_list_header_text))  
  99.                 .setText(title);  
  100.     }  
  101.   
  102.     @Override  
  103.     public Object[] getSections() {  
  104.         // TODO Auto-generated method stub  
  105.         return mFriendsSections.toArray();  
  106.     }  
  107.   
  108.     @Override  
  109.     public int getPositionForSection(int section) {  
  110.         if (section < 0 || section >= mFriendsSections.size()) {  
  111.             return -1;  
  112.         }  
  113.         return mFriendsPositions.get(section);  
  114.     }  
  115.   
  116.     @Override  
  117.     public int getSectionForPosition(int position) {  
  118.         // TODO Auto-generated method stub  
  119.         if (position < 0 || position >= getCount()) {  
  120.             return -1;  
  121.         }  
  122.         int index = Arrays.binarySearch(mFriendsPositions.toArray(), position);  
  123.         return index >= 0 ? index : -index - 2;  
  124.     }  
  125.   
  126. }  


最后就是MainActivity中的处理了:

[java] view plaincopy
  1. public class MainActivity extends Activity {  
  2.     private static final String FORMAT = "^[a-z,A-Z].*$";  
  3.     private PinnedHeaderListView mListView;  
  4.     private BladeView mLetter;  
  5.     private FriendsAdapter mAdapter;  
  6.     private String[] datas;  
  7.     // 首字母集  
  8.     private List<String> mSections;  
  9.     // 根据首字母存放数据  
  10.     private Map<String, List<String>> mMap;  
  11.     // 首字母位置集  
  12.     private List<Integer> mPositions;  
  13.     // 首字母对应的位置  
  14.     private Map<String, Integer> mIndexer;  
  15.   
  16.     @Override  
  17.     protected void onCreate(Bundle savedInstanceState) {  
  18.         super.onCreate(savedInstanceState);  
  19.         setContentView(R.layout.activity_main);  
  20.         initData();  
  21.         initView();  
  22.     }  
  23.   
  24.     private void initData() {  
  25.         datas = getResources().getStringArray(R.array.countries);  
  26.         mSections = new ArrayList<String>();  
  27.         mMap = new HashMap<String, List<String>>();  
  28.         mPositions = new ArrayList<Integer>();  
  29.         mIndexer = new HashMap<String, Integer>();  
  30.   
  31.         for (int i = 0; i < datas.length; i++) {  
  32.             String firstName = datas[i].substring(01);  
  33.             if (firstName.matches(FORMAT)) {  
  34.                 if (mSections.contains(firstName)) {  
  35.                     mMap.get(firstName).add(datas[i]);  
  36.                 } else {  
  37.                     mSections.add(firstName);  
  38.                     List<String> list = new ArrayList<String>();  
  39.                     list.add(datas[i]);  
  40.                     mMap.put(firstName, list);  
  41.                 }  
  42.             } else {  
  43.                 if (mSections.contains("#")) {  
  44.                     mMap.get("#").add(datas[i]);  
  45.                 } else {  
  46.                     mSections.add("#");  
  47.                     List<String> list = new ArrayList<String>();  
  48.                     list.add(datas[i]);  
  49.                     mMap.put("#", list);  
  50.                 }  
  51.             }  
  52.         }  
  53.   
  54.         Collections.sort(mSections);  
  55.         int position = 0;  
  56.         for (int i = 0; i < mSections.size(); i++) {  
  57.             mIndexer.put(mSections.get(i), position);// 存入map中,key为首字母字符串,value为首字母在listview中位置  
  58.             mPositions.add(position);// 首字母在listview中位置,存入list中  
  59.             position += mMap.get(mSections.get(i)).size();// 计算下一个首字母在listview的位置  
  60.         }  
  61.     }  
  62.   
  63.     private void initView() {  
  64.         // TODO Auto-generated method stub  
  65.         mListView = (PinnedHeaderListView) findViewById(R.id.friends_display);  
  66.         mLetter = (BladeView) findViewById(R.id.friends_myletterlistview);  
  67.         mLetter.setOnItemClickListener(new OnItemClickListener() {  
  68.   
  69.             @Override  
  70.             public void onItemClick(String s) {  
  71.                 if (mIndexer.get(s) != null) {  
  72.                     mListView.setSelection(mIndexer.get(s));  
  73.                 }  
  74.             }  
  75.         });  
  76.         mAdapter = new FriendsAdapter(this, datas, mSections, mPositions);  
  77.         mListView.setAdapter(mAdapter);  
  78.         mListView.setOnScrollListener(mAdapter);  
  79.         mListView.setPinnedHeaderView(LayoutInflater.from(this).inflate(  
  80.                 R.layout.listview_head, mListView, false));  
  81.     }  
  82.   
  83. }  

还有一个数据arrays.xml,我就不贴出来了,有兴趣的朋友可以下源码看看:http://download.csdn.net/detail/weidi1989/5576125
1 0
原创粉丝点击