先看下效果

一 、布局

<!-- 上面的搜索框 -->
<com.example.editablealphalist.widgget.ClearEditText
android:id="@+id/filter_edit"
android:layout_marginTop="5dip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/search_bar_edit_selector"
android:drawableLeft="@drawable/search_bar_icon_normal"
android:hint="请输入关键字"
android:singleLine="true"
android:textSize="15sp" /> <FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" > <ListView
android:id="@+id/name_listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:divider="@null" /> <!-- 中间显示的选中的大写首字母 -->
<TextView
android:id="@+id/dialog"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_gravity="center"
android:background="@drawable/show_head_toast_bg"
android:gravity="center"
android:textColor="@color/font_color_selected"
android:textSize="30sp"
android:visibility="gone" /> <!-- 右侧供选择的列表 -->
<com.example.editablealphalist.widgget.SideBar
android:id="@+id/sidrbar"
android:layout_width="30dp"
android:layout_height="match_parent"
android:layout_gravity="right|center" />
</FrameLayout>

二、自定义控件

2.1  ClearEditText 带删除按钮的输入框

public class ClearEditText extends AppCompatEditText implements OnFocusChangeListener, TextWatcher {

    /**
* 删除按钮的引用
*/
private Drawable mClearDrawable; public ClearEditText(Context context) {
this(context, null);
} public ClearEditText(Context context, AttributeSet attrs) {
// 这里构造方法也很重要,不加这个很多属性不能再XML里面定义
this(context, attrs, android.R.attr.editTextStyle);
} public ClearEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
} private void init() {
// 获取EditText的DrawableRight,假如没有设置我们就使用默认的图片
mClearDrawable = getCompoundDrawables()[2];
if (mClearDrawable == null) {
mClearDrawable = getResources().getDrawable(R.drawable.emotionstore_progresscancelbtn);
}
mClearDrawable.setBounds(0, 0, mClearDrawable.getIntrinsicWidth(), mClearDrawable.getIntrinsicHeight());
setClearIconVisible(false);
setOnFocusChangeListener(this);
addTextChangedListener(this);
} @Override
public boolean onTouchEvent(MotionEvent event) { if (getCompoundDrawables()[2] != null) { if (event.getAction() == MotionEvent.ACTION_UP) { boolean touchable = event.getX() > (getWidth() - getPaddingRight() - mClearDrawable.getIntrinsicWidth())
&& (event.getX() < ((getWidth() - getPaddingRight())));
if (touchable) { //选中了“删除”按钮 this.setText("");
}
}
}
return super.onTouchEvent(event);
} /**
* 当ClearEditText焦点发生变化的时候,判断里面字符串长度设置清除图标的显示与隐藏
*/
@Override
public void onFocusChange(View v, boolean hasFocus) { if (hasFocus) { setClearIconVisible(getText().length() > 0);
} else { setClearIconVisible(false);
}
} /**
* 设置清除图标的显示与隐藏,调用setCompoundDrawables为EditText绘制上去
*
* @param visible
*/
protected void setClearIconVisible(boolean visible) { Drawable right = visible ? mClearDrawable : null;
setCompoundDrawables(getCompoundDrawables()[0], getCompoundDrawables()[1], right, getCompoundDrawables()[3]);
} /**
* 当输入框里面内容发生变化的时候回调的方法
*/
@Override
public void onTextChanged(CharSequence s, int start, int count, int after) {
setClearIconVisible(s.length() > 0);
} @Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
} @Override
public void afterTextChanged(Editable s) { }
}

2.2  SideBar 右侧首字母列表

/**
* 右侧首字母列表bar
* @author Jack
* @version 创建时间:2014-2-6 下午3:37:33
*/
public class SideBar extends View { /** 触摸事件 */
private OnTouchingLetterChangedListener onTouchingLetterChangedListener;
/** 26个字母 */
public static String[] characters = { "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", "#" };
private int ifSelected = -1; // 选中
private Paint paint = new Paint();
private TextView mTextDialog; public void setTextView(TextView mTextDialog) {
this.mTextDialog = mTextDialog;
} public SideBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
} public SideBar(Context context, AttributeSet attrs) {
super(context, attrs);
} public SideBar(Context context) {
super(context);
} /**
* 重写这个方法
*/
protected void onDraw(Canvas canvas) { super.onDraw(canvas);
// 获取焦点改变背景颜色.
int height = getHeight(); // 获取对应高度
int width = getWidth(); // 获取对应宽度
int singleHeight = height / characters.length; // 获取每一个字母的高度 for (int i = 0; i < characters.length; i++) { // 设置颜色
paint.setColor(Color.rgb(33, 65, 98));
// 设置字体
paint.setTypeface(Typeface.DEFAULT_BOLD);
// 设置抗锯齿
paint.setAntiAlias(true);
// 设置字体大小
paint.setTextSize(20);
// 选中的状态
if (i == ifSelected) { paint.setColor(Color.parseColor("#3399ff"));
paint.setFakeBoldText(true);
}
// x坐标等于中间-字符串宽度的一半.
float xPos = width / 2 - paint.measureText(characters[i]) / 2;
float yPos = singleHeight * i + singleHeight;
canvas.drawText(characters[i], xPos, yPos, paint);
paint.reset();// 重置画笔
}
} @Override
public boolean dispatchTouchEvent(MotionEvent event) { final int action = event.getAction();
final float y = event.getY();// 点击y坐标
final int oldSelected = ifSelected;
final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener;
final int selected = (int) (y / getHeight() * characters.length);// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数. switch (action) { case MotionEvent.ACTION_UP: setBackgroundDrawable(new ColorDrawable(0x00000000));
ifSelected = -1;//
invalidate();
if (mTextDialog != null) {
mTextDialog.setVisibility(View.INVISIBLE);
}
break;
default: setBackgroundResource(R.drawable.sidebar_background);
if (oldSelected != selected) {
if (selected >= 0 && selected < characters.length) {
if (listener != null) {
listener.onTouchingLetterChanged(characters[selected]);
}
if (mTextDialog != null) {
mTextDialog.setText(characters[selected]);
mTextDialog.setVisibility(View.VISIBLE);
}
ifSelected = selected;
invalidate();
}
}
break;
}
return true;
} /**
* 向外公开的方法
* @param onTouchingLetterChangedListener
*/
public void setOnTouchingLetterChangedListener(OnTouchingLetterChangedListener onTouchingLetterChangedListener) { this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;
} /**
* 触碰右侧列表时的回调接口
*/
public interface OnTouchingLetterChangedListener {
public void onTouchingLetterChanged(String s);
}

三、事件处理

3.1 右侧字母栏滑动处理

     sideBar = (SideBar) findViewById(R.id.sidrbar);
dialog = (TextView) findViewById(R.id.dialog);
sideBar.setTextView(dialog);
// 设置右侧触摸监听
sideBar.setOnTouchingLetterChangedListener(new SideBar.OnTouchingLetterChangedListener() { @Override
public void onTouchingLetterChanged(String s) {
// 该字母首次出现的位置
int position = adapter.getPositionForSection(s.charAt(0));
if (position != -1) {
sortListView.setSelection(position);
}
}
});

3.2 输入框事件处理

//查询框设置监听
mClearEditText = (ClearEditText) findViewById(R.id.filter_edit);
// 根据输入框输入值的改变来过滤搜索
mClearEditText.addTextChangedListener(new TextWatcher() { @Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
// 当输入框里面的值为空,更新为原来的列表,否则为过滤数据列表
filterData(s.toString());
} @Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) { } @Override
public void afterTextChanged(Editable s) {
}
});
/**
* 根据输入框中的值来过滤数据源,截取含有查询字符串的数据
*
* @param filterStr 查询字符串
*/
private void filterData(String filterStr) { List<SortModel> filterDataList = new ArrayList<SortModel>();
if (TextUtils.isEmpty(filterStr)) { filterDataList = sourceDataList;
} else { filterDataList.clear();
for (SortModel sortModel : sourceDataList) { String name = sortModel.getName();
/*if (name.indexOf(filterStr.toString()) != -1 || characterParser.getSelling(name).startsWith(filterStr.toString())) { filterDataList.add(sortModel);
}*/
if (name.indexOf(filterStr.toString()) != -1 || pinyin4JUtil.convertChineseToPinyin(name).startsWith(filterStr.toString())) { filterDataList.add(sortModel);
}
}
}
// 根据a-z进行排序
Collections.sort(filterDataList, pinyinComparator);
adapter.updateListView(filterDataList);
}

四、汉字转拼音及多音字处理

4.1 初始化转换格式

/**
* 获取拼音初始汉语拼音格式化实例
*
* @param withTone
* @return
*/
private HanyuPinyinOutputFormat getHanyuPinyinOutputFormat(boolean withTone) {
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
if (withTone) {
//直接用音标符
format.setToneType(HanyuPinyinToneType.WITH_TONE_MARK);// WITHOUT_TONE:无音标 (xing)
//format.setToneType(HanyuPinyinToneType.WITH_TONE_NUMBER);// WITH_TONE_NUMBER:1-4数字表示英标 (xing2)
//直接用ü (nü)
format.setVCharType(HanyuPinyinVCharType.WITH_U_UNICODE);//WITH_V:用v表示ü (nv) //WITH_U_AND_COLON:用”u:”表示ü (nu:)
format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
} else {
//直接用音标符
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
format.setVCharType(HanyuPinyinVCharType.WITH_U_UNICODE);
format.setCaseType(HanyuPinyinCaseType.UPPERCASE);
}
return format;
}
    1. setToneType 设置音标的显示方式:

      • HanyuPinyinToneType.WITH_TONE_MARK:在拼音字母上显示音标,如“zhòng”
      • HanyuPinyinToneType.WITH_TONE_NUMBER:在拼音字符串后面通过数字显示,如“zhong4”
      • HanyuPinyinToneType.WITHOUT_TONE:不显示音标
    2. setCaseType 设置拼音大小写:

      • HanyuPinyinCaseType.LOWERCASE:返回的拼音为小写字母
      • HanyuPinyinCaseType.UPPERCASE:返回的拼音为大写字母
    3. setVCharType 设置拼音字母“ü”的显示方式 
      汉语拼音中的“ü”不能简单的通过英文来表示,所以需要单独定义“ü”的显示格式

      • HanyuPinyinVCharType.WITH_U_UNICODE:默认的显示方式,输出“ü”
      • HanyuPinyinVCharType.WITH_V:输出“v”
      • HanyuPinyinVCharType.WITH_U_AND_COLON:输出“u:”

4.2 转换成汉语拼音

HanyuPinyinOutputFormat defaultFormat = getHanyuPinyinOutputFormat(false);
String[] results = PinyinHelper.toHanyuPinyinStringArray(ch, defaultFormat);//ch是要转化的汉字,用char表示。如'重'
如果results中拼音个数如果大于1说明该汉字是多音字

4.3 多音字处理

4.3.1 获取py4j.txt中的数据转换成map形式

private HashMap<String, String> initDictionary(Context context) {
String fileName = "py4j.txt";
InputStreamReader inputReader = null;
BufferedReader bufferedReader = null;
HashMap<String, String> polyphoneMap = new HashMap<String, String>();
try {
inputReader = new InputStreamReader(context.getResources().getAssets().open(fileName), "UTF-8");
bufferedReader = new BufferedReader(inputReader);
String line = null;
while ((line = bufferedReader.readLine()) != null) {
//Log.d(TAG,"======"+line);
if (line != null) {
String[] arr = line.split("#");
String pinyin = arr[0];
String chinese = arr[1];
if (chinese != null) {
String[] strs = chinese.split(" ");
List<String> list = Arrays.asList(strs);
pinyinMap.put(pinyin, list);
}
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}

将py4j.txt保存到assets目录通过context.getResources().getAssets().open(fileName)打开,存放到字符流中。

4.3.2 判断多音字并找到最优的拼音

{
int len = results.length;
if (len == 1) { // 不是多音字
String[] pinyinArray = getHanyuStrings(true, ch);
pinyin.append(pinyinArray[0]);
} else if (results[0].equals(results[1])) { //非多音字 有多个音,取第一个
//pinyin.append(results[0]);
String[] pinyinArray = getHanyuStrings(true, ch);
pinyin.append(pinyinArray[0]);
} else { // 多音字
int length = chinese.length();
boolean flag = false;
String s = null;
List<String> keyList = null;
for (int x = 0; x < len; x++) {
String py = results[x];
keyList = pinyinMap.get(py.toLowerCase());
resultPos = x;
if (i + 3 <= length) { //后向匹配2个汉字 大西洋
s = chinese.substring(i, i + 3);
if (keyList != null && (keyList.contains(s))) {
flag = true;
break;
}
}
if (i + 2 <= length) { //后向匹配 1个汉字 大西
s = chinese.substring(i, i + 2);
if (keyList != null && (keyList.contains(s))) {
flag = true;
break;
}
}
if ((i - 2 >= 0) && (i + 1 <= length)) { // 前向匹配2个汉字 龙固大
s = chinese.substring(i - 2, i + 1);
if (keyList != null && (keyList.contains(s))) {
flag = true;
break;
}
}
if ((i - 1 >= 0) && (i + 1 <= length)) { // 前向匹配1个汉字 固大
s = chinese.substring(i - 1, i + 1);
if (keyList != null && (keyList.contains(s))) {
flag = true;
break;
}
}
if ((i - 1 >= 0) && (i + 2 <= length)) { //前向1个,后向1个 固大西
s = chinese.substring(i - 1, i + 2);
if (keyList != null && (keyList.contains(s))) {
flag = true;
break;
}
}
}
if (!flag) {//都没有找到,匹配默认的 读音 大
s = String.valueOf(ch);
for (int x = 0; x < len; x++) {
String py = results[x];
keyList = pinyinMap.get(py.toLowerCase());
if (keyList != null && (keyList.contains(s))) {
String[] pinyinArray = getHanyuStrings(true, ch);
pinyin.append(pinyinArray[x]);
break;
}
}
} else {
String[] pinyinArray = getHanyuStrings(true, ch);
pinyin.append(pinyinArray[resultPos]);
}
}
}

如果是多音字,则去匹配py4j.txt中的字符是否存在找到对应的多音字下标

 String[] pinyinArray = getHanyuStrings(true, ch);
pinyin.append(pinyinArray[resultPos]);
...
private String[] getHanyuStrings(boolean withTone, char ch) {
HanyuPinyinOutputFormat format = getHanyuPinyinOutputFormat(withTone);
String[] pinyinArray = new String[0];
try {
pinyinArray = PinyinHelper.toHanyuPinyinStringArray(ch, format);
} catch (BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) {
badHanyuPinyinOutputFormatCombination.printStackTrace();
}
return pinyinArray;
}

五、缺点

判断多音字存在缺陷,只能通过py4j.txt字库中查找,字库资源不完善。

https://github.com/MichealPan9999/chinesetopinyin

py4j汉语转拼音多音字处理的更多相关文章

  1. C# 汉语转拼音

    汉语转拼音或首字母 通常不少网站上有汉语转拼音功能,今天就小记下这段汉语转拼音的代码,自己测试ok,现把代码贴出来,以备日后使用: 效果 用法很简单后台使用到了两个类文件,一个是:ConvertHzT ...

  2. java:工具(汉语转拼音,压缩包,EXCEL,JFrame窗口和文件选择器,SFTP上传下载,FTP工具类,SSH)

    1.汉语转拼音: import net.sourceforge.pinyin4j.PinyinHelper; import net.sourceforge.pinyin4j.format.HanyuP ...

  3. java 汉语转拼音(全拼,首字母)

    import java.util.*; import net.sourceforge.pinyin4j.PinyinHelper;import net.sourceforge.pinyin4j.for ...

  4. JS汉语转拼音脚本

    测试代码: var anhui = "安徽"; //获得全拼 pinyin.getFullChars(anhui); //获得首拼 pinyin.getCamelChars(anh ...

  5. js汉语转拼音(全拼、首字母、拼音首字母)

    新建js文件first_alphabet.js // JavaScript Document // 汉字拼音首字母列表 本列表包含了20902个汉字,用于配合 ToChineseSpell //函数使 ...

  6. 汉语转拼音pinyin4j

    分享一个将汉语转成拼音的工具包:pinyin4j-2.5.0.jar,下载地址:http://download.csdn.net/detail/abc_key/7629141 使用例如以下代码 imp ...

  7. Java-汉字繁体拼音转换

    import com.github.stuxuhai.jpinyin.ChineseHelper; import com.github.stuxuhai.jpinyin.PinyinFormat; i ...

  8. C#编写的通过汉字得到拼音和五笔码

    public static class SpellAndWbConfig { #region 变量声明 // XML文件读取实例 /// <summary> /// XML文件读取实例 / ...

  9. .net 生成拼音码与五笔码

    首先加入配置文件: <?xml version="1.0" encoding="utf-8" ?> <CodeConfig> <S ...

随机推荐

  1. PHP7语法知识(一):语言基础

    一.数据类型 1.字符串: 2.整形: var_dump函数:返回变量的数据类型和值. 3.浮点型: 4.布尔型: 5.数组: 6.对象: 7.NULL值 二.运算符 1.算术运算符: 2.递增递减运 ...

  2. git详细介绍

    Git管理我们的代码会经历三个不过程 1. 工作区:没有提交的代码就是存放的工作区 2. 暂存区:通过 git add 文件名 命令提交代码该文件就放在暂存区 3. 历史区:通过 git commit ...

  3. 【译】第七篇 SQL Server安全跨数据库所有权链接

    本篇文章是SQL Server安全系列的第七篇,详细内容请参考原文. Relational databases are used in an amazing variety of applicatio ...

  4. no plugin found for prefix 'tomcat 7' in the current project

    使用maven build编译出错 “no plugin found for prefix 'tomcat 7' in the current project..........” 参照下面方法 ht ...

  5. yum upgrade和yum update的区别

    Linux升级命令有两个分别是yum upgrade和yum update, 这个两个命令是有区别的: yum -y update 升级所有包同时也升级软件.系统版本和系统内核 yum -y upgr ...

  6. jQuery实现回车绑定Tab事件

    有时候我们希望回车事件绑定的是键盘的Tab事件.我的第一思路就是切换事件的keyCode,比如键盘事件按下的keyCode如果是13,我们将keyCode改为9.但是在实际编程中却未能实现此效果.于是 ...

  7. Java中通过脚本引擎调用js函数

    import java.io.*; import javax.script.Invocable; import javax.script.ScriptEngine; import javax.scri ...

  8. OGG初始加载过程概述

    您可以使用Oracle GoldenGate来: 执行独立的批量加载以填充数据库表以进行迁移或其他用途. 将数据作为初始同步运行的一部分加载到数据库表中,以准备与Oracle GoldenGate进行 ...

  9. C/C++ assert()函数用法总结

    1. 简介 assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行. 原型定义: #include <assert.h>void ass ...

  10. [转] 图 + 文 + 公式 理解LSTM

    转自公号“机器之心” LSTM入门必读:从入门基础到工作方式详解 长短期记忆(LSTM)是一种非常重要的神经网络技术,其在语音识别和自然语言处理等许多领域都得到了广泛的应用..在这篇文章中,Edwin ...