Android之快速索引导航栏,联系人字母排序侧边栏sidebar开发

生活中,常常遇到这样一个Android功能,联系人按照字母排序,于是乎,爱搞事情的鄙人,也做了一个这样一个功能,以下是代码笔记。

首先,咱得导入三方包,我日,本人较懒,我看到网上很多都用sidebar ,原本以为是一个第三方包,但找来找去就是没有,那干脆照着网上说的写一个工具类吧。

SideBar.class
public class SideBar extends View {

        private static final String TAG = SideBar.class.getSimpleName();

        public interface OnTouchingLetterChangedListener {
            void onTouchingLetterChanged(String s);
        }

        private OnTouchingLetterChangedListener mOnTouchingLetterChangedListener;

        private String[] mLetters = null;
        private Paint mPaint;
        private int mTextColor;
        private int mResArrayId = R.array.letter_list;

        private int mChoose = -1;

        private final float mDensity;
        private float mY;
        private float mHalfWidth, mHalfHeight;
        private float mLetterHeight;
        private float mAnimStep;

        private int mTouchSlop;
        private float mInitialDownY;
        private boolean mIsBeingDragged, mStartEndAnim;
        private int mActivePointerId = INVALID_POINTER;

        private RectF mIsDownRect = new RectF();

        public SideBar(Context context) {
            this(context, null);
        }

        public SideBar(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }

        public SideBar(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            this.mPaint = new Paint();
            this.mTextColor = Color.GRAY;
            this.mPaint.setAntiAlias(true);
            this.mPaint.setTextAlign(Paint.Align.CENTER);
            this.mPaint.setColor(this.mTextColor);

            this.mLetters = context.getResources().getStringArray(mResArrayId);

            mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
            mDensity = getContext().getResources().getDisplayMetrics().density;

            setPadding(0, dip2px(20), 0, dip2px(20));
        }

        public void setOnTouchingLetterChangedListener(OnTouchingLetterChangedListener listener) {
            this.mOnTouchingLetterChangedListener = listener;
        }

        private int getLettersSize() {
            return mLetters.length;
        }

        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            final int action = MotionEventCompat.getActionMasked(ev);
            switch (action) {
                case MotionEvent.ACTION_DOWN:
                    mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
                    mIsBeingDragged = false;
                    final float initialDownY = getMotionEventY(ev, mActivePointerId);
                    if (initialDownY == -1) {
                        return false;
                    }
                    if (!mIsDownRect.contains(ev.getX(), ev.getY())) {
                        return false;
                    }
                    mInitialDownY = initialDownY;
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (mActivePointerId == INVALID_POINTER) {
                        return false;
                    }

                    final float y = getMotionEventY(ev, mActivePointerId);
                    if (y == -1) {
                        return false;
                    }
                    final float yDiff = Math.abs(y - mInitialDownY);
                    if (yDiff > mTouchSlop && !mIsBeingDragged) {
                        mIsBeingDragged = true;
                    }
                    if (mIsBeingDragged) {
                        mY = y;
                        final float moveY = y - getPaddingTop() - mLetterHeight / 1.64f;
                        final int characterIndex = (int) (moveY / mHalfHeight * mLetters.length);
                        if (mChoose != characterIndex) {
                            if (characterIndex >= 0 && characterIndex < mLetters.length) {
                                mChoose = characterIndex;
                                Log.d(TAG, "mChoose " + mChoose + " mLetterHeight " + mLetterHeight);
                                mOnTouchingLetterChangedListener.onTouchingLetterChanged(mLetters[characterIndex]);
                            }
                        }
                        invalidate();
                    }
                    break;
                case MotionEventCompat.ACTION_POINTER_UP:
                    onSecondaryPointerUp(ev);
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    if (mOnTouchingLetterChangedListener != null) {
                        if (mIsBeingDragged) {
                            mOnTouchingLetterChangedListener.onTouchingLetterChanged(mLetters[mChoose]);
                        } else {
                            float downY = ev.getY() - getPaddingTop();
                            final int characterIndex = (int) (downY / mHalfHeight * mLetters.length);
                            if (characterIndex >= 0 && characterIndex < mLetters.length) {
                                mOnTouchingLetterChangedListener.onTouchingLetterChanged(mLetters[characterIndex]);
                            }
                        }
                    }
                    mStartEndAnim = mIsBeingDragged;
                    mIsBeingDragged = false;
                    mActivePointerId = INVALID_POINTER;

                    mChoose = -1;
                    mAnimStep = 0f;
                    invalidate();
                    return false;
            }
            return true;
        }

        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            mHalfWidth = w - dip2px(16);
            mHalfHeight = h - getPaddingTop() - getPaddingBottom();

            float lettersLen = getLettersSize();

            mLetterHeight = mHalfHeight / lettersLen;
            int textSize = (int) (mHalfHeight * 0.7f / lettersLen);
            this.mPaint.setTextSize(textSize);

            mIsDownRect.set(w - dip2px(16 * 2), 0, w, h);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            for (int i = 0; i < getLettersSize(); i++) {
                float letterPosY = mLetterHeight * (i + 1) + getPaddingTop();
                float diff, diffY, diffX;
                if (mChoose == i && i != 0 && i != getLettersSize() - 1) {
                    diffX = 0f;
                    diffY = 0f;
                    diff = 2.16f;
                } else {
                    float maxPos = Math.abs((mY - letterPosY) / mHalfHeight * 7f);
                    diff = Math.max(1f, 2.2f - maxPos);
                    if (mStartEndAnim && diff != 1f) {
                        diff -= mAnimStep;
                        if (diff <= 1f) {
                            diff = 1f;
                        }
                    } else if (!mIsBeingDragged) {
                        diff = 1f;
                    }
                    diffY = maxPos * 50f * (letterPosY >= mY ? -1 : 1);
                    diffX = maxPos * 100f;
                }
                canvas.save();
                canvas.scale(diff, diff, mHalfWidth * 1.20f + diffX, letterPosY + diffY);
                if (diff == 1f) {
                    this.mPaint.setAlpha(255);
                    this.mPaint.setTypeface(Typeface.DEFAULT);
                } else {
                    int alpha = (int) (255 * (1 - Math.min(0.9, diff - 1)));
                    if (mChoose == i)
                        alpha = 255;
                    this.mPaint.setAlpha(alpha);
                    this.mPaint.setTypeface(Typeface.DEFAULT_BOLD);
                }
                canvas.drawText(mLetters[i], mHalfWidth, letterPosY, this.mPaint);
                canvas.restore();
            }
            if (mChoose == -1 && mStartEndAnim && mAnimStep <= 0.6f) {
                mAnimStep += 0.6f;
                postInvalidateDelayed(25);
            } else {
                mAnimStep = 0f;
                mStartEndAnim = false;
            }
        }

        private int dip2px(int dipValue) {
            return (int) (dipValue * mDensity + 0.5f);
        }

        private float getMotionEventY(MotionEvent ev, int activePointerId) {
            final int index = MotionEventCompat.findPointerIndex(ev, activePointerId);
            if (index < 0) {
                return -1;
            }
            return MotionEventCompat.getY(ev, index);
        }

        private void onSecondaryPointerUp(MotionEvent ev) {
            final int pointerIndex = MotionEventCompat.getActionIndex(ev);
            final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
            if (pointerId == mActivePointerId) {
                final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
            }
        }
}

以上的类直接拿来用吧,孰能生巧,慢慢就理解这是啥玩意了,哦对了,还得给他一个A~#的属性值


    
     
        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
        Y
        Z
        \#
    

接下来,咱把布局给加上,我用的是recycleview,推荐用这个,炒鸡好用,下次得写个recycleview的用法了



    
    
    
    
        
    


此外还要考虑汉字转拼音

cn2spell.class


    
public class Cn2Spell {

    public static StringBuffer sb = new StringBuffer();

    /**
     * 获取汉字字符串的首字母,英文字符不变
     * 例如:阿飞→af
     */
    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();
    }
接下来就是修改model类了,注意:修改model类,在需要添加所以的具体model类下面,添加一下代码,(有的情况是model下面还有model,讨厌~~嘤嘤嘤)
public class model {
    public static class YcTeacherBean {
        private String id;
        private String yc_allow_address;
        private String yc_allow_class;
        private String yc_allow_qrcode;
        private String yc_avatar;
        private int yc_delete;
        private int yc_gender;
        private int yc_id;
        private String yc_nickname;
        private String yc_phone;
        private int yc_role;
        private String yc_rongcloudtoken;
        private String yc_status;
        private String yc_token;
        private String yc_user_token;
        private String yc_username;
        private String yc_video_name;
        private String firstLetter;
        private String pinYin;

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getYc_allow_address() {
            return yc_allow_address;
        }

        public void setYc_allow_address(String yc_allow_address) {
            this.yc_allow_address = yc_allow_address;
        }

        public String getYc_allow_class() {
            return yc_allow_class;
        }

        public void setYc_allow_class(String yc_allow_class) {
            this.yc_allow_class = yc_allow_class;
        }

        public String getYc_allow_qrcode() {
            return yc_allow_qrcode;
        }

        public void setYc_allow_qrcode(String yc_allow_qrcode) {
            this.yc_allow_qrcode = yc_allow_qrcode;
        }

        public String getYc_avatar() {
            return yc_avatar;
        }

        public void setYc_avatar(String yc_avatar) {
            this.yc_avatar = yc_avatar;
        }

        public int getYc_delete() {
            return yc_delete;
        }

        public void setYc_delete(int yc_delete) {
            this.yc_delete = yc_delete;
        }

        public int getYc_gender() {
            return yc_gender;
        }

        public void setYc_gender(int yc_gender) {
            this.yc_gender = yc_gender;
        }

        public int getYc_id() {
            return yc_id;
        }

        public void setYc_id(int yc_id) {
            this.yc_id = yc_id;
        }

        public String getYc_nickname() {
            return yc_nickname;
        }

        public void setYc_nickname(String yc_nickname) {
            this.yc_nickname = yc_nickname;
        }

        public String getYc_phone() {
            return yc_phone;
        }

        public void setYc_phone(String yc_phone) {
            this.yc_phone = yc_phone;
        }

        public int getYc_role() {
            return yc_role;
        }

        public void setYc_role(int yc_role) {
            this.yc_role = yc_role;
        }

        public String getYc_rongcloudtoken() {
            return yc_rongcloudtoken;
        }

        public void setYc_rongcloudtoken(String yc_rongcloudtoken) {
            this.yc_rongcloudtoken = yc_rongcloudtoken;
        }

        public String getYc_status() {
            return yc_status;
        }

        public void setYc_status(String yc_status) {
            this.yc_status = yc_status;
        }

        public String getYc_token() {
            return yc_token;
        }

        public void setYc_token(String yc_token) {
            this.yc_token = yc_token;
        }

        public String getYc_user_token() {
            return yc_user_token;
        }

        public void setYc_user_token(String yc_user_token) {
            this.yc_user_token = yc_user_token;
        }

        public String getYc_username() {
            return yc_username;
        }

        public void setYc_username(String yc_username) {
            this.yc_username = yc_username;
        }

        public String getYc_video_name() {
            return yc_video_name;
        }

        public void setYc_video_name(String yc_video_name) {
            this.yc_video_name = yc_video_name;
        }


        public String getFirstLetter() {
            return firstLetter;
        }

        public void setFirstLetter(String firstLetter) {
            this.firstLetter = firstLetter;
        }

        public String getPinYin() {
            return pinYin;
        }

        public void setPinYin(String pinYin) {
            this.pinYin = pinYin;
        }

        public  void  initFirstLetter(){
            String name=yc_username;
            if (yc_video_name.equals("2")){
                name=yc_nickname;
            }
            this.firstLetter = Cn2Spell.getPinYinFirstLetter(name);
            this.pinYin = Cn2Spell.getPinYin(name);
            this.firstLetter = pinYin.substring(0, 1).toUpperCase(); // 获取拼音首字母并转成大写
            if (!firstLetter.matches("[A-Z]")) { // 如果不在A-Z中则默认为“#”
                firstLetter = "#";
            }
        }
    }
  

}

以上关键代码是这些瞎

    private String firstLetter;
    private String pinYin; 
    public String getFirstLetter() {
            return firstLetter;
        }

        public void setFirstLetter(String firstLetter) {
            this.firstLetter = firstLetter;
        }

        public String getPinYin() {
            return pinYin;
        }

        public void setPinYin(String pinYin) {
            this.pinYin = pinYin;
        }

        public  void  initFirstLetter(){
            String name=yc_username;
            if (yc_video_name.equals("2")){
                name=yc_nickname;
            }
            this.firstLetter = Cn2Spell.getPinYinFirstLetter(name);
            this.pinYin = Cn2Spell.getPinYin(name);
            this.firstLetter = pinYin.substring(0, 1).toUpperCase(); // 获取拼音首字母并转成大写
            if (!firstLetter.matches("[A-Z]")) { // 如果不在A-Z中则默认为“#”
                firstLetter = "#";
            }
        }
   

接下来是另外一个工具类

public class PaySection extends SectionEntity implements Comparable {


    public PaySection(boolean isHeader, String header) {
        super(isHeader, header);
    }

    public PaySection(model recordChildrenModel) {
        super(recordChildrenModel);
    }

    @Override
    public int compareTo(@NonNull PaySection o) {
        if ( t.getYcTeacher().getFirstLetter().equals("#") && !o.t.getYcTeacher().getFirstLetter().equals("#")) {
            return 1;
        } else if (! t.getYcTeacher().getFirstLetter().equals("#") && o.t.getYcTeacher().getFirstLetter().equals("#")) {
            return -1;
        } else {
            return t.getYcTeacher().getPinYin().compareToIgnoreCase(o.t.getYcTeacher().getPinYin());
        }
    }
}

上边代码是针对这个model写的一个工具类,我当然能看懂,如果有幸其他人看到,不懂可以留言、

最后,激动人心的时刻到了  轮到你了 activity

public class MainActivity extends AppCompatActivity {
    @BindView(R.id.record_list_sb_letter)
    SideBar record_list_sb_letter;
    @BindView(R.id.user_concerned)
    RecyclerView recyclerView1;
    private static PayAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        record_list_sb_letter.setOnTouchingLetterChangedListener(new SideBar.OnTouchingLetterChangedListener() {
            @Override
            public void onTouchingLetterChanged(String s) {

                if (adapter == null) {

                    return;
                }
                List sectionList = adapter.getData();
                for (int i = 0; i < sectionList.size(); i++) {
                    PaySection recordSection = adapter.getData().get(i);
                    if (recordSection.isHeader && recordSection.header.equalsIgnoreCase(s)) {

                        layoutManager.scrollToPositionWithOffset(i, 0);
                        return;
                    }
                }
            }
        });
    }
    public void teaSection(List teaList){
        recordSectionList = new ArrayList<>();
        for (int i = 0; i < teaList.size(); i++) {
            TeaModel model = teaList.get(i);
            model.getYcTeacher().initFirstLetter();
            recordSectionList.add(new PaySection(model));
        }
        Collections.sort(recordSectionList);
        //增加字母
        String head = null;
        for (int i = 0; i < recordSectionList.size(); i++) {
            if (head == null || !head.equals(recordSectionList.get(i).t.getYcTeacher().getFirstLetter())) {
                head = recordSectionList.get(i).t.getYcTeacher().getFirstLetter();
                recordSectionList.add(i, new PaySection(true, head));
            }
        }
    }
    public void showTopnewsData(List teaList) {
        teaSection(teaList);
        adapter = new PayAdapter(R.layout.my_pay_tea,R.layout.record_head_pay_item, recordSectionList);
        recyclerView1.setAdapter(adapter);}
}

大概就是这么个意思吧,activity代码不全,但是关键代码都有,主要是teaSection这个方法

呼~~

来个不太美观的效果图

Android之快速索引导航栏,联系人字母排序侧边栏sidebar开发_第1张图片

你可能感兴趣的:(Android之快速索引导航栏,联系人字母排序侧边栏sidebar开发)