关于这篇文章 刚开始我心里也不知道从何下手,只能一步步来了。
看下实现效果:
先说下我的步骤:
步骤1:学会使用汉语转拼音的第三方jar包; compile ‘com.belerweb:pinyin4j:2.5.0’
步骤2:自定义view实现右侧字母表
步骤3:然后书写普通的listview。(里面用到汉语转拼音)
步骤4:关联listview和右侧的自定义view;
步骤1:
这个没啥好说的,看下代码吧;
package com.app.test.pinyinproject;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
/**
* Created by mengqiang on 2017/5/8.
*/
public class PinyinUtils {
private static StringBuffer stringBuffer = new StringBuffer();
/**
* 返回汉语首个汉字的首字母,英文就返回首字母(小写的)
* 例如:你好→n
* nihao→n
*/
public static String getPinyin(String infoString){
stringBuffer.setLength(0);
String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(infoString.toCharArray()[0]);
if(pinyinArray != null){
stringBuffer.append(pinyinArray[0].charAt(0));
}else{
stringBuffer.append(infoString.toCharArray()[0]);
}
return stringBuffer.toString();
}
/**
* 返回汉语首个汉字的首字母,英文就返回首字母(大写的)
* 例如:你好→N
* nihao→N
*/
public static String getUpPinyin(String infoString){
stringBuffer.setLength(0);
String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(infoString.toCharArray()[0]);
if(pinyinArray != null){
stringBuffer.append(pinyinArray[0].toUpperCase().charAt(0));
}else{
stringBuffer.append(infoString.toUpperCase().toCharArray()[0]);
}
return stringBuffer.toString();
}
/**
* 获取汉字字符串的首字母,英文字符不变
* 例如:你好→nh
* nihao→nihao
*/
public static String getPinYinHeadChar(String headString) {
stringBuffer.setLength(0);
char[] chars = headString.toCharArray();
HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
for (int i = 0; i < chars.length; i++) {
if (chars[i] > 128) {
try {
stringBuffer.append(PinyinHelper.toHanyuPinyinStringArray(chars[i], defaultFormat)[0].charAt(0));
} catch (Exception e) {
e.printStackTrace();
}
} else {
stringBuffer.append(chars[0]);
}
}
return stringBuffer.toString();
}
/**
* 获取汉字字符串的汉语拼音,英文字符不变
* 例如:你好→nihao
* nihao→nihao
*/
public static String getPinYinLine(String lineString) {
stringBuffer.setLength(0);
char[] nameChar = lineString.toCharArray();
HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
for (int i = 0; i < nameChar.length; i++) {
if (nameChar[i] > 128) {
try {
stringBuffer.append(PinyinHelper.toHanyuPinyinStringArray(nameChar[i], defaultFormat)[0]);
} catch (Exception e) {
e.printStackTrace();
}
} else {
stringBuffer.append(nameChar[i]);
}
}
return stringBuffer.toString();
}
}
步骤2:
(1)首先获取自定义view的height和wigth,然后将height分为27份heightText(26字母 + “#”),然后用canvas.drawText写出每一个字母。其中baselinbe的计算需要掌握。
(2)然后就是点击view怎么获取字母了。我们可以转化一下,我们点击view的时候获取点击的坐标(重写onTouchEvent方法),然后根据坐标计算出应该是哪一个字母。在使用接口回调给activity;
上代码:
package com.app.test.pinyinproject;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
/**
* Created by mengqiang on 2017/5/8.
*/
/**
* 思路:先将height分为27个heightText,然后将分别将字母写在自己的区域;
* 设置点击事件实际上就是重写view内部的TouchEvent方法,然后根据TouchEvent的不同事件做出不同的反应。
*/
public class PinyinView extends View {
private Paint paint;
private int height;
private int wight;
private float heightText;
private OnItemClickListener onItemClickListener;
private int color = Color.WHITE;
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
private String[] pinyinArray= {"#",
"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"
};
public PinyinView(Context context) {
super(context);
initView();
}
public PinyinView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public PinyinView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
height = getMeasuredHeight();
wight = getMeasuredWidth();
heightText = ((float)height/(float)27);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(color);
for(int i = 0;i < pinyinArray.length;i++){
float x = wight/2 - paint.measureText(pinyinArray[i])/2;
/**
* 知识点:baseLine的计算
*/
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
float y = i * heightText + heightText/2 - (fontMetrics.top + fontMetrics.bottom)/2;
canvas.drawText(pinyinArray[i],x,y,paint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float coordinateY;
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:{//点击Down是颜色是gray
color = Color.GRAY;
postInvalidate();//延伸知识点:1:invalidate()和postInvalidate()的区别 2:view的双缓冲技术
break;
}
case MotionEvent.ACTION_UP:{//UP的时候颜色是white
coordinateY = event.getY();
onItemClickListener.onItemListener(getChar(coordinateY));
color = Color.WHITE;
postInvalidate();
break;
}
}
return true;
}
/**
* 定义接口,用于传递所点击的字母
*/
interface OnItemClickListener{
void onItemListener(String infoString);
}
/**
* 计算coordinateY对应的字母
* @param coordinateY 点击的坐标
* @return 返回coordinateY对应的字母
*/
public String getChar(float coordinateY){
for(int i = 0;i < pinyinArray.length;i++){
if(heightText * i > coordinateY){
return pinyinArray[i - 1];
}
}
return pinyinArray[26];
}
public void initView(){
paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.BLUE);
paint.setAntiAlias(true);
paint.setTextSize(20);
}
}
步骤3:
其实步骤2也是需要多考虑一些东西,比如:我们是使用两个adapter还是一个adapter,都能实现,再次我们是一个adapter;
我遇到问题一般是这样解决的:首先它是有什么组成?然后拆分成小部分;最后组合一下。
在这里我们需要书写adapter和adapter的数据(数据比较,降序排列)。
先说数据比较。我们需要创建一个User类用,
private String name;//名称
private String headChar;//首字母
private String comparaChar;//第一个汉字的拼音全称
然后根据User类的首个汉字的拼音进行比较。
private String[] name = new String[]{"潘粤明", "戴军", "薛之谦", "蓝雨", "任泉", "张杰", "秦俊杰","陈坤", "田亮", "夏雨", "保剑锋", "陆毅", "乔振宇", "吉杰", "郭敬明", "巫迪文", "欢子", "井柏然","左小祖咒", "段奕宏", "毛宁", "樊凡", "汤潮", "山野", "陈龙", "侯勇", "俞思远", "冯绍峰", "崔健","杜淳", "张翰", "彭坦", "柏栩栩", "蒲巴甲", "凌潇肃", "毛方圆", "武艺", "耿乐", "钱泳辰","aaa","13","123654"};
public void setListData(){
for(int i = 0;i < name.length;i++){
User user = new User();
user.setName(name[i]);
if(PinyinUtils.getUpPinyin(name[i]).matches("[A-Z]")){//首字母
user.setHeadChar(PinyinUtils.getUpPinyin(name[i]));
}else{
user.setHeadChar(PinyinUtils.getUpPinyin("#"));
}
user.setComparaChar(PinyinUtils.getPinYinLine(name[i]));//比较 (此字段用于比较第一个汉字)
list.add(user);
}
Collections.sort(list, new ComparaUser());// 第一个汉字进行拼音比较(降序);
}
然后就是adapter的实现了。
package com.app.test.pinyinproject;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.List;
/**
* Created by mengqiang on 2017/5/8.
*/
public class ListAdapter extends BaseAdapter {
private List<User> userList ;
private OnItemClickListener onItemClickListener;
public OnItemClickListener getOnItemClickListener() {
return onItemClickListener;
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
public ListAdapter(List<User> userList) {
this.userList = userList;
}
@Override
public int getCount() {
return userList.size();
}
@Override
public Object getItem(int position) {
return userList.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ItemViewHolder itemViewHolder;
if(convertView == null){
convertView = View.inflate(parent.getContext(), R.layout.item_layout, null);
itemViewHolder = new ItemViewHolder();
itemViewHolder.charText = (TextView) convertView.findViewById(R.id.char_text);
itemViewHolder.nameText = (TextView) convertView.findViewById(R.id.name_text);
convertView.setTag(itemViewHolder);
}else{
itemViewHolder = (ItemViewHolder) convertView.getTag();
}
if(position == getPosition(position)){
itemViewHolder.charText.setVisibility(View.VISIBLE);
itemViewHolder.charText.setText(userList.get(position).getHeadChar());
}else{
itemViewHolder.charText.setVisibility(View.GONE);
}
itemViewHolder.nameText.setText(userList.get(position).getName());
itemViewHolder.nameText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onItemClickListener.onItemCLick(position);
}
});
return convertView;
}
/**
* 计算出该luserist中position第一次对应的charAt下标i,然后判断i是否等于position。
* @param position
* @return
*/
public int getPosition(int position){
char charAt = userList.get(position).getHeadChar().charAt(0);
for(int i = 0 ;i < userList.size();i++){
if(charAt == userList.get(i).getHeadChar().charAt(0)){
return i;
}
}
return -1;
}
class ItemViewHolder{
public TextView nameText;
public TextView charText;
}
/**
* 用于传递点击了userlist哪一个item。
*/
interface OnItemClickListener{
void onItemCLick(int position);
}
}
步骤4:
然后就是view和listview怎么关联呢,根据view接口返回的infoString 获取position,然后listview滑动到相应的位置
pinyinView.setOnItemClickListener(new PinyinView.OnItemClickListener() {
@Override
public void onItemListener(String infoString) {
/**
* 点击右侧的字母表,listview滑动到相应的位置
*/
for(int i = 0;i < list.size();i++){
if(infoString.equals(list.get(i).getHeadChar())){
listview.setSelection(i);
break;
}
}
}
});
感觉这都不难,重点是碰见一个问题之后怎么看待这个问题。
最后付上源码下载地址:http://download.csdn.net/detail/lmq121210/9836455