Android之联系人PinnedHeaderListView使用介绍
Android之联系人PinnedHeaderListView使用介绍
发布时间:2017-01-07 来源:查字典编辑
摘要:Android联系人中的ListView是做得比较独特的,但是源码写得比较复制,当我们想使用他的时候再从源码中提取,实属不易啊,而且容易出错...

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

1

首先是封装好的带头部的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:

复制代码 代码如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

tools:context=".MainActivity" >

<com.way.view.PinnedHeaderListView

android:id="@+id/friends_display"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:cacheColorHint="#00000000"

android:divider="@null"

android:footerDividersEnabled="false"

android:headerDividersEnabled="false" />

<com.way.view.BladeView

android:id="@+id/friends_myletterlistview"

android:layout_width="30dip"

android:layout_height="fill_parent"

android:layout_alignParentRight="true"

android:background="#00000000" />

</RelativeLayout>

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

复制代码 代码如下:

public class FriendsAdapter extends BaseAdapter implements SectionIndexer,

PinnedHeaderAdapter, OnScrollListener {

private int mLocationPosition = -1;

private String[] mDatas;

// 首字母集

private List<String> mFriendsSections;

private List<Integer> mFriendsPositions;

private LayoutInflater inflater;

public FriendsAdapter(Context context,String[] datas, List<String> friendsSections,

List<Integer> 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<String> mSections;

// 根据首字母存放数据

private Map<String, List<String>> mMap;

// 首字母位置集

private List<Integer> mPositions;

// 首字母对应的位置

private Map<String, Integer> 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<String>();

mMap = new HashMap<String, List<String>>();

mPositions = new ArrayList<Integer>();

mIndexer = new HashMap<String, Integer>();

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<String> list = new ArrayList<String>();

list.add(datas[i]);

mMap.put(firstName, list);

}

} else {

if (mSections.contains("#")) {

mMap.get("#").add(datas[i]);

} else {

mSections.add("#");

List<String> list = new ArrayList<String>();

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,我就不贴出来了,有兴趣的朋友可以下载源码

推荐文章
猜你喜欢
附近的人在看
推荐阅读
拓展阅读
相关阅读
网友关注
最新安卓软件开发学习
热门安卓软件开发学习
编程开发子分类