您的位置:首页 > 移动开发 > Android开发

Android自定义类似联系人列表的 快速索引控件

2015-12-14 21:55 483 查看

效果图



思考

将字母 A - Z 画出来

处理字母的触摸事件

提供使用的回调

联系人汉字转成拼音

按拼音排序

分组(同一个拼音开头的为一组)

将自定义的view和ListView绑定

实现

1. 绘制A-Z

准备好A-Z 26个字母

在onDraw方法里面计算每个字母的位置并绘制



private static final String[] LETTERS = new String[]{
"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"};
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制A-Z
for (int i = 0; i < LETTERS.length; i++) {
//            int width = (int) (screenWidth * 1.0 / 2 - paint.measureText(LETTERS[i]) * 1.0 / 2);
Rect rect = new Rect();
paint.getTextBounds(LETTERS[i], 0, 1, rect);
int width = (int) (screenWidth * 1.0 / 2 - rect.width() * 1.0 / 2);
int height = (int) (cellHeight * 1.0 / 2 + rect.height() * 1.0 / 2 + i * cellHeight);
canvas.drawText(LETTERS[i], width, height, paint);
}

}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
screenWidth = getMeasuredWidth();
screenHeight = getMeasuredHeight();
cellHeight = screenHeight * 1.0 / LETTERS.length;
}


2. 处理onTouchEvent事件

int touchIndex = -1;

@Override
public boolean onTouchEvent(MotionEvent event) {
int y;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
y = (int) event.getY();
for (int i = 0; i < LETTERS.length; i++) {
if (y > i * cellHeight && y < (i + 1) * cellHeight) {
if (touchIndex != i) {
Log.e(TAG, LETTERS[i]);
Toast.makeText(getContext(), LETTERS[i], 0).show();
touchIndex = i;
}
break;
}
}
break;

case MotionEvent.ACTION_MOVE:
y = (int) event.getY();
for (int i = 0; i < LETTERS.length; i++) {
if (y > i * cellHeight && y < (i + 1) * cellHeight) {
if (touchIndex != i) {
Log.e(TAG, LETTERS[i]);
Toast.makeText(getContext(), LETTERS[i], 0).show();
touchIndex = i;
}
break;
}
}
break;
case MotionEvent.ACTION_UP:
break;

}
return true;
}


3. 提供回调方法

private OnIndexChangedListener listener;

public void setOnIndexChangedListener(OnIndexChangedListener listener) {
this.listener = listener;
}

public interface OnIndexChangedListener {
void onIndexChanged(String index);
}
//触摸事件的操作通过接口让调用者去实现
@Override
public final boolean onTouchEvent(MotionEvent event) {
int y;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
y = (int) event.getY();
for (int i = 0; i < LETTERS.length; i++) {
if (y > i * cellHeight && y < (i + 1) * cellHeight) {
if (touchIndex != i) {
if (listener != null) {
listener.onIndexChanged(LETTERS[i]);
}
touchIndex = i;
}
break;
}
}
break;

case MotionEvent.ACTION_MOVE:
y = (int) event.getY();
for (int i = 0; i < LETTERS.length; i++) {
if (y > i * cellHeight && y < (i + 1) * cellHeight) {
if (touchIndex != i) {
if (listener != null) {
listener.onIndexChanged(LETTERS[i]);
}
touchIndex = i;
}
break;
}
}
break;
case MotionEvent.ACTION_UP:
break;

}
return true;
}


4. 汉字转拼音

需要添加 pinyin4j-2.5.0.jar

/**
* 描述:汉字转拼音的工具类
* 作者 mjd
* 日期:2015/12/10 12:50
*/
public class PinYinUtils {

public static String getPinYin(String hanZi) {
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
format.setCaseType(HanyuPinyinCaseType.UPPERCASE);
format.setToneType(HanyuPinyinToneType.WITH_TONE_NUMBER);
StringBuilder sb = new StringBuilder();

char[] charArray = hanZi.toCharArray();
for (int i = 0; i < charArray.length; i++) {
char c = charArray[i];
// 如果是空格, 跳过
if (Character.isWhitespace(c)) {
continue;
}
if (c >= -127 && c < 128) {
// 肯定不是汉字
sb.append(c);
} else {
String s = "";
try {
// 通过char得到拼音集合. 单 -> dan, shan
s = PinyinHelper.toHanyuPinyinStringArray(c, format)[0];
sb.append(s);
} catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace();
sb.append(s);
}
}
}

return sb.toString();
}

}


5. 汉字按拼音排序

//让联系人自身具备比较性(按照拼音)

/**
* 描述:
* 作者 mjd
* 日期:2015/12/10 13:01
*/
public class Person implements Comparable<Person> {

private String name;
private String pinyin;

public Person(String name) {
this.name = name;
this.pinyin = PinYinUtils.getPinYin(name);
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getPinyin() {
return pinyin;
}

public void setPinyin(String pinyin) {
this.pinyin = pinyin;
}

@Override
public int compareTo(@NonNull Person another) {
return this.pinyin.compareTo(another.getPinyin());
}

}

//主页面(Cheeses.NAMES 是准备好的一百零八位好汉的名字)
/**
* 描述:
* 作者 mjd
* 日期:2015/12/9 21:43
*/

public class MainActivity extends AppCompatActivity {

private FastIndexBar fastIndexBar;
private RecyclerView recyclerView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fastIndexBar = (FastIndexBar) findViewById(R.id.fast_index_bar);
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
fastIndexBar.setOnIndexChangedListener(new FastIndexBar.OnIndexChangedListener() {
@Override
public void onIndexChanged(String index) {
Toast.makeText(MainActivity.this, index, 0).show();
}
});

ContactAdapter adapter = new ContactAdapter(getContacts());
recyclerView.setAdapter(adapter);
RecyclerView.LayoutManager manager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(manager);

}

private List<Person> getContacts() {
List<Person> list = new ArrayList<>();
String[] names = Cheeses.NAMES;
for (int i = 0; i < names.length; i++) {
list.add(new Person(names[i]));
}
Collections.sort(list);
return list;
}

}
//联系人的适配器
/**
* 描述:
* 作者 mjd
* 日期:2015/12/10 13:08
*/
public class ContactAdapter extends RecyclerView.Adapter<MyViewHolder> {

private List<Person> personList;

public ContactAdapter(List<Person> personList) {
this.personList = personList;
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = View.inflate(parent.getContext(), R.layout.item_contact, null);
view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
return new MyViewHolder(view);
}

@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Person person = personList.get(position);
holder.tvIndex.setText(String.valueOf(person.getPinyin().charAt(0)));
holder.tvName.setText(person.getName());
}

@Override
public int getItemCount() {
return personList.size();
}

}

class MyViewHolder extends RecyclerView.ViewHolder {

TextView tvIndex;
TextView tvName;

public MyViewHolder(View itemView) {
super(itemView);
tvIndex = (TextView) itemView.findViewById(R.id.tv_index);
tvName = (TextView) itemView.findViewById(R.id.tv_name);
}
}


6. 汉字按拼音分组

//在适配器的onBindViewHolder方法中判断
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Person person = personList.get(position);
String currentIndex = String.valueOf(person.getPinyin().charAt(0));
String str = null;
if (position == 0) {
str = currentIndex;
} else {
String preIndex = String.valueOf(personList.get(position - 1).getPinyin().charAt(0));
if (!currentIndex.equals(preIndex)) {
str = currentIndex;
}
}
holder.tvIndex.setVisibility(str == null ? View.GONE : View.VISIBLE);
holder.tvIndex.setText(currentIndex);
holder.tvName.setText(person.getName());
}


7. 将快速索引控件与RecyclerView绑定

fastIndexBar.setOnIndexChangedListener(new FastIndexBar.OnIndexChangedListener() {
@Override
public void onIndexChanged(String index) {
//显示居中的字母提醒
showIndex(index);
//找到personList中第一个以index为拼音首字母的对象,得到索引
for (int i = 0; i < personList.size(); i++) {
String currentIndex = String.valueOf(personList.get(i).getPinyin().charAt(0));
if (currentIndex.equals(index)) {//匹配成功
recyclerView.scrollToPosition(i);
break;
}
}
}
});

private Handler handler = new Handler();

private void showIndex(String index) {
tvCenter.setVisibility(View.VISIBLE);
tvCenter.setText(index);
handler.removeCallbacksAndMessages(null);
handler.postDelayed(new Runnable() {
@Override
public void run() {
tvCenter.setVisibility(View.GONE);
}
}, 2000);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: