前言
此篇文章利用StickyListHeadersListView和自定义view的方式实现所需效果,所以此篇文章的重点有两个方面,一是介绍StickyListHeadersListView的使用,二则为介绍字母检索的实现方式。其实技术含量不是很高,就算是记录一下吧
实现思路
本来字母检索打算用listview展示,但是网上查了一通资料后发现基本上都是使用的自定义view展示,想也对,字母检索会被频繁的刷新,如果用listview的话,感觉太重了。
效果图
实现功能点
1.粘性显示
2.字母栏显示的只是主数据中含有的字母项
3.主数据滑动,字母栏跟着滑到相应的字母
4.点击字母栏定位到主数据的那一字母族的第一个数据
实现步骤
1.使用StickyListHeadersListView呈现基本数据
mListView = (StickyListHeadersListView) findViewById(R.id.id);
mAdapter = new Adapter(this, datas,letterdata);
mListView.setAdapter(mAdapter);
2.ListView的adapter展示
public class Adapter extends BaseAdapter implements StickyListHeadersAdapter {
private List countries;
private LayoutInflater inflater;
private String chars;//字母栏中所有字母的字符串,为了拿到字母的位置
public AreaInfoAdapter(Context context, List countries, List letterdata) {
inflater = LayoutInflater.from(context);
this.countries = countries;
chars = ListToString(letterdata);
}
@Override
public int getCount() {
return countries.size();
}
@Override
public Object getItem(int position) {
return countries.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.layout, parent, false);
...findViewById
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
...对控件的赋值
return convertView;
}
@Override
public View getHeaderView(int position, View convertView, ViewGroup parent) {
HeaderViewHolder holder;
if (convertView == null) {
holder = new HeaderViewHolder();
convertView = inflater.inflate(R.layout.item_layout, parent, false);
...findViewById
convertView.setTag(holder);
} else {
holder = (HeaderViewHolder) convertView.getTag();
}
...对控件的赋值
return convertView;
}
//返回header的唯一标识
@Override
public long getHeaderId(int position) {
//拿到集合中的字母值
String charname = countries.get(position).getChar();
//拿到字母在字母表中的位置
int index = chars.indexOf(charname);
return index;
}
class HeaderViewHolder {
TextView charName;
}
class ViewHolder {
TextView name;
TextView code;
}
//获得集合中字母为letter的一族中第一个数据的position
public int getSelectPosition(String letter) {
for (int i = 0; i < countries.size(); i++) {
if (countries.get(i).getChar().equals(letter)) {
return i;
}
}
return 0;
}
//获得具体位置的字母,以及字母在显示字母表中的位置
public int getSectionForPosition(int position) {
String charname = countries.get(position).getChar();
return chars.indexOf(charname);
}
//将集合转变为字符串
public String ListToString(List list) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < list.size(); i++) {
sb.append(list.get(i));
}
return sb.toString();
}
}
3.自定义字母检索
public class LetterView extends View {
//当前手指滑动到的位置
private int choosedPosition = -1;
//画文字的画笔
private Paint paint;
//右边的所有文字
private List letters;
//让信息滑到指定位置
private UpdateListView updateListView;
//单个字母的高度
private float perTextHeight;
//字母的字体大小
private float letterSize;
//页面正中央的TextView,用来显示手指当前滑动到的位置的文本
//private TextView textViewDialog;
public LetterIndexView(Context context) {
this(context, null);
}
public LetterIndexView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public LetterIndexView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.Letter, defStyleAttr, 0);
//字母的字体大小
letterSize = a.getDimension(R.styleable.Letter_letter_size, DisplayUtils.sp2px(getContext(), 10.0f));
//每个字母的高
perTextHeight = a.getDimension(R.styleable.Letter_letter_height, DisplayUtils.dp2px(getContext(), 24.0f));
a.recycle();
init();
}
public void init() {
paint = new Paint();
paint.setAntiAlias(true);
paint.setTextSize(letterSize);
paint.setTypeface(Typeface.DEFAULT_BOLD);
}
//测量view的大小,让其有多大显示多大
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec); //获取宽的模式
int heightMode = MeasureSpec.getMode(heightMeasureSpec); //获取高的模式
int widthSize = MeasureSpec.getSize(widthMeasureSpec); //获取宽的尺寸
int heightSize = MeasureSpec.getSize(heightMeasureSpec); //获取高的尺寸
int width = 0;
int height;
if (widthMode == MeasureSpec.EXACTLY) {
//如果match_parent或者具体的值,直接赋值
width = widthSize;
}
//高度跟宽度处理方式一样
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else {
float textHeight = perTextHeight;
height = (int) (getPaddingTop() + textHeight *( letters.size()+1) + getPaddingBottom());
}
//保存测量宽度和测量高度
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
for (int i = 0; i < letters.size(); i++) {
if (i == choosedPosition) {
paint.setColor(Color.parseColor("#AD8748"));
} else {
paint.setColor(Color.parseColor("#adadad"));
}
//DisplayUtils.dp2px(getContext(), 3.0f) 这段话的含义是 我为了让字母好点击,手动把字母检索的栏的宽度增加了,所以画的时候就不可以居中画了,增加了一个偏移量
canvas.drawText(letters.get(i), (getWidth() - paint.measureText(letters.get(i))) / 2 + DisplayUtils.dp2px(getContext(), 3.0f), (i + 1) * perTextHeight, paint);
}
}
//根据点击的y值(y的值是根据你自己定义的view的原点为起点的)判断点的是第几项
@Override
public boolean onTouchEvent(MotionEvent event) {
float y = event.getY();
int currentPosition = (int) (y / perTextHeight);
if (currentPosition < 0) {
currentPosition = 0;
}
if (currentPosition >= letters.size()) {
return true;
}
String letter = letters.get(currentPosition);
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
// if (textViewDialog != null) {
// textViewDialog.setVisibility(View.GONE);
// }
break;
default:
// setBackgroundColor(Color.parseColor("#cccccc"));
// if (textViewDialog != null) {
// textViewDialog.setVisibility(View.VISIBLE);
// textViewDialog.setText(letter);
// }
if (updateListView != null) {
updateListView.updateListView(letter);
}
choosedPosition = currentPosition;
break;
}
invalidate();
return true;
}
//主ListView调用重回letterView
public void updateLetterIndexView(int currentChar) {
if (currentChar >= 0 && currentChar < letters.size()) {
choosedPosition = currentChar;
invalidate();
}
}
public void setUpdateListView(UpdateListView mUpdateListView) {
this.updateListView = mUpdateListView;
}
public void setData(List letters) {
this.letters = letters;
}
//控制主ListView数据滑动到指定的位置
public interface UpdateListView {
void updateListView(String letter);
}
}
4.交互
letterList.setUpdateListView(new LetterIndexView.UpdateListView() {
@Override
public void updateListView(String currentChar) {
int positionForSection = mAdapter.getSelectPosition(currentChar);
mListView.setSelection(positionForSection);
}
});
mListView.setOnStickyHeaderChangedListener(new StickyListHeadersListView.OnStickyHeaderChangedListener() {
@Override
public void onStickyHeaderChanged(StickyListHeadersListView l, View header, int itemPosition, long headerId) {
int sectionForPosition = mAdapter.getSectionForPosition(itemPosition);
letterList.updateLetterIndexView(sectionForPosition);
}
});
资料
android自定义View之仿通讯录侧边栏滑动,实现A-Z字母检索
喵印~~~