Android 侧边字母索引栏

这篇写下常用的类似通讯录似得效果    右边自定义一个sidebar  左边使用listview实现

1、自定义SideBar 

①重写onDraw     计算每个字母所占的高度  就是整体的高度除以要画的字母的个数,所以每个字母的高为依次叠加

因为竖行排列,所以每个字母的宽都一样,每个字母的x为整体的宽度减去该字母的宽度的一半

②重写触摸事件  拿到触摸的y除以总的高度 然后乘以所有字母的个数  就可以拿到点击的是第几个字母,如果该字母改变则进行重绘

③设置回调  点击该字母具体方法由外界实现

public class SideBar extends View {
    // 触摸事件
    private OnTouchingLetterChangedListener onTouchingLetterChangedListener;
    // 26个字母
    public static String[] b = {"☆", "#", "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 float size;
    private int choose = -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);
        init(context);
    }

    public SideBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public SideBar(Context context) {
        super(context);
        init(context);
    }

    private void init(Context context) {
        size = DeviceUtil.dip2px(context, 13);
    }

    /**
     * 重写这个方法
     */
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 获取焦点改变背景颜色.
        int height = getHeight();// 获取对应高度
        int width = getWidth(); // 获取对应宽度
        int singleHeight = height / b.length;// 获取每一个字母的高度

        for (int i = 0; i < b.length; i++) {
            if (!isInEditMode()) {
                paint.setColor(Color.parseColor("#838383"));
            }
            //设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢。
            paint.setAntiAlias(true);
            paint.setTextSize(size);
            // 选中的状态
            if (i == choose) {
                paint.setColor(getResources().getColor(R.color.yellow_light));
                paint.setFakeBoldText(true); //true为粗体,false为非粗体
            }
            // x坐标等于中间-字符串宽度的一半.
            float xPos = width / 2 - paint.measureText(b[i]) / 2;
            float yPos = singleHeight * i + singleHeight;
            canvas.drawText(b[i], xPos, yPos, paint);
            paint.reset();// 重置画笔
        }

    }

    @SuppressWarnings("deprecation")
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        final int action = event.getAction();
        final float y = event.getY();// 点击y坐标
        final int oldChoose = choose;
        final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener;
        final int c = (int) (y / getHeight() * b.length);// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数.

        switch (action) {
            case MotionEvent.ACTION_UP:
                setBackgroundDrawable(new ColorDrawable(0x00000000));
                choose = -1;//
                invalidate();
                if (mTextDialog != null) {
                    mTextDialog.setVisibility(View.INVISIBLE);
                }
                break;

            default:
                if (oldChoose != c) {
                    if (c >= 0 && c < b.length) {
                        if (listener != null) {
                            listener.onTouchingLetterChanged(b[c]);
                        }
                        if (mTextDialog != null) {
                            mTextDialog.setText(b[c]);
                            mTextDialog.setVisibility(View.VISIBLE);
                        }

                        choose = c;
                        invalidate();
                    }
                }

                break;
        }
        return true;
    }

    /**
     * 向外公开的方法
     *
     * @param onTouchingLetterChangedListener
     */
    public void setOnTouchingLetterChangedListener(OnTouchingLetterChangedListener onTouchingLetterChangedListener) {
        this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;
    }

    /**
     * 接口
     *
     * @author coder
     */
    public interface OnTouchingLetterChangedListener {
        public void onTouchingLetterChanged(String s);
    }

}

2、准备好汉字转拼音的工具类

  ①将jar包丢到libs目录下

     

  ②  汉字转拼音工具类

public class PinYinUtil {
    /**
     * 获取汉字的拼音
     * @param chinese
     * @return
     */
    public static String getPinYin(String chinese){
        if(TextUtils.isEmpty(chinese))return null;

        //输出的格式化对象,用来决定输出字母的大小写,是否带有音标之类
        HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
        format.setCaseType(HanyuPinyinCaseType.UPPERCASE);//设置大写字母
        format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);//设置不带有音汉字进行获取,所以要将字符串转为字符数组,一个一个获取,最后拼接
        StringBuilder builder = new StringBuilder();
        char[] chars = chinese.toCharArray();

        for (int i = 0; i < chars.length; i++) {
            char c = chars[i];
            //1.过滤空格
            if(Character.isWhitespace(c)){
                //如果是空格,则忽略即可
                continue;
            }

            //2.简单判断是否是汉字:一个字节范围是-128~127,所以汉字一定大于127
            if(c > 127){
                //说明有可能是汉字,那么利用Pinyin4j的api进行获取
                try {
                    //由于多音字的存在,返回的是数组,比如:单: {dan, chan ,shan}
                    String[] pinyinArr = PinyinHelper.toHanyuPinyinStringArray(c, format);
                    if(pinyinArr!=null){
                        //问题来了:取哪个拼音?答:暂时只能取第1个
                        //为啥呢?:首先大部分汉字只有一个读音,对于多音字的情况,由于我们实在无能为力去
                        //判断它的真实读音,也只能取第1个罢了。
                        builder.append(pinyinArr[0]);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    //如果异常,说明不是正确的汉字,直接忽略
                }
            }else {
                //说明肯定不是汉字,一般是英文字母,我们选择直接拼接
                builder.append(c);
            }

        }

        return builder.toString();
    }
}

3、将数据放到listview上展示

     ①布局如下        

<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ListView
        android:id="@+id/school_friend_member"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:cacheColorHint="@android:color/transparent"
        android:divider="@mipmap/bg_cut_line"
        android:dividerHeight="1px"
        android:fadingEdge="none"
        android:listSelector="@android:color/transparent"
        android:scrollbars="none"></ListView>

    <TextView
        android:id="@+id/school_friend_dialog"
        android:layout_width="80.0dip"
        android:layout_height="80.0dip"
        android:layout_gravity="center"
        android:background="@drawable/bg_show_head_toast"
        android:gravity="center"
        android:textColor="#ffffffff"
        android:textSize="30.0dip"
        android:visibility="invisible" />

    <com.hiteamtech.ddbes.ui.view.SideBar
        android:id="@+id/school_friend_sidrbar"
        android:layout_width="30dp"
        android:layout_height="match_parent"
        android:layout_gravity="right|center" />
</FrameLayout>

②初始化各个类

mListView = (ListView) findViewById(R.id.school_friend_member);
mSideBar = (SideBar) findViewById(R.id.school_friend_sidrbar);
mDialog = (TextView) findViewById(R.id.school_friend_dialog);
mSideBar.setOnTouchingLetterChangedListener(this);

mSideBar.setTextView(mDialog);

③给获取到的集合排序   

Collections.sort(complete, new Comparator<UserBean>() {
   @Override
   public int compare(UserBean o1, AUserBean o2) {
      String pinying1;
      String pinying2;
      if(o1.getAssetname()!=null){
         pinying1= PinYinUtil.getPinYin(o1.getUserName());
      }else{
         pinying1= PinYinUtil.getPinYin("z");
      }
      if(o2.getAssetname()!=null){
         pinying2= PinYinUtil.getPinYin(o2.getUserName());
      }else{
         pinying2=PinYinUtil.getPinYin("z");
      }
      return pinying1.compareTo(pinying2);
   }
});

④给listview设置adapter

adapter如下:

public class InviteFriendListAdapter extends BaseAdapter implements SectionIndexer {

    private LayoutInflater inflater;

    private Context mContext;

    private List<UserBean> list;

    public InviteFriendListAdapter(Context context, List<UserBean> list) {
        this.mContext = context;
        this.list = list;
    }

    /**
     * 当ListView数据发生变化时,调用此方法来更新ListView
     *
     * @param list
     */
    public void updateListView(List<UserBean> list) {
        this.list = list;
        notifyDataSetChanged();
    }

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

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

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
//            inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            inflater = LayoutInflater.from(mContext);
            convertView = inflater.inflate(R.layout.invitation_friends_item_layout, null);
            holder = new ViewHolder();
            holder.ivHead = (CircleImageView) convertView.findViewById(R.id.head);
            holder.tvTitle = (TextView) convertView.findViewById(R.id.title);
            holder.tvLetter = (TextView) convertView.findViewById(R.id.catalog);
            holder.tvLine = (TextView) convertView.findViewById(R.id.line);
            holder.checkFriendCb = (CheckBox) convertView.findViewById(R.id.checkFriendCb);
            holder.tvContent = (LinearLayout) convertView.findViewById(R.id.content);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        final UserBean phoneContactBean = list.get(position);

        if (phoneContactBean != null) {
            // 根据position获取分类的首字母的Char ascii值
            int section = getSectionForPosition(position);
            // 如果当前位置等于该分类首字母的Char的位置 ,则认为是第一次出现
            if (position == getPositionForSection(section)) {
                holder.tvLetter.setVisibility(View.VISIBLE);
                holder.tvLetter.setText("☆".equals(phoneContactBean.getSortLetters()) ? phoneContactBean.getSortLetters() + "(管理员)" : phoneContactBean.getSortLetters());
                holder.tvLine.setVisibility(View.VISIBLE);
            } else {
                holder.tvLetter.setVisibility(View.GONE);
                holder.tvLine.setVisibility(View.GONE);
            }
            holder.tvTitle.setText(phoneContactBean.getUserName());
            if (phoneContactBean.isChecked()) {
                holder.checkFriendCb.setChecked(true);
            } else {
                holder.checkFriendCb.setChecked(false);
            }
            Glide.with(mContext).load(phoneContactBean.getHeadimg()).asBitmap().error(R.mipmap.headimg_default).into(holder.ivHead);
            holder.tvContent.setOnClickListener(new OnCheckFriendClick(phoneContactBean));
        }
        return convertView;
    }

    private class OnCheckFriendClick implements View.OnClickListener {

        private UserBean userBean;

        public OnCheckFriendClick(UserBean userBean) {
            this.userBean = userBean;
        }

        @Override
        public void onClick(View v) {
            if (userBean.isChecked()) {
                userBean.setChecked(false);
            } else {
                userBean.setChecked(true);
            }
            notifyDataSetChanged();
        }
    }

    class ViewHolder {
        CircleImageView ivHead;
        TextView tvLetter;
        TextView tvTitle;
        TextView tvLine;
        CheckBox checkFriendCb;
        LinearLayout tvContent;
    }

    /**
     * 根据ListView的当前位置获取分类的首字母的Char ascii值
     */
    public int getSectionForPosition(int position) {
        return list.get(position).getSortLetters().charAt(0);
    }

    /**
     * 根据分类的首字母的Char ascii值获取其第一次出现该首字母的位置
     */
    public int getPositionForSection(int section) {
        for (int i = 0; i < getCount(); i++) {
            String sortStr = list.get(i).getSortLetters();
            char firstChar = sortStr.toUpperCase().charAt(0);
            if (firstChar == section) {
                return i;
            }
        }
        return -1;
    }

    @Override
    public Object[] getSections() {
        return null;
    }

    public List<UserBean> getList() {
        return list;
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_38811767/article/details/81484312