当前位置:  编程技术>移动开发

Android之联系人PinnedHeaderListView使用介绍

    来源: 互联网  发布时间:2014-10-18

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

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

public class PinnedHeaderListView extends ListView {
public interface PinnedHeaderAdapter {
public static final int PINNED_HEADER_GONE = 0;
public static final int PINNED_HEADER_VISIBLE = 1;
public static final int PINNED_HEADER_PUSHED_UP = 2;
int getPinnedHeaderState(int position);
void configurePinnedHeader(View header, int position, int alpha);
}
private static final int MAX_ALPHA = 255;
private PinnedHeaderAdapter mAdapter;
private View mHeaderView;
private boolean mHeaderViewVisible;
private int mHeaderViewWidth;
private int mHeaderViewHeight;
public PinnedHeaderListView(Context context) {
super(context);
}
public PinnedHeaderListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PinnedHeaderListView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (mHeaderView != null) {
mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);
configureHeaderView(getFirstVisiblePosition());
}
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mHeaderView != null) {
measureChild(mHeaderView, widthMeasureSpec, heightMeasureSpec);
mHeaderViewWidth = mHeaderView.getMeasuredWidth();
mHeaderViewHeight = mHeaderView.getMeasuredHeight();
}
}
public void setPinnedHeaderView(View view) {
mHeaderView = view;
if (mHeaderView != null) {
setFadingEdgeLength(0);
}
requestLayout();
}
public void setAdapter(ListAdapter adapter) {
super.setAdapter(adapter);
mAdapter = (PinnedHeaderAdapter)adapter;
}
public void configureHeaderView(int position) {
if (mHeaderView == null) {
return;
}
int state = mAdapter.getPinnedHeaderState(position);
switch (state) {
case PinnedHeaderAdapter.PINNED_HEADER_GONE: {
mHeaderViewVisible = false;
break;
}
case PinnedHeaderAdapter.PINNED_HEADER_VISIBLE: {
mAdapter.configurePinnedHeader(mHeaderView, position, MAX_ALPHA);
if (mHeaderView.getTop() != 0) {
mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);
}
mHeaderViewVisible = true;
break;
}
case PinnedHeaderAdapter.PINNED_HEADER_PUSHED_UP: {
View firstView = getChildAt(0);
int bottom = firstView.getBottom();
int headerHeight = mHeaderView.getHeight();
int y;
int alpha;
if (bottom < headerHeight) {
y = (bottom - headerHeight);
alpha = MAX_ALPHA * (headerHeight + y) / headerHeight;
} else {
y = 0;
alpha = MAX_ALPHA;
}
mAdapter.configurePinnedHeader(mHeaderView, position, alpha);
if (mHeaderView.getTop() != y) {
mHeaderView.layout(0, y, mHeaderViewWidth, mHeaderViewHeight
+ y);
}
mHeaderViewVisible = true;
break;
}
}
}
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (mHeaderViewVisible) {
drawChild(canvas, mHeaderView, getDrawingTime());
}
}
}

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

public class BladeView extends View {
private OnItemClickListener mOnItemClickListener;
String[] b = { "#", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K",
"L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X",
"Y", "Z" };
int choose = -1;
Paint paint = new Paint();
boolean showBkg = false;
private PopupWindow mPopupWindow;
private TextView mPopupText;
private Handler handler = new Handler();
public BladeView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public BladeView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BladeView(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (showBkg) {
canvas.drawColor(Color.parseColor("#00000000"));
}
int height = getHeight();
int width = getWidth();
int singleHeight = height / b.length;
for (int i = 0; i < b.length; i++) {
paint.setColor(Color.BLACK);
paint.setTypeface(Typeface.DEFAULT_BOLD);
paint.setFakeBoldText(true);
paint.setAntiAlias(true);
if (i == choose) {
paint.setColor(Color.parseColor("#3399ff"));
}
float xPos = width / 2 - paint.measureText(b[i]) / 2;
float yPos = singleHeight * i + singleHeight;
canvas.drawText(b[i], xPos, yPos, paint);
paint.reset();
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
final int action = event.getAction();
final float y = event.getY();
final int oldChoose = choose;
final int c = (int) (y / getHeight() * b.length);
switch (action) {
case MotionEvent.ACTION_DOWN:
showBkg = true;
if (oldChoose != c) {
if (c > 0 && c < b.length) {
performItemClicked(c);
choose = c;
invalidate();
}
}
break;
case MotionEvent.ACTION_MOVE:
if (oldChoose != c) {
if (c > 0 && c < b.length) {
performItemClicked(c);
choose = c;
invalidate();
}
}
break;
case MotionEvent.ACTION_UP:
showBkg = false;
choose = -1;
dismissPopup();
invalidate();
break;
}
return true;
}
private void showPopup(int item) {
if (mPopupWindow == null) {
handler.removeCallbacks(dismissRunnable);
mPopupText = new TextView(getContext());
mPopupText.setBackgroundColor(Color.GRAY);
mPopupText.setTextColor(Color.CYAN);
mPopupText.setTextSize(50);
mPopupText.setGravity(Gravity.CENTER_HORIZONTAL
| Gravity.CENTER_VERTICAL);
mPopupWindow = new PopupWindow(mPopupText, 100, 100);
}
String text = "";
if (item == 0) {
text = "#";
} else {
text = Character.toString((char) ('A' + item - 1));
}
mPopupText.setText(text);
if (mPopupWindow.isShowing()) {
mPopupWindow.update();
} else {
mPopupWindow.showAtLocation(getRootView(),
Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL, 0, 0);
}
}
private void dismissPopup() {
handler.postDelayed(dismissRunnable, 800);
}
Runnable dismissRunnable = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
if (mPopupWindow != null) {
mPopupWindow.dismiss();
}
}
};
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
public void setOnItemClickListener(OnItemClickListener listener) {
mOnItemClickListener = listener;
}
private void performItemClicked(int item) {
if (mOnItemClickListener != null) {
mOnItemClickListener.onItemClick(b[item]);
showPopup(item);
}
}
public interface OnItemClickListener {
void onItemClick(String s);
}
}

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






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

public class FriendsAdapter extends BaseAdapter implements SectionIndexer,
PinnedHeaderAdapter, OnScrollListener {
private int mLocationPosition = -1;
private String[] mDatas;
// 首字母集
private List mFriendsSections;
private List mFriendsPositions;
private LayoutInflater inflater;
public FriendsAdapter(Context context,String[] datas, List friendsSections,
List friendsPositions) {
// TODO Auto-generated constructor stub
inflater = LayoutInflater.from(context);
mDatas = datas;
mFriendsSections = friendsSections;
mFriendsPositions = friendsPositions;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return mDatas.length;
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return mDatas[position];
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
int section = getSectionForPosition(position);
if (convertView == null) {
convertView = inflater.inflate(R.layout.listview_item, null);
}
LinearLayout mHeaderParent = (LinearLayout) convertView
.findViewById(R.id.friends_item_header_parent);
TextView mHeaderText = (TextView) convertView
.findViewById(R.id.friends_item_header_text);
if (getPositionForSection(section) == position) {
mHeaderParent.setVisibility(View.VISIBLE);
mHeaderText.setText(mFriendsSections.get(section));
} else {
mHeaderParent.setVisibility(View.GONE);
}
TextView textView = (TextView) convertView
.findViewById(R.id.friends_item);
textView.setText(mDatas[position]);
return convertView;
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// TODO Auto-generated method stub
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// TODO Auto-generated method stub
if (view instanceof PinnedHeaderListView) {
((PinnedHeaderListView) view).configureHeaderView(firstVisibleItem);
}
}
@Override
public int getPinnedHeaderState(int position) {
int realPosition = position;
if (realPosition < 0
|| (mLocationPosition != -1 && mLocationPosition == realPosition)) {
return PINNED_HEADER_GONE;
}
mLocationPosition = -1;
int section = getSectionForPosition(realPosition);
int nextSectionPosition = getPositionForSection(section + 1);
if (nextSectionPosition != -1
&& realPosition == nextSectionPosition - 1) {
return PINNED_HEADER_PUSHED_UP;
}
return PINNED_HEADER_VISIBLE;
}
@Override
public void configurePinnedHeader(View header, int position, int alpha) {
// TODO Auto-generated method stub
int realPosition = position;
int section = getSectionForPosition(realPosition);
String title = (String) getSections()[section];
((TextView) header.findViewById(R.id.friends_list_header_text))
.setText(title);
}
@Override
public Object[] getSections() {
// TODO Auto-generated method stub
return mFriendsSections.toArray();
}
@Override
public int getPositionForSection(int section) {
if (section < 0 || section >= mFriendsSections.size()) {
return -1;
}
return mFriendsPositions.get(section);
}
@Override
public int getSectionForPosition(int position) {
// TODO Auto-generated method stub
if (position < 0 || position >= getCount()) {
return -1;
}
int index = Arrays.binarySearch(mFriendsPositions.toArray(), position);
return index >= 0 ? index : -index - 2;
}
}

最后就是MainActivity中的处理了:
代码如下:

public class MainActivity extends Activity {
private static final String FORMAT = "^[a-z,A-Z].*$";
private PinnedHeaderListView mListView;
private BladeView mLetter;
private FriendsAdapter mAdapter;
private String[] datas;
// 首字母集
private List mSections;
// 根据首字母存放数据
private Map mMap;
// 首字母位置集
private List mPositions;
// 首字母对应的位置
private Map mIndexer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initView();
}
private void initData() {
datas = getResources().getStringArray(R.array.countries);
mSections = new ArrayList();
mMap = new HashMap();
mPositions = new ArrayList();
mIndexer = new HashMap();
for (int i = 0; i < datas.length; i++) {
String firstName = datas[i].substring(0, 1);
if (firstName.matches(FORMAT)) {
if (mSections.contains(firstName)) {
mMap.get(firstName).add(datas[i]);
} else {
mSections.add(firstName);
List list = new ArrayList();
list.add(datas[i]);
mMap.put(firstName, list);
}
} else {
if (mSections.contains("#")) {
mMap.get("#").add(datas[i]);
} else {
mSections.add("#");
List list = new ArrayList();
list.add(datas[i]);
mMap.put("#", list);
}
}
}
Collections.sort(mSections);
int position = 0;
for (int i = 0; i < mSections.size(); i++) {
mIndexer.put(mSections.get(i), position);// 存入map中,key为首字母字符串,value为首字母在listview中位置
mPositions.add(position);// 首字母在listview中位置,存入list中
position += mMap.get(mSections.get(i)).size();// 计算下一个首字母在listview的位置
}
}
private void initView() {
// TODO Auto-generated method stub
mListView = (PinnedHeaderListView) findViewById(R.id.friends_display);
mLetter = (BladeView) findViewById(R.id.friends_myletterlistview);
mLetter.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(String s) {
if (mIndexer.get(s) != null) {
mListView.setSelection(mIndexer.get(s));
}
}
});
mAdapter = new FriendsAdapter(this, datas, mSections, mPositions);
mListView.setAdapter(mAdapter);
mListView.setOnScrollListener(mAdapter);
mListView.setPinnedHeaderView(LayoutInflater.from(this).inflate(
R.layout.listview_head, mListView, false));
}
}

还有一个数据arrays.xml,我就不贴出来了,有兴趣的朋友可以下载源码

    
 
 
 
本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • 申请Android Map 的API Key(v2)的最新申请方式(SHA1密钥)
  • Android瀑布流实例 android_waterfall
  • Android开发需要的几点注意事项总结
  • Android系统自带样式 (android:theme)
  • android 4.0 托管进程介绍及优先级和回收机制
  • Android网络共享软件 Android Wifi Tether
  • Android访问与手机通讯相关类的介绍
  • Android 图标库 Android GraphView
  • Android及andriod无线网络Wifi开发的几点注意事项
  • 轻量级Android开发工具 Android Tools
  • Android 2.3 下StrictMode介绍
  • Android 开发环境 Android Studio
  • IDEA的Android开发插件 idea-android
  • Android手机事件提醒 Android Notifier
  • XBMC的Android客户端 android-xbmcremote
  • Android小游戏 Android Shapes
  • Android电池监控 Android Battery Dog
  • android开发:“android:WindowTitle”没有对应项no resource
  • Android 上类似IOS 的开关控件。 Android ToggleButton
  • Android 将 android view 的位置设为右下角的解决方法
  • Android 2D游戏引擎 Android Angle


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3