一 :具体说下思路
1 :整体用到的控件,list view(recyclerView原理一样),自定义view,汉字转拼音的utils工具类.
2:MainActivity的xml简单就不说了,下面看代码,说下自定义View,首先自定义类继承View重写三个构造方法,重写
onMeasure()的方法用于测量View的宽高,onSizeChanged()方法改变当前控件大小的时候调用,onDarw()方法绘制View,
onTouchEvent()方法用于手势监听,自定义接口用于保存点击了那个字母的值。
3:数据实体类必须 实现Comparable<泛型为当前类名> 接口,用于获取汉字的首字母和字母排序。
4在list的Adaptes里面根据position的首字母来作为目录catalog。通过getPositionForSection(此方法为自定义的)方法,来获取catalog的首次出现的位置。如果当前位置(position)等于该分类首字母的Char的位置 ,则认为是第一次出现,则首字母显示,否则隐藏,此判断是为了避免出现相同的字母。
5:在接口回调的方法里面,遍历list集合(为数据集合).getFirstLetter()方法获取到集合的每条数据的首字母,和接口回传的字母通过equalsIgnoreCase(此方法用于和回传的字母匹配)方法匹配。成功list就掉用setSelection(i)定位到首字母出现的位置。
思路完毕,下面就贴代码:
二 代码实现:
1 MainActivity 的xml
android:layout_width="match_parent"
android:layout_height="match_parent"
">
android:id="@+id/mListView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toLeftOf="@+id/mYunFengView"
android:scrollbars="none">
android:id="@+id/mYunFengView"
android:layout_width="40dp"
android:layout_height="match_parent"
android:layout_alignParentRight="true" />
android:visibility="gone"
android:id="@+id/mDaZiMu2"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerInParent="true"
android:background="@drawable/dzm"
android:gravity="center"
android:text="A"
android:textSize="30dp" />
2 自定义VIew
package com.example.yangai00.yy_2018_6_29.mudel.home.chengshi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
/**
* Created by yangai00 on 2018/7/10.
*/
public class YunfengView extends View {
private String[] yuns = {"↑", "💗", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P"
, "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};
private Paint paint;
//初始化对象的时候调用
public YunfengView(Context context) {
super(context, null);
}
//在布局里面声明控件的时候调用
public YunfengView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs, 0);
init();
}
//在布局里面声明控件并用到styel的时候调用
public YunfengView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
//初始化
private void init() {
paint = new Paint();
paint.setColor(Color.BLACK);
paint.setTextSize(30);
}
//布局控件加载完成调用此方法
@Override
protected void onFinishInflate() {
super.onFinishInflate();
}
//测量View的宽高
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private float mWeight;
private float mHeight;
//改变当前控件大小的时候调用
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
//获取View的宽高
mWeight = getMeasuredWidth();
mHeight = getMeasuredHeight() / yuns.length;
super.onSizeChanged(w, h, oldw, oldh);
}
//View 的绘制
@Override
protected void onDraw(Canvas canvas) {
//循环绘制
for (int i = 0; i < yuns.length; i++) {
//字母的宽高
float x = mWeight / 2;
float y = (mHeight / 2) + DanQianKuan(yuns[i]) / 2 + i * mHeight;
paint.setColor(i == mId ? Color.BLUE : Color.BLACK);
canvas.drawText(yuns[i], x, y, paint);
}
//刷新View
invalidate();
super.onDraw(canvas);
}
private int mId = -1;
//手势监听
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
//滑动和点击
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
float Y = event.getY();
int id = (int) (Y / mHeight);
if (mId != id) {
String dqzf = yuns[id];
Log.e("点击", dqzf + "");
//接口方法保存点击或滑动的字母,用于回调
if (yunn != null) {
yunn.nunn(id, dqzf);
}
}
mId = id;
invalidate();//重新走OnDraw方法
break;
case MotionEvent.ACTION_UP:
mId = -1;
break;
}
return true;
}
//接口回调保存值
private Yunn yunn;
public interface Yunn {
void nunn(int pop, String zf);
}
public void getYunn(Yunn yunn) {
this.yunn = yunn;
}
//当前的宽度
private float DanQianKuan(String s) {
Rect rect = new Rect();
paint.getTextBounds(s, 0, 1, rect);
return rect.height();
}
}
3 MainActivity 主代码:
package com.example.yangai00.yy_2018_6_29.mudel.home.homeview.activity;
public class ChengShiActivity extends AppCompatActivity implements HomeContract.ChengShiView, View.OnClickListener {
private TextView mDaZiMu;
private ListView mListView;
private YunfengView mYunFengView;
private List list;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_cheng_shi);
//初始化
initView();
//获取数据
initData();
}
public void initData(){
//list1集合中的数据是网络请求,我就不粘贴了,你换成你自己的数据就可以,注意! 实体类有汉字转拼音的方法,不要覆盖了。
for (int i = 0; i < list1.size(); i++) {
list.add(new User(list1.get(i).getCity_name()));
}
//适配器
myAdaptesList = new MyAdaptes_list(list, this);
mListView.setAdapter(myAdaptesList);
//自定义接口
mYunFengView.getYunn(new YunfengView.Yunn() {
@Override public void nunn(int pop, String zf) {
for (int i = 0; i < list.size(); i++) {
//获取到list集合中的每一个条目的首字母和接口传回来的进行匹配,成功就定位到listview对应的item。
if (zf.equalsIgnoreCase(list.get(i).getFirstLetter())) {
mListView.setSelection(i); // 选择到首字母出现的位置 return;
}
}
msetText(zf);
}
});
mDaZiMu.setVisibility(View.GONE);
}
}
//通过hander来让土司的字母延迟2秒消失。
Handler handler = new Handler();
private void msetText(String s) {
mDaZiMu.setText(s);
mDaZiMu.setVisibility(View.VISIBLE);
handler.postDelayed(new Runnable() {
@Override
public void run() {
mDaZiMu.setVisibility(View.GONE);
}
}, 2000);
}
//初始化
private void initView() {
mListView = (ListView) findViewById(R.id.mListView);
mYunFengView = findViewById(R.id.mYunFengView);
mDaZiMu = findViewById(R.id.mDaZiMu2);
}
}
4 适配器
package com.example.yangai00.yy_2018_6_29.mudel.home.chengshi.adaptes;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import com.example.yangai00.yy_2018_6_29.R;
import com.example.yangai00.yy_2018_6_29.mudel.home.homeentity.MyChengShiBen;
import com.example.yangai00.yy_2018_6_29.mudel.home.homeentity.MyZhuanHuan;
import com.example.yangai00.yy_2018_6_29.mudel.home.homeentity.User;
import java.util.ArrayList;
import java.util.List;
/**
* Created by yangai00 on 2018/7/10.
*/
public class MyAdaptes_list extends BaseAdapter {
private List list;
private Context context;
public MyAdaptes_list(List 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 position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
User user = list.get(position);
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = LayoutInflater.from(context).inflate(R.layout.my_chengshilist, null);
holder.mDingWeiText1 = (TextView) convertView.findViewById(R.id.mZiMuList);
holder.mDingWeiText2 = (TextView) convertView.findViewById(R.id.mNameList);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
//根据position获取首字母作为目录catalog
String catalog = list.get(position).getFirstLetter();
//如果当前位置等于该分类首字母的Char的位置 ,则认为是第一次出现,第一次出现显示,其他的隐藏
if (position == getPositionForSection(catalog)) {
holder.mDingWeiText1.setVisibility(View.VISIBLE);
holder.mDingWeiText1.setText(user.getFirstLetter().toUpperCase());
} else {
holder.mDingWeiText1.setVisibility(View.GONE);
}
//赋值给Textview
holder.mDingWeiText2.setText(this.list.get(position).getName());
return convertView;
}
private class ViewHolder {
private TextView mDingWeiText1;
private TextView mDingWeiText2;
}
/**
* 获取catalog首次出现位置
*/
public int getPositionForSection(String catalog) {
for (int i = 0; i < getCount(); i++) {
String sortStr = list.get(i).getFirstLetter();
if (catalog.equalsIgnoreCase(sortStr)) {
return i;
}
}
return -1;
}
}
5 适配器引入的xml布局
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
android:id="@+id/mZiMuList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#E0E0E0"
android:padding="10dp"
android:text="A"
android:textColor="#FF2A2A2D"
android:textSize="20sp" />
android:id="@+id/mNameList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:padding="10dp"
android:text="云哥哥"
android:textColor="#FF4859ED"
android:textSize="16sp" />
6 汉字转拼音的工具类:
package com.example.yangai00.yy_2018_6_29.mudel.home.homeentity;
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 yangai00 on 2018/7/10.
*/
public class MyZhuanHuan {
public static StringBuffer sb = new StringBuffer();
/**
* 获取汉字字符串的首字母,英文字符不变
* 例如:云哥哥→ygg
*/
public static String getPinYinHeadChar(String chines) {
sb.setLength(0);
char[] chars = chines.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 {
sb.append(PinyinHelper.toHanyuPinyinStringArray(chars[i], defaultFormat)[0].charAt(0));
} catch (Exception e) {
e.printStackTrace();
}
} else {
sb.append(chars[i]);
}
}
return sb.toString();
}
/**
* 获取汉字字符串的第一个字母
*/
public static String getPinYinFirstLetter(String str) {
sb.setLength(0);
char c = str.charAt(0);
String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(c);
if (pinyinArray != null) {
sb.append(pinyinArray[0].charAt(0));
} else {
sb.append(c);
}
return sb.toString();
}
/**
* 获取汉字字符串的汉语拼音,英文字符不变
*/
public static String getPinYin(String chines) {
sb.setLength(0);
char[] nameChar = chines.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 {
sb.append(PinyinHelper.toHanyuPinyinStringArray(nameChar[i], defaultFormat)[0]);
} catch (Exception e) {
e.printStackTrace();
}
} else {
sb.append(nameChar[i]);
}
}
return sb.toString();
}
}
7 实体类:
package com.example.yangai00.yy_2018_6_29.mudel.home.homeentity;
/**
* Created by yangai00 on 2018/7/11.
*/
public class User implements Comparable {
private String name; // 姓名
private String pinyin; // 姓名对应的拼音
private String firstLetter; // 拼音的首字母
public User() {
}
public User(String name) {
this.name = name;
//MyZhuanHuan类,是汉字转拼音的工具类
pinyin = MyZhuanHuan.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());
}
}
}
到此代码完毕。