代码解析
IndexBarView.java
该接口的设计目的主要是建立一个自定义View-屏幕左边的检索条。代码的解析如下:
public class IndexBarView extends View {
// index bar margin
//索引条周边留白的宽度
float mIndexbarMargin;
// user touched Y axis coordinate value
//用户触摸索引条的位置
float mSideIndexY;
// flag used in touch events manipulations
//是否正在索引的标志
boolean mIsIndexing = false;
// holds current section position selected by user
int mCurrentSectionPosition = -1;
// array list to store section positions
public ArrayList<Integer> mListSections;
// array list to store listView data
ArrayList<String> mListItems;
// paint object
Paint mIndexPaint;
// context object
Context mContext;
// interface object used as bridge between list view and index bar view for
// filtering list view content on touch event
IIndexBarFilter mIndexBarFilter;
public IndexBarView(Context context) {
super(context);
this.mContext = context;
}
public IndexBarView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
}
public IndexBarView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.mContext = context;
}
public void setData(PinnedHeaderListView listView, ArrayList<String> listItems,ArrayList<Integer> listSections) {
this.mListItems = listItems;
this.mListSections = listSections;
// list view implements mIndexBarFilter interface
mIndexBarFilter = listView;
// set index bar margin from resources
mIndexbarMargin = mContext.getResources().getDimension(R.dimen.index_bar_view_margin);
// index bar item color and text size
mIndexPaint = new Paint();
mIndexPaint.setColor(mContext.getResources().getColor(R.color.color_black));
mIndexPaint.setAntiAlias(true);
mIndexPaint.setTextSize(mContext.getResources().getDimension(R.dimen.index_bar_view_text_size));
}
//重写View的onDraw方法
// draw view content on canvas using paint
@Override
protected void onDraw(Canvas canvas) {
if (mListSections != null && mListSections.size() > 1) {
//索引条每个字母的占据的高度
float sectionHeight = (getMeasuredHeight() - 2 * mIndexbarMargin)/ mListSections.size();
//索引条字母离顶部边框的距离
float paddingTop = (sectionHeight - (mIndexPaint.descent() - mIndexPaint.ascent())) / 2;
for (int i = 0; i < mListSections.size(); i++) {
float paddingLeft = (getMeasuredWidth() - mIndexPaint.measureText(getSectionText(mListSections.get(i)))) / 2;
canvas.drawText(getSectionText(mListSections.get(i)),
paddingLeft,
mIndexbarMargin + (sectionHeight * i) + paddingTop + mIndexPaint.descent(),
mIndexPaint);
}
}
super.onDraw(canvas);
}
public String getSectionText(int sectionPosition) {
return mListItems.get(sectionPosition);
}
boolean contains(float x, float y) {
// Determine if the point is in index bar region, which includes the
// right margin of the bar
return (x >= getLeft() && y >= getTop() && y <= getTop() + getMeasuredHeight());
}
void filterListItem(float sideIndexY) {
mSideIndexY = sideIndexY;
// filter list items and get touched section position with in index bar
mCurrentSectionPosition = (int) (((mSideIndexY) - getTop() - mIndexbarMargin) /
((getMeasuredHeight() - (2 * mIndexbarMargin)) / mListSections.size()));
if (mCurrentSectionPosition >= 0 && mCurrentSectionPosition < mListSections.size()) {
int position = mListSections.get(mCurrentSectionPosition);
String previewText = mListItems.get(position);
mIndexBarFilter.filterList(mSideIndexY, position, previewText);
}
}
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
// If down event occurs inside index bar region, start indexing
if (contains(ev.getX(), ev.getY())) {
// It demonstrates that the motion event started from index
// bar
mIsIndexing = true;
// Determine which section the point is in, and move the
// list to
// that section
filterListItem(ev.getY());
return true;
}
else {
mCurrentSectionPosition = -1;
return false;
}
case MotionEvent.ACTION_MOVE:
if (mIsIndexing) {
// If this event moves inside index bar
if (contains(ev.getX(), ev.getY())) {
// Determine which section the point is in, and move the
// list to that section
filterListItem(ev.getY());
return true;
}
else {
mCurrentSectionPosition = -1;
return false;
}
}
break;
case MotionEvent.ACTION_UP:
if (mIsIndexing) {
mIsIndexing = false;
mCurrentSectionPosition = -1;
}
break;
}
return false;
}
}