先看下效果

一 、布局

<!-- 上面的搜索框 -->
<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. 第20月第14天 objc_getAssociatedObject _cmd

    1. - (CustomNavigationControllerDelegate *)customDelegate { return objc_getAssociatedObject(self, _c ...

  2. JavaScript中Float类型保留两位小数

    JavaScript中Float类型保留两位小数 核心方法: num:要操作的数字     size:要保留的位数 parseFloat(num).toFixed(size); 实现代码如下:var  ...

  3. 爬虫BS4—淘女郎

    1.修改网页头 用独自的py文件getheaders,随机返回header getheaders文件 import random headerstr = """Mozil ...

  4. AndroidStudio Terminal的使用

    gradlew  assembleDebug  --stacktrace 查看使用的依赖的 Execution failed for task ':app:transformClassesWithMu ...

  5. 《Java编程思想第四版》附录 B 对比 C++和 Java

    <Java编程思想第四版完整中文高清版.pdf>-笔记 附录 B 对比 C++和 Java “作为一名 C++程序员,我们早已掌握了面向对象程序设计的基本概念,而且 Java 的语法无疑是 ...

  6. [转] 如何轻松愉快地理解条件随机场(CRF)?

    原文链接:https://www.jianshu.com/p/55755fc649b1 如何轻松愉快地理解条件随机场(CRF)?   理解条件随机场最好的办法就是用一个现实的例子来说明它.但是目前中文 ...

  7. WindowsPE权威指南-PE文件头中的重定位表

    PE加载的过程 任何一个EXE程序会被分配4GB的内存空间,用户层处理低2G的内存,驱动处理高2G的内存. 1.双击EXE程序,操作系统开辟一个4GB的空间. 2.从ImageBase决定了加载后的基 ...

  8. Spring Boot中的initializers的作用分析

    在SpringApplication的实例属性中有一个初始器的属性:List<ApplicationContextInitializer<?>> initializers ,这 ...

  9. VB获取CAD属性值

    Dim myAcadApp As AutoCAD.AcadApplication, activeDoc As AutoCAD.AcadDocument, acMS As AutoCAD.AcadMod ...

  10. Openssl源代码整理学习---含P7/P10/P12说明

    声明:建议结合Openssl源代码学习: 一.基础知识 1.Openssl 简史 OpenSSL项目是加拿大人Eric A.Yang 和Tim J.Hudson开发,现在有Openssl项目小组负责改 ...