1、添加依赖
把中文转成拼音才能按首字母进行排序
implementation 'com.belerweb:pinyin4j:2.5.1'
2、三个工具类
PinYinUtils
public class PinYinUtils {
/**
* 返回首字母,大写
*
* @param str
* @return
*/
public static String getFirstLetter(String str) {
if (TextUtils.isEmpty(str)) {
return "";
} // 得到一个字符串的拼音的大写
String pinyinStr = getPinyin(str).toUpperCase();
// 取拼音字符串的第一个字母
// String first = pinyinStr.substring(0, 1).toLowerCase();
// if (first.matches("[a-z]")) {
//
// } else {
//
// }
char firstCahr = pinyinStr.charAt(0);
// 不是A-Z字母
if (firstCahr > 90 || firstCahr < 65) {
return "#";
} else { // 代表是A-Z
return String.valueOf(firstCahr);
}
}
/**
* 得到一个字符串的拼音读音
*
* @param chineseStr
* @return
*/
public static String getPinyin(String chineseStr) {
StringBuffer sb = new StringBuffer();
// 将汉字拆分成一个个的char
char[] chars = chineseStr.toCharArray();
// 遍历汉字的每一个char
for (int i = 0; i < chars.length; i++) {
try { // 汉字的所有读音放在一个pinyins数组
String[] pinyins = PinyinHelper.toHanyuPinyinStringArray(chars[i], getDefaultFormat());
if (pinyins == null) {
sb.append(chars[i]);
} else {
sb.append(pinyins[0]);
}
} catch (BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) {
badHanyuPinyinOutputFormatCombination.printStackTrace();
}
}
return sb.toString();
}
/**
* 设置默认的输出格式
*
* @return
*/
public static HanyuPinyinOutputFormat getDefaultFormat() {
HanyuPinyinOutputFormat outputFormat = new HanyuPinyinOutputFormat();
// 去除声调
outputFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
// 小写
outputFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
// 包含Unicode特殊字符
outputFormat.setVCharType(HanyuPinyinVCharType.WITH_U_UNICODE);
return outputFormat;
}
}
SystemUtil
public class SystemUtil {
/**
* 检查WIFI是否连接
*/
public static boolean isWifiConnected() {
ConnectivityManager connectivityManager = (ConnectivityManager) BaseApp.getInstance().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo wifiInfo = connectivityManager
.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
return wifiInfo != null;
}
/**
* 检查手机网络(4G/3G/2G)是否连接
*/
public static boolean isMobileNetworkConnected() {
ConnectivityManager connectivityManager = (ConnectivityManager) BaseApp.getInstance().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mobileNetworkInfo = connectivityManager
.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
return mobileNetworkInfo != null;
}
/**
* 检查是否有可用网络
*/
public static boolean isNetworkConnected() {
ConnectivityManager connectivityManager = (ConnectivityManager) BaseApp.getInstance().getSystemService(Context.CONNECTIVITY_SERVICE);
return connectivityManager.getActiveNetworkInfo() != null;
}
/**
* 保存文字到剪贴板
* @param context
* @param text
*/
public static void copyToClipBoard(Context context, String text) {
ClipData clipData = ClipData.newPlainText("url", text);
ClipboardManager manager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
manager.setPrimaryClip(clipData);
Toast.makeText(context,"已复制到剪贴板",Toast.LENGTH_SHORT).show();
}
/**
* 保存图片到本地
* @param context
* @param url
* @param bitmap
*/
public static Uri saveBitmapToFile(Context context, String url, Bitmap bitmap,
View container, boolean isShare){
String fileName = url.substring(url.lastIndexOf("/"),url.lastIndexOf(".")) + ".png";
File fileDir = new File(Constants.PATH_SDCARD);
if (!fileDir.exists()){
fileDir.mkdirs();
}
File imageFile = new File(fileDir,fileName);
Uri uri = Uri.fromFile(imageFile);
if (isShare && imageFile.exists()) {
if (Build.VERSION.SDK_INT >= 24) {
uri = FileProvider.getUriForFile(context.getApplicationContext(),
Constants.FILE_PROVIDER_AUTHORITY, imageFile);
}
return uri;
}
try {
FileOutputStream fos = new FileOutputStream(imageFile);
boolean isCompress = bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);
if (isCompress) {
ToastUtil.showShort("保存妹纸成功n(*≧▽≦*)n");
} else {
ToastUtil.showShort("保存妹纸失败ヽ(≧Д≦)ノ");
}
fos.flush();
fos.close();
} catch (IOException e) {
e.printStackTrace();
ToastUtil.showShort("保存妹纸失败ヽ(≧Д≦)ノ");
}
try {
MediaStore.Images.Media.insertImage(context.getContentResolver(), imageFile.getAbsolutePath(), fileName, null);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,uri));
if (Build.VERSION.SDK_INT >= 24) {
uri = FileProvider.getUriForFile(context.getApplicationContext(),
Constants.FILE_PROVIDER_AUTHORITY, imageFile);
}
return uri;
}
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
public static int dp2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
public static int dp2px(float dpValue) {
final float scale = BaseApp.getInstance().getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 根据手机的分辨率从 px(像素) 的单位 转成为 dp
*/
public static int px2dp(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
public static int px2dp(float pxValue) {
final float scale = BaseApp.getInstance().getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
/**
* 获取进程号对应的进程名
*
* @param pid 进程号
* @return 进程名
*/
public static String getProcessName(int pid) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("/proc/" + pid + "/cmdline"));
String processName = reader.readLine();
if (!TextUtils.isEmpty(processName)) {
processName = processName.trim();
}
return processName;
} catch (Throwable throwable) {
throwable.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (IOException exception) {
exception.printStackTrace();
}
}
return null;
}
}
ToastUtil
public class ToastUtil {
public static void showShort(String msg){
//避免内存泄漏的一个方法,用到上下文的地方,能用application的就application
Toast.makeText(BaseApp.getInstance(),msg,Toast.LENGTH_SHORT).show();
}
public static void showLong(String msg){
//避免内存泄漏的一个方法,用到上下文的地方,能用application的就application
Toast.makeText(BaseApp.getInstance(),msg,Toast.LENGTH_LONG).show();
}
}
3、Constants(常量接口)
public interface Constants {
boolean isDebug = true;
String PATH_SDCARD = Environment.getExternalStorageDirectory().getAbsolutePath() +
File.separator + "codeest" + File.separator + "GeekNews";
String FILE_PROVIDER_AUTHORITY="com.baidu.geek.fileprovider";
//网络缓存的地址
String PATH_DATA = BaseApp.getInstance().getCacheDir().getAbsolutePath() +
File.separator + "data";
}
4、BaseApp
别忘了在清单文件中配置
public class BaseApp extends Application {
private static BaseApp sBaseApp;
//默认不是夜间模式
public static int mMode = AppCompatDelegate.MODE_NIGHT_NO;
public static int mWidthPixels;
public static int mHeightPixels;
@Override
public void onCreate() {
super.onCreate();
sBaseApp = this;
getScreenWH();
}
//计算屏幕宽高
private void getScreenWH() {
WindowManager manager = (WindowManager) getSystemService(WINDOW_SERVICE);
Display defaultDisplay = manager.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
defaultDisplay.getMetrics(metrics);
mWidthPixels = metrics.widthPixels;
mHeightPixels = metrics.heightPixels;
}
public static BaseApp getInstance(){
return sBaseApp;
}
public static Resources getRes() {
return sBaseApp.getResources();
}
}
5、MyLetterView(自定义view)
public class MyLetterView extends View {
public static String[] letters = { "*" ,"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 Paint paint = new Paint();
/**
* 用于标记哪个位置被选中
*/
private int choose = -1;
//该TextView是左边显示的对话框
private TextView mTextDialog;
public void setTextDialog(TextView mTextDialog) {
this.mTextDialog = mTextDialog;
}
private OnTouchingLetterChangedListener listener;
public void setOnTouchingLetterChangedListener(OnTouchingLetterChangedListener listener) {
this.listener = listener;
}
public MyLetterView(Context context) {
super(context);
}
public MyLetterView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyLetterView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 获取该自定义View的宽度和高度
int width = getWidth();
int height = getHeight();
// 单个字母的高度
int singleHeight = height / letters.length;
for (int i = 0; i < letters.length; i++) {
paint.setColor(getResources().getColor(
R.color.c_fa6a13));
paint.setTypeface(Typeface.DEFAULT_BOLD);
paint.setAntiAlias(true);
paint.setTextSize(SystemUtil.dp2px(12));
// 如果选中的话,改变样式和颜色
if (i == choose) {
paint.setColor(Color.parseColor("#3399ff"));
paint.setFakeBoldText(true);
}
// 首先确定每个字母的横坐标的位置,横坐标:该自定义View的一半 -(减去) 单个字母宽度的一半
float xPos = width / 2 - paint.measureText(letters[i]) / 2;
float yPos = singleHeight * (i + 1);
canvas.drawText(letters[i], xPos, yPos, paint);
// 重置画笔
paint.reset();
}
}
@SuppressWarnings("deprecation")
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int action = event.getAction();
float y = event.getY();
int oldChoose = choose;
// 根据y坐标确定当前哪个字母被选中
int pos = (int) (y / getHeight() * letters.length);
switch (action) {
case MotionEvent.ACTION_UP:
// 当手指抬起时,设置View的背景为白色
setBackgroundDrawable(new ColorDrawable(0x00000000));
// 重置为初始状态
choose = -1;
// 让View重绘
invalidate();
// 将对话框设置为不可见
if (mTextDialog != null) {
mTextDialog.setVisibility(View.INVISIBLE);
}
break;
default:
// 设置右边字母View的背景色
// setBackgroundResource(R.drawable.);
if (pos != oldChoose) {
// 如果之前选中的和当前的不一样,需要重绘
if (pos >= 0 && pos < letters.length) {
if(listener != null) {
//当前字母被选中,需要让ListView去更新显示的位置
listener.onTouchingLetterChanged(letters[pos]);
}
//在左边显示选中的字母,该字母放在TextView上,相当于一个dialog
if (mTextDialog != null) {
mTextDialog.setText(letters[pos]); //让对话框显示响应的字母
mTextDialog.setVisibility(View.VISIBLE);
}
choose = pos; //当前位置为选中位置
}
}
break;
}
return true;
}
/**
* 该回调接口用于通知ListView更新状态
*/
public interface OnTouchingLetterChangedListener {
public void onTouchingLetterChanged(String s);
}
}
6、User(实体类)
public class User implements Comparable {
private String name; // 姓名
private String pinyin; // 姓名对应的拼音
private String firstLetter; // 拼音的首字母
public User() {
}
public User(String name) {
this.name = name;
pinyin = PinYinUtils.getPinyin(name); // 根据姓名获取拼音
firstLetter = pinyin.substring(0, 1).toUpperCase(); // 获取拼音首字母并转成大写
if (!firstLetter.matches("[A-Z]")) { // 如果不在A-Z中则默认为“#”
firstLetter = "#";
}
}
public String getName() {
return name;
}
public String getPinyin() {
return pinyin;
}
public String getFirstLetter() {
return firstLetter;
}
@Override
public int compareTo(User another) {
if (firstLetter.equals("#") && !another.getFirstLetter().equals("#")) {
return 1;
} else if (!firstLetter.equals("#") && another.getFirstLetter().equals("#")) {
return -1;
} else {
return pinyin.compareToIgnoreCase(another.getPinyin());
}
}
}
7、MainActivity
xml
MainActivity
public class MainActivity extends AppCompatActivity {
private ArrayList list;
private ListView list_friends;
private MyLetterView right_letter;
private TextView dialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initView();
}
private void initData() {
list = new ArrayList<>();
list.add(new User("亳州")); // 亳[bó]属于不常见的二级汉字
list.add(new User("蚌埠"));
list.add(new User("合肥"));
list.add(new User("北京"));
list.add(new User("天津"));
list.add(new User("苏州"));
list.add(new User("宿州"));
list.add(new User("淮北"));
list.add(new User("淮南"));
list.add(new User("黄山"));
list.add(new User("阜阳"));
list.add(new User("滁州"));
list.add(new User("马鞍山"));
list.add(new User("芜湖"));
list.add(new User("铜陵"));
list.add(new User("安庆"));
list.add(new User("六安"));
list.add(new User("池州"));
list.add(new User("巢湖"));
list.add(new User("宣城"));
list.add(new User("福州"));
list.add(new User("南平"));
list.add(new User("界首"));
list.add(new User("明光"));
list.add(new User("天长"));
list.add(new User("桐城"));
list.add(new User("宁国"));
list.add(new User("厦门"));
list.add(new User("三明"));
list.add(new User("莆田"));
list.add(new User("泉州"));
list.add(new User("怀远"));
list.add(new User("漳州"));
list.add(new User("龙岩"));
list.add(new User("兰州"));
list.add(new User("贵阳"));
list.add(new User("石家庄"));
list.add(new User("张三"));
list.add(new User("李四"));
list.add(new User("哈尔滨"));
list.add(new User("郑州"));
list.add(new User("武汉"));
list.add(new User("长沙"));
list.add(new User("长春"));
list.add(new User("南京"));
list.add(new User("南昌"));
list.add(new User("沈阳"));
list.add(new User("大连"));
Collections.sort(list); // 对list进行排序,需要让User实现Comparable接口重写compareTo方法
}
private void initView() {
list_friends = (ListView) findViewById(R.id.list_friends);
right_letter = (MyLetterView) findViewById(R.id.right_letter);
dialog = (TextView) findViewById(R.id.dialog);
right_letter.setTextDialog(dialog);
final FriendsAdapter adapter = new FriendsAdapter(list, this);
right_letter.setOnTouchingLetterChangedListener(new MyLetterView.OnTouchingLetterChangedListener() {
@Override
public void onTouchingLetterChanged(String s) {
// 该字母首次出现的位置
int position = adapter.getPositionForSection(s.charAt(0));
if (position != -1) {
list_friends.setSelection(position);
}
}
});
list_friends.setAdapter(adapter);
}
}
8、FriendsAdapter(适配器)
public class FriendsAdapter extends BaseAdapter {
ArrayList list;
Context context;
public FriendsAdapter(ArrayList list, Context context) {
this.list = list;
this.context = context;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if(convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.item_user_friend, null);
viewHolder = new ViewHolder();
viewHolder.name = (TextView) convertView.findViewById(R.id.tv_friend_name);
viewHolder.alpha = (TextView) convertView.findViewById(R.id.alpha);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
User friend = list.get(position);
viewHolder.name.setText(friend.getName());
// 根据position获取分类的首字母的Char ascii值
int section = getSectionForPosition(position);
// 如果当前位置等于该分类首字母的Char的位置 ,则认为是第一次出现
if (position == getPositionForSection(section)) {
viewHolder.alpha.setVisibility(View.VISIBLE);
viewHolder.alpha.setText(friend.getFirstLetter());
} else {
viewHolder.alpha.setVisibility(View.GONE);
}
return convertView;
}
static class ViewHolder {
TextView name;
TextView alpha;;
}
//判断当前位置是否是该位置对应的字母第一次出现
public int getPositionForSection(int section) {
for (int i = 0; i < getCount(); i++) {
String sortStr = list.get(i).getFirstLetter();
char firstChar = sortStr.toUpperCase().charAt(0);
if (section == firstChar) {
return i;
}
}
return -1;
}
/**
* 根据ListView的当前位置获取分类的首字母的Char ascii值
*/
private int getSectionForPosition(int position) {
return list.get(position).getFirstLetter().charAt(0);
}
}