android 自定义view,字母排序(仿微信好友列表)

一:简言

一个月没有写博客了,公司项目比较忙,最近发现公司用到一个知识点,所以抽时间通过博客的形式分享给大家,该知识点,模仿微信的好友列表,通过字母索引进行定位,该功能主要通过几个知识点实现。下面会一一讲解。

二:具体说下思路

  • 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;
    }

    @Override
    public 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 shan
                    String[] 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);
    }

    /**
     * 测量方法
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        itemWidth = getMeasuredWidth();
        itemHeight = getMeasuredHeight() / words.length;
    }

    @Override
    protected 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);
        }
    }

    @Override
    public 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;
    @Override
    protected 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() {
            /**
             * 回传是字母
             * */
            @Override
            public 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-->Y
            if (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() {
            @Override
            public 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>() {
            @Override
            public int compare(Person o1, Person o2) {

                return o1.getPinyin().compareTo(o2.getPinyin());
            }
        });
    }

    class  IndexAdapter extends BaseAdapter{

        @Override
        public int getCount() {
            return persons.size();
        }

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public 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->A
            viewHolder.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~Z
                if(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"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.zzsy.quickindex.MainActivity">
    <ListView
        android:id="@+id/lv_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
        <TextView
            android: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.IndexView
        android: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="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <TextView
        android: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" />

    <TextView
        android: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包地址:

https://download.csdn.net/download/wk_beicai/11635244

发布了96 篇原创文章 · 获赞 370 · 访问量 42万+

猜你喜欢

转载自blog.csdn.net/wk_beicai/article/details/100130202
今日推荐