第一次写博客。。写的太渣请见谅。可以直接下代码~~
这段时间的项目中用到了这么一个类似的功能,主要用来选择城市。
刚好现在有空,所以提取整理出了代码。
当时在网上找了大概3-4个类似demo,但都功能不完整。所以决定参照那些demo自己写一个。
Iterator iterator=alphaChars.iterator();
while (iterator.hasNext()) {
AlphaChar ac= iterator.next();
if (ac.c==section &&iterator.hasNext()) {
ac=iterator.next();
return ac.index;
}
}
return -1;
public class PinnedHeaderListView extends ListView implements OnScrollListener{
private static final String TAG = "";
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;
private static final int MAX_ALPHA = 255;
private CityAdapter 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);
if (isInEditMode()) {
return;
}
}
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();
this.setOnScrollListener(this);
}
public void setAdapter(CityAdapter adapter) {
super.setAdapter(adapter);
mAdapter=adapter;
}
/**
* 根据state状态 修改headView 的动作
* @param position
*/
public void configureHeaderView(int position) {
if (mHeaderView == null) {
return;
}
int state = getPinnedHeaderState(position);
switch (state) {
case PINNED_HEADER_GONE: {
mHeaderViewVisible = false;
break;
}
case PINNED_HEADER_VISIBLE: {
configurePinnedHeader(position);
if (mHeaderView.getTop() != 0) {
mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);
}
mHeaderViewVisible = true;
break;
}
case PINNED_HEADER_PUSHED_UP: {
View firstView = getChildAt(0);
if(firstView != null){
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;
}
configurePinnedHeader(position);
if (mHeaderView.getTop() != y) {
mHeaderView.layout(0, y, mHeaderViewWidth, mHeaderViewHeight
+ y);
}
mHeaderViewVisible = true;
}else{
Log.w(TAG, "firstView ==null");
}
break;
}
}
}
/**
* 判断当前是该隐藏还是悬浮 还是被推动上移
* @param position
* @return
*/
public int getPinnedHeaderState(int position) {
int realPosition = position;
if (realPosition < 0) {
return PINNED_HEADER_GONE;
}
int section = mAdapter.getSectionForPosition(realPosition);
int nextSectionPosition = mAdapter.getNextPositionForSection(section);
if (nextSectionPosition != -1
&& realPosition == nextSectionPosition - 1) {
return PINNED_HEADER_PUSHED_UP;
}
return PINNED_HEADER_VISIBLE;
}
/**
* 设置head的文字
* @param position
*/
private void configurePinnedHeader(int position){
char title=(char) mAdapter.getSectionForPosition(position);
String text=String.valueOf(title);
((TextView)mHeaderView.findViewById(R.id.query_ticket_header_text)).setText(text);
}
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (mHeaderViewVisible) {
drawChild(canvas, mHeaderView, getDrawingTime());
}
}
@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
configureHeaderView(firstVisibleItem);
}
}
CityAdapter 实现了SectionIndexer接口。代码里注释还好,就不多说其他的了,直接贴代码
public class CityAdapter extends BaseAdapter implements SectionIndexer{
private static final String TAG = "TicketCityAdapter";
private List list;
private LayoutInflater inflater;
private List alphaChars;
public CityAdapter(Context context, List list,List alphaChars) {
// TODO Auto-generated constructor stub
inflater = LayoutInflater.from(context);
this.list = list;
this.alphaChars=alphaChars;
}
public void updateListView(List list,List alphaChars) {
this.list = list;
this.alphaChars=alphaChars;
notifyDataSetChanged();
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return list.size();
}
@Override
public TicketCity getItem(int position) {
// TODO Auto-generated method stub
return list.get(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);
Holder holder = null;
if (convertView == null) {
convertView = inflater.inflate(R.layout.query_ticket_item, null);
holder = new Holder();
holder.mHeaderParent=(LinearLayout)convertView.findViewById(R.id.query_ticket_item_parent);
holder.mHeaderText=(TextView)convertView.findViewById(R.id.query_ticket_item_header_text);
holder.textView=(TextView)convertView.findViewById(R.id.query_ticket_item_text);
convertView.setTag(holder);
} else {
holder = (Holder) convertView.getTag();
}
if (getPositionForSection(section) == position) {
holder.mHeaderParent.setVisibility(View.VISIBLE);
String text=list.get(position).cityShortPinyin.toUpperCase()
.substring(0, 1);
holder.mHeaderText.setText(text);
} else {
holder.mHeaderParent.setVisibility(View.GONE);
}
holder.textView.setText(list.get(position).cityName);
return convertView;
}
/**
* 根据分类的首字母的Char ascii值获取其第一次出现该首字母的位置 section=65 在总list中查开头是65的
*/
@Override
public int getPositionForSection(int section) {
if (section < 0) {
return -1;
}
for (AlphaChar ac : alphaChars) {
if (ac.c==section) {
return ac.index;
}
}
return -1;
}
/**
* 获得下一个首字母的位置
* @param section
* @return
*/
public int getNextPositionForSection(int section) {
if (section < 0 ) {
return -1;
}
Iterator iterator=alphaChars.iterator();
while (iterator.hasNext()) {
AlphaChar ac= iterator.next();
if (ac.c==section &&iterator.hasNext()) {
ac=iterator.next();
return ac.index;
}
}
return -1;
}
/**
* 根据ListView的当前位置获取分类的首字母的Char ascii值
* 例如cityShortPinyin=ags char= A return 65
*/
@Override
public int getSectionForPosition(int position) {
// TODO Auto-generated method stub
if (position >= list.size()) {
return -1;
}
return list.get(position).cityShortPinyin.toUpperCase().charAt(0);
}
@Override
public Object[] getSections() {
// TODO Auto-generated method stub
return null;
}
class Holder {
LinearLayout mHeaderParent;
TextView mHeaderText;
TextView textView;
}
}
public class MainActivity extends Activity {
private static final String TAG = MainActivity.class.getSimpleName();
private static final int HANDLER_MSG_SHOW = 1;
private PinnedHeaderListView mListView;
private CityAdapter mAdapter;
private BladeView mLetter;
private ClearEditText mClearEditText;
private List tcs;
private List alphaChars;
String[] datas;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (PinnedHeaderListView) findViewById(R.id.query_ticket_activity_list);
mLetter = (BladeView) findViewById(R.id.query_ticket_activity_sidrbar);
mClearEditText = (ClearEditText) findViewById(R.id.query_ticket_activity_edit);
init();
}
private void init() {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
// http获取数据等,这里直接读本地的文件了
datas = getResources().getStringArray(R.array.countries);
if (tcs==null) {
tcs=new ArrayList();
}
tcs.clear();
TicketCity tc;
for (int i = 0; i < datas.length; i++) {
tc = new TicketCity();
tc.cityShortPinyin = datas[i];
tc.cityName = datas[i] + "名字" + i;
tc.cityFullPinyin = datas[i] + "全拼" + i;
tcs.add(tc);
}
Collections.sort(tcs);
initSAlphaChar(tcs);
mHandler.sendEmptyMessage(HANDLER_MSG_SHOW);
}
});
thread.start();
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
switch (msg.what) {
case HANDLER_MSG_SHOW:
showView();
break;
default:
break;
}
}
};
protected void showView() {
// TODO Auto-generated method stub
mLetter.setOnItemClickListener(new BladeView.OnItemClickListener() {
@Override
public void onItemClick(String s) {
mListView.setSelection(mAdapter.getPositionForSection(s
.toUpperCase().charAt(0)));
}
});
mClearEditText.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
try {
filterData(s.toString());
} catch (Exception e) {
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
});
mAdapter = new CityAdapter(this, tcs, alphaChars);
mListView.setAdapter(mAdapter);
mListView.setPinnedHeaderView(LayoutInflater.from(this).inflate(
R.layout.query_ticket_header, mListView, false));
mListView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view,
int position, long id) {
// TODO Auto-generated method stub
String py= mAdapter.getItem(position).cityShortPinyin;
Toast.makeText(MainActivity.this, py, Toast.LENGTH_LONG).show();;
}
});
}
/**
* 根据输入框中的值来过滤数据并更新ListView
*
* @param filterStr
*/
private void filterData(String filterStr) {
List filterDateList = new ArrayList();
if (TextUtils.isEmpty(filterStr)) {
filterDateList = tcs;
} else {
filterDateList.clear();
for (TicketCity tc : tcs) {
// 简拼 全屏 汉字都匹配
if (tc.cityShortPinyin.toUpperCase().indexOf(
filterStr.toUpperCase()) >= 0
|| tc.cityName.indexOf(filterStr) >= 0
|| tc.cityFullPinyin.toUpperCase().indexOf(
filterStr.toUpperCase()) >= 0) {
filterDateList.add(tc);
}
}
}
// 根据a-z进行排序
Collections.sort(filterDateList);
initSAlphaChar(filterDateList);
mAdapter.updateListView(filterDateList, alphaChars);
}
/**
* 初始化起始城市首字母列表
*
* @param list
*/
private void initSAlphaChar(List list) {
if (alphaChars == null) {
alphaChars = new ArrayList();
}
alphaChars.clear();
char c;
char oldc = 0;
for (int i = 0; i < list.size(); i++) {
c = list.get(i).cityShortPinyin.toUpperCase().charAt(0);
if (c != oldc) {
AlphaChar ac = new AlphaChar();
ac.c = c;
ac.index = i;
alphaChars.add(ac);
}
oldc = c;
}
}
}
public class TicketCity implements Comparable{
/**
* 城市名称
*/
public String cityName;
/**
* 城市拼音全拼
*/
public String cityFullPinyin;
/**
* 城市拼音简拼
*/
public String cityShortPinyin;
Comparator cmp = Collator.getInstance(java.util.Locale.CHINA);
@Override
public int compareTo(TicketCity another) {
// TODO Auto-generated method stub
return cmp.compare(this.cityShortPinyin, another.cityShortPinyin);
}
}
主界面布局: