一:简言
一个月没有写博客了,公司项目比较忙,最近发现公司用到一个知识点,所以抽时间通过博客的形式分享给大家,该知识点,模仿微信的好友列表,通过字母索引进行定位,该功能主要通过几个知识点实现。下面会一一讲解。
二:具体说下思路
1 :整体用到的控件,list view(recyclerView原理一样),自定义view,汉字转拼音的utils工具类.2:创建一个自定义类继承view,实现侧面滑动字母显示字母索引数据,说下自定义View,首先自定义类继承View重写三个构造方法,重写onMeasure()的方法用于测量View的宽高,onSizeChanged()方法改变当前控件大小的时候调用,onDarw()方法绘制View,onTouchEvent()方法用于手势监听,自定义接口用于保存点击了那个字母的值。3:创建一个person的实体bean,实现列表数据的展示,4。通过将汉字通过拼音的形式进行分类,添加一个pinyinj-2.5.0.jar,实现转换,(稍后代码会详细介绍)。5:将数据显示出来,实现效果;
三:实现效果
四:通过代码的形式介绍步骤:
1)首先实现实体bean(Person)
public class Person {private String name;private String pinyin;public Person(String name){this.name = name;this.pinyin = PinYinUtils.getPinYin(name);}public String getPinyin() {return pinyin;}public void setPinyin(String pinyin) {this.pinyin = pinyin;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", pinyin='" + pinyin + '\'' +'}';}}
该类没有讲解的必要,直接刀币下一个类:
2)拼音转换工具类(PinYinUtils)
首先添加这个jar包(稍后分享)
然后创建该类(代码如下)
public class PinYinUtils {/*** 得到指定汉字的拼音* 注意:不应该被频繁调用,它消耗一定内存* @param hanzi* @return*/public static String getPinYin(String hanzi){String pinyin = "";HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();//控制转换是否大小写,是否带音标format.setCaseType(HanyuPinyinCaseType.UPPERCASE);//大写format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);//由于不能直接对多个汉字转换,只能对单个汉字转换char[] arr = hanzi.toCharArray();for (int i = 0; i < arr.length; i++) {if(Character.isWhitespace(arr[i]))continue;//如果是空格,则不处理,进行下次遍历//汉字是2个字节存储,肯定大于127,所以大于127就可以当为汉字转换if(arr[i]>127){try {//由于多音字的存在,单 dan shanString[] pinyinArr = PinyinHelper.toHanyuPinyinStringArray(arr[i], format);if(pinyinArr!=null){pinyin += pinyinArr[0];}else {pinyin += arr[i];}} catch (BadHanyuPinyinOutputFormatCombination e) {e.printStackTrace();//不是正确的汉字pinyin += arr[i];}}else {//不是汉字,pinyin += arr[i];}}return pinyin;}}
3)重点来了,主要实现的功能,自定义view(IndexView)
/*** Created by wk先森* 快速索引* 绘制快速索引的字母* 1.二十六个字母 放入集合中* 2.在onMeaus中计算每条的宽和高 itemHeight itemWidth wordHeight wordX wordY* <p>* 手指按下 文字变色* 重写onTouchEvent方法 返回true* 在Down和move中 计算* int touchIndex = Y/itemHeight 强制绘制* <p>* 2.在onDraw方法对于该下包画笔变色* <p>* 3。在Up的时候 touchIndex = -1;* 强制绘制*/public class IndexView extends View {/*** 每条的宽和高*/private int itemWidth;private int itemHeight;Paint paint;private String[] words = {"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 touchIndex = -1;public IndexView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);initView(context);}private void initView(Context context) {paint = new Paint();paint.setColor(Color.BLACK);//设置颜色paint.setAntiAlias(true);paint.setTypeface(Typeface.DEFAULT_BOLD);}/*** 测量方法*/@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);itemWidth = getMeasuredWidth();itemHeight = getMeasuredHeight() / words.length;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);for (int i = 0; i < words.length; i++) {if(touchIndex == i){//设置灰色paint.setColor(Color.GRAY);}else{//设置白色paint.setColor(Color.BLACK);}String word = words[i];Rect rect = new Rect();//0,1 取一个字母paint.getTextBounds(word, 0, 1, rect);int wordWidth = rect.width();int wordHeight = rect.height();//计算每个字母在视图上的坐标float wordX = itemWidth / 2 - wordWidth / 2;float wordY = itemHeight / 2 + wordHeight / 2 + i * itemHeight;canvas.drawText(word, wordX, wordY, paint);}}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:break;case MotionEvent.ACTION_MOVE:float Y= event.getY();int index = (int) (Y/itemHeight);//字母的索引if(index != touchIndex){touchIndex = index;//强制绘制 onDraw();invalidate();if(onIndexChangeListener != null && touchIndex<words.length){onIndexChangeListener.OnIndexChange(words[touchIndex]);}}break;case MotionEvent.ACTION_UP :touchIndex = -1;invalidate();break;}return true;}/*** 字母下标索引变化监听器* */public interface OnIndexChangeListener{/*** 挡字幕下标位置发生变化时候回调* */void OnIndexChange(String word);}private OnIndexChangeListener onIndexChangeListener;public void setOnIndexChangeListener(OnIndexChangeListener onIndexChangeListener) {this.onIndexChangeListener = onIndexChangeListener;}}
5)通过activity实现该功能(MainActivity)
该类需要关注的点:
Toast显示的时间
public class MainActivity extends AppCompatActivity {private ListView lvMain;private TextView tvWord;private IndexView ivWords;private Handler handler = new Handler();/*** 联系人的集合*/private ArrayList<Person> persons;private IndexAdapter adapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();}private void initView() {lvMain = findViewById(R.id.lv_main);tvWord = findViewById(R.id.tv_word);ivWords = findViewById(R.id.iv_words);//设置监听字母下标索引变化ivWords.setOnIndexChangeListener(new IndexView.OnIndexChangeListener() {/*** 回传是字母* */@Overridepublic void OnIndexChange(String word) {updateWord(word);updateListView(word);//A~Z}});initData();adapter = new IndexAdapter();lvMain.setAdapter(adapter);}private void updateListView(String word) {for(int i=0;i<persons.size();i++){String listWord = persons.get(i).getPinyin().substring(0,1);//YANGGUANGFU-->Yif (word.equals(listWord)) {//i是listView中的位置lvMain.setSelection(i);//定位到ListVeiw中的某个位置return;}}}private void updateWord(String word){//显示tvWord.setVisibility(View.VISIBLE);tvWord.setText(word);handler.removeCallbacksAndMessages(null);handler.postDelayed(new Runnable() {@Overridepublic void run() {//也是运行在主线程中tvWord.setVisibility(View.GONE);}},500);}/*** 初始化数据*/private void initData() {persons = new ArrayList<>();persons.add(new Person("张晓飞"));persons.add(new Person("杨光福"));persons.add(new Person("胡继群"));persons.add(new Person("刘畅"));persons.add(new Person("钟泽兴"));persons.add(new Person("尹革新"));persons.add(new Person("安传鑫"));persons.add(new Person("张骞壬"));persons.add(new Person("温松"));persons.add(new Person("李凤秋"));persons.add(new Person("刘甫"));persons.add(new Person("娄全超"));persons.add(new Person("张猛"));persons.add(new Person("王英杰"));persons.add(new Person("李振南"));persons.add(new Person("孙仁政"));persons.add(new Person("唐春雷"));persons.add(new Person("牛鹏伟"));persons.add(new Person("姜宇航"));persons.add(new Person("刘挺"));persons.add(new Person("张洪瑞"));persons.add(new Person("张建忠"));persons.add(new Person("侯亚帅"));persons.add(new Person("刘帅"));persons.add(new Person("乔竞飞"));persons.add(new Person("徐雨健"));persons.add(new Person("吴亮"));persons.add(new Person("王兆霖"));persons.add(new Person("阿三"));persons.add(new Person("李博俊"));//排序Collections.sort(persons, new Comparator<Person>() {@Overridepublic int compare(Person o1, Person o2) {return o1.getPinyin().compareTo(o2.getPinyin());}});}class IndexAdapter extends BaseAdapter{@Overridepublic int getCount() {return persons.size();}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {return 0;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder viewHolder;if(convertView == null){convertView = View.inflate(MainActivity.this,R.layout.item_main,null);viewHolder = new ViewHolder();viewHolder.tv_word = convertView.findViewById(R.id.tv_word);viewHolder.tv_name = convertView.findViewById(R.id.tv_name);convertView.setTag(viewHolder);}else{viewHolder = (ViewHolder) convertView.getTag();}String name = persons.get(position).getName();//阿福String word = persons.get(position).getPinyin().substring(0,1);//AFU->AviewHolder.tv_word.setText(word);viewHolder.tv_name.setText(name);if(position ==0){viewHolder.tv_word.setVisibility(View.VISIBLE);}else{//得到前一个位置对应的字母,如果当前的字母和上一个相同,隐藏;否则就显示String preWord = persons.get(position-1).getPinyin().substring(0,1);//A~Zif(word.equals(preWord)){viewHolder.tv_word.setVisibility(View.GONE);}else{viewHolder.tv_word.setVisibility(View.VISIBLE);}}return convertView;}}static class ViewHolder{TextView tv_word;TextView tv_name;}}
到这里功能可以说已经介绍完了。把剩下的xml文件赠送给大家
<?xml version="1.0" encoding="utf-8"?><RelativeLayoutxmlns:android="/apk/res/android"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.zzsy.quickindex.MainActivity"><ListViewandroid:id="@+id/lv_main"android:layout_width="match_parent"android:layout_height="match_parent"/><TextViewandroid:id="@+id/tv_word"android:visibility="gone"android:layout_centerInParent="true"android:layout_width="80dp"android:layout_height="80dp"android:gravity="center"android:background="#44000000"android:textColor="#000000"android:text="A"android:textSize="30sp"android:textStyle="bold"/><com.zzsy.quickindex.IndexViewandroid:id="@+id/iv_words"android:layout_width="35dp"android:layout_height="match_parent"android:layout_alignParentEnd="true"android:layout_alignParentRight="true"android:layout_alignParentTop="true"android:background="#10000000" /></RelativeLayout>
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><TextViewandroid:id="@+id/tv_word"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="#22000000"android:text="A"android:paddingLeft="5dp"android:textColor="#000000"android:textSize="25sp" /><TextViewandroid:id="@+id/tv_name"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="阿福"android:padding="5dp"android:textColor="#dd000000"android:textSize="22sp" /></LinearLayout>
上面的xml文件分别是main,item_main
五。jar包地址:
/download/wk_beicai/11635244