├── SearchSidebar
├── .gitignore
├── libs
│ └── pinyin4j-2.5.0.jar
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── icon_search.png
│ │ │ │ └── icon_delete_gray.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── drawable
│ │ │ │ ├── default_useravatar.png
│ │ │ │ ├── shape_slide_grey.xml
│ │ │ │ ├── btn_list_item_bg.xml
│ │ │ │ ├── shape_border_grey.xml
│ │ │ │ └── bg_sidebar.xml
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── styles.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── arrays.xml
│ │ │ ├── menu
│ │ │ │ └── menu_main.xml
│ │ │ └── layout
│ │ │ │ ├── mainactivity.xml
│ │ │ │ ├── listviewsortbarfilter_item.xml
│ │ │ │ └── listviewsortbarfilter.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── lujianchao
│ │ │ └── SearchSideBar
│ │ │ ├── MainActivity.java
│ │ │ └── SearchSidebar
│ │ │ ├── SearchEditText.java
│ │ │ ├── SortAdapter.java
│ │ │ ├── PinyinUtils.java
│ │ │ ├── SideBar.java
│ │ │ └── SearchSideBar.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── adan
│ │ └── contactsdome
│ │ └── ApplicationTest.java
├── proguard-rules.pro
├── build.gradle
├── app.iml
├── applist.iml
└── SearchSidebar.iml
├── asprojects.zip
├── SearchSidebar.gif
├── .gitattributes
├── .gitignore
└── README.md
/SearchSidebar/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/asprojects.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itgowo/SearchSidebar/HEAD/asprojects.zip
--------------------------------------------------------------------------------
/SearchSidebar.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itgowo/SearchSidebar/HEAD/SearchSidebar.gif
--------------------------------------------------------------------------------
/SearchSidebar/libs/pinyin4j-2.5.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itgowo/SearchSidebar/HEAD/SearchSidebar/libs/pinyin4j-2.5.0.jar
--------------------------------------------------------------------------------
/SearchSidebar/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itgowo/SearchSidebar/HEAD/SearchSidebar/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/SearchSidebar/src/main/res/mipmap-hdpi/icon_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itgowo/SearchSidebar/HEAD/SearchSidebar/src/main/res/mipmap-hdpi/icon_search.png
--------------------------------------------------------------------------------
/SearchSidebar/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itgowo/SearchSidebar/HEAD/SearchSidebar/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/SearchSidebar/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itgowo/SearchSidebar/HEAD/SearchSidebar/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/SearchSidebar/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itgowo/SearchSidebar/HEAD/SearchSidebar/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/SearchSidebar/src/main/res/drawable/default_useravatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itgowo/SearchSidebar/HEAD/SearchSidebar/src/main/res/drawable/default_useravatar.png
--------------------------------------------------------------------------------
/SearchSidebar/src/main/res/mipmap-hdpi/icon_delete_gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itgowo/SearchSidebar/HEAD/SearchSidebar/src/main/res/mipmap-hdpi/icon_delete_gray.png
--------------------------------------------------------------------------------
/SearchSidebar/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 联系人
3 | Settings
4 |
5 |
--------------------------------------------------------------------------------
/SearchSidebar/src/main/res/drawable/shape_slide_grey.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/SearchSidebar/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SearchSidebar/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/SearchSidebar/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #F55813
4 | #5A5A5A
5 | #FFFFFF
6 | #000000
7 |
8 |
--------------------------------------------------------------------------------
/SearchSidebar/src/main/res/drawable/btn_list_item_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 | -
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SearchSidebar/src/main/res/drawable/shape_border_grey.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
--------------------------------------------------------------------------------
/SearchSidebar/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/SearchSidebar/src/main/res/drawable/bg_sidebar.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
10 |
13 |
14 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/SearchSidebar/src/androidTest/java/com/adan/contactsdome/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.adan.contactsdome;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/SearchSidebar/src/main/res/layout/mainactivity.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
15 |
--------------------------------------------------------------------------------
/SearchSidebar/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\Users\Administrator\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/SearchSidebar/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Windows image file caches
2 | Thumbs.db
3 | ehthumbs.db
4 |
5 | # Folder config file
6 | Desktop.ini
7 |
8 | # Recycle Bin used on file shares
9 | $RECYCLE.BIN/
10 |
11 | # Windows Installer files
12 | *.cab
13 | *.msi
14 | *.msm
15 | *.msp
16 |
17 | # Windows shortcuts
18 | *.lnk
19 |
20 | # =========================
21 | # Operating System Files
22 | # =========================
23 |
24 | # OSX
25 | # =========================
26 |
27 | .DS_Store
28 | .AppleDouble
29 | .LSOverride
30 |
31 | # Thumbnails
32 | ._*
33 |
34 | # Files that might appear in the root of a volume
35 | .DocumentRevisions-V100
36 | .fseventsd
37 | .Spotlight-V100
38 | .TemporaryItems
39 | .Trashes
40 | .VolumeIcon.icns
41 |
42 | # Directories potentially created on remote AFP share
43 | .AppleDB
44 | .AppleDesktop
45 | Network Trash Folder
46 | Temporary Items
47 | .apdisk
48 |
--------------------------------------------------------------------------------
/SearchSidebar/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.2"
6 |
7 | defaultConfig {
8 | applicationId "com.adan.contactsdome"
9 | minSdkVersion 10
10 | targetSdkVersion 23
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(include: ['*.jar'], dir: 'libs')
24 | compile 'com.android.support:appcompat-v7:23.1.1'
25 | compile files('libs/pinyin4j-2.5.0.jar')
26 | compile 'com.google.code.gson:gson:2.7'
27 | compile 'com.github.bumptech.glide:glide:3.7.0'
28 | }
29 |
--------------------------------------------------------------------------------
/SearchSidebar/src/main/java/com/lujianchao/SearchSideBar/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.lujianchao.SearchSideBar;
2 |
3 | import android.app.Activity;
4 | import android.content.ContentResolver;
5 | import android.net.Uri;
6 | import android.os.Bundle;
7 |
8 |
9 | import com.lujianchao.SearchSideBar.SearchSidebar.SearchSideBar;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 | public class MainActivity extends Activity {
15 |
16 | private SearchSideBar mSortBarFilter;
17 |
18 | private List mMembers = new ArrayList<>();
19 |
20 | @Override
21 | protected void onCreate(Bundle savedInstanceState) {
22 | super.onCreate(savedInstanceState);
23 | setContentView(R.layout.mainactivity);
24 | mSortBarFilter = (SearchSideBar) findViewById(R.id.lv_contact);
25 | String[] mStrings = getResources().getStringArray(R.array.contacts);
26 | Uri uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://"
27 | + getResources().getResourcePackageName(R.mipmap.ic_launcher) + "/"
28 | + getResources().getResourceTypeName(R.mipmap.ic_launcher) + "/"
29 | + getResources().getResourceEntryName(R.mipmap.ic_launcher));
30 | for (int i = 0; i < mStrings.length; i++) {
31 | SearchSideBar.ContactSortModel mMember = new SearchSideBar.ContactSortModel();
32 | mMember.setID("aaaaaaa" + i);
33 | mMember.setName(mStrings[i]);
34 | mMember.setLogo(uri.toString());
35 | mMembers.add(mMember);
36 | }
37 | mSortBarFilter.setMembers(mMembers, new SearchSideBar.onItemClickListener() {
38 | @Override
39 | public void onItem(int position, SearchSideBar.ContactSortModel mModel) {
40 | System.out.println("position = [" + position + "], mModel = [" + mModel + "]");
41 | }
42 | });
43 | }
44 |
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/SearchSidebar/src/main/res/layout/listviewsortbarfilter_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
19 |
20 |
24 |
25 |
34 |
35 |
45 |
46 |
51 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SearchSidebar
2 |
3 | ## 一:关键词:
4 | ~~~~
5 | 联系人列表 导航bar 搜索
6 | ~~~~
7 |
8 | QQ:1264957104
9 |
10 |
11 |
12 | ## 二:说明
13 | 导航bar有很多了,我看了别人的有一些不满足需求,于是改了改:
14 | 1.增加了对数字和特殊符号的处理,按#处理了。
15 | 2.针对导航字母数量不同做了处理。当数量少时,间距较大方便点击,数量越多间距越小。
16 | 3.做成了自定义View方式,充分解耦,使用方便。
17 |
18 | 如果直接导入会出错,把布局文件listviewsortbarfilter.xml里自定义view重新写一下路径和名字就可以了,clean项目,一般没问题了。
19 | 核心代码方法: mSortBarFilter.setMembers(mMembers, new SearchSideBar.onItemClickListener()
20 |
21 | ## 示例
22 | 
23 |
24 |
25 |
26 | ## 布局
27 |
28 |
32 |
33 | ## 代码
34 |
35 |
36 | protected void onCreate(Bundle savedInstanceState) {
37 | super.onCreate(savedInstanceState);
38 | setContentView(R.layout.mainactivity);
39 | mSortBarFilter = (SearchSideBar) findViewById(R.id.lv_contact);
40 | String[] mStrings = getResources().getStringArray(R.array.contacts);
41 | Uri uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://"
42 | + getResources().getResourcePackageName(R.mipmap.ic_launcher) + "/"
43 | + getResources().getResourceTypeName(R.mipmap.ic_launcher) + "/"
44 | + getResources().getResourceEntryName(R.mipmap.ic_launcher));
45 | for (int i = 0; i < mStrings.length; i++) {
46 | SearchSideBar.ContactSortModel mMember = new SearchSideBar.ContactSortModel();
47 | mMember.setID("aaaaaaa" + i);
48 | mMember.setName(mStrings[i]);
49 | mMember.setLogo(uri.toString());
50 | mMembers.add(mMember);
51 | }
52 | mSortBarFilter.setMembers(mMembers, new SearchSideBar.onItemClickListener() {
53 | @Override
54 | public void onItem(int position, SearchSideBar.ContactSortModel mModel) {
55 | System.out.println("position = [" + position + "], mModel = [" + mModel + "]");
56 | }
57 | });
58 | }
59 |
--------------------------------------------------------------------------------
/SearchSidebar/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | - /
6 | - !
7 | - */*-
8 | - aaa
9 | - 111
10 | - 222
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | - 毛泽东
34 | - 周恩来
35 | - 孙中山
36 | - 刘少奇
37 | - 邓小平
38 | - 宋庆龄
39 | - 邓稼先
40 | - 陈景润
41 | - 黄子卿
42 | - 李四光
43 | - 马大猷
44 | - 茅以升
45 | - 钱学森
46 | - 卢永根
47 | - 华罗庚
48 | - 郭沫若
49 | - 鲁迅
50 | - 李大钊
51 | - 彭德怀
52 | - 朱德
53 | - 恽代英
54 | - 瞿秋白
55 | - 江泽民
56 | - 张太雷
57 | - 秋瑾
58 | - 袁隆平
59 | - 李小龙
60 | - 成龙
61 | - 李连杰
62 | - 刘德华
63 | - 周杰伦
64 | - 张学友
65 | - 姚明
66 | - 刘翔
67 | - 李嘉诚
68 | - 何鸿燊
69 | - 于丹
70 | - 李政道
71 | - 杨振宁
72 |
73 |
74 |
--------------------------------------------------------------------------------
/SearchSidebar/src/main/res/layout/listviewsortbarfilter.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
22 |
23 |
26 |
27 |
35 |
36 |
49 |
50 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/SearchSidebar/src/main/java/com/lujianchao/SearchSideBar/SearchSidebar/SearchEditText.java:
--------------------------------------------------------------------------------
1 | package com.lujianchao.SearchSideBar.SearchSidebar;
2 |
3 | /**
4 | * Created by Lu JianChao on 2016/6/29.
5 | * https://github.com/hnsugar
6 | */
7 |
8 | import android.content.Context;
9 | import android.graphics.Rect;
10 | import android.graphics.drawable.Drawable;
11 | import android.text.Editable;
12 | import android.text.TextWatcher;
13 | import android.util.AttributeSet;
14 | import android.view.MotionEvent;
15 | import android.widget.EditText;
16 |
17 | import com.lujianchao.SearchSideBar.R;
18 |
19 |
20 | /**
21 | * @description: 自定义带有删除功能的EditText
22 | */
23 | public class SearchEditText extends EditText {
24 | private final static String TAG = "EditTextWithDel";
25 | private Drawable imgLeft, imgAble;
26 | private Context mContext;
27 |
28 | public SearchEditText(Context context) {
29 | super(context);
30 | mContext = context;
31 | init();
32 | }
33 |
34 | public SearchEditText(Context context, AttributeSet attrs, int defStyle) {
35 | super(context, attrs, defStyle);
36 | mContext = context;
37 | init();
38 | }
39 |
40 | public SearchEditText(Context context, AttributeSet attrs) {
41 | super(context, attrs);
42 | mContext = context;
43 | init();
44 | }
45 |
46 | private void init() {
47 | imgLeft = mContext.getResources().getDrawable(R.mipmap.icon_search);
48 | imgAble = mContext.getResources().getDrawable(R.mipmap.icon_delete_gray);
49 | addTextChangedListener(new TextWatcher() {
50 | @Override
51 | public void onTextChanged(CharSequence s, int start, int before, int count) {
52 | }
53 |
54 | @Override
55 | public void beforeTextChanged(CharSequence s, int start, int count, int after) {
56 | }
57 |
58 | @Override
59 | public void afterTextChanged(Editable s) {
60 | setDrawable();
61 | }
62 | });
63 | setDrawable();
64 | }
65 |
66 | // 设置删除图片
67 | private void setDrawable() {
68 | if (length() < 1) {
69 | setCompoundDrawablesWithIntrinsicBounds(imgLeft, null, null, null);
70 | } else {
71 | setCompoundDrawablesWithIntrinsicBounds(imgLeft, null, imgAble, null);
72 | }
73 | }
74 |
75 | // 处理删除事件
76 | @Override
77 | public boolean onTouchEvent(MotionEvent event) {
78 | if (imgAble != null && event.getAction() == MotionEvent.ACTION_UP) {
79 | int eventX = (int) event.getRawX();
80 | int eventY = (int) event.getRawY();
81 | Rect rect = new Rect();
82 | getGlobalVisibleRect(rect);
83 | rect.left = rect.right - 90;
84 | if (rect.contains(eventX, eventY))
85 | setText("");
86 | }
87 | return super.onTouchEvent(event);
88 | }
89 |
90 | @Override
91 | protected void finalize() throws Throwable {
92 | super.finalize();
93 | }
94 | }
--------------------------------------------------------------------------------
/SearchSidebar/src/main/java/com/lujianchao/SearchSideBar/SearchSidebar/SortAdapter.java:
--------------------------------------------------------------------------------
1 | package com.lujianchao.SearchSideBar.SearchSidebar;
2 |
3 | import android.content.Context;
4 | import android.net.Uri;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.BaseAdapter;
9 | import android.widget.ImageView;
10 | import android.widget.SectionIndexer;
11 | import android.widget.TextView;
12 |
13 |
14 | import com.lujianchao.SearchSideBar.R;
15 |
16 | import java.util.List;
17 |
18 | public class SortAdapter extends BaseAdapter implements SectionIndexer {
19 | private List list = null;
20 | private Context mContext;
21 |
22 | public SortAdapter(Context mContext, List list) {
23 | this.mContext = mContext;
24 | this.list = list;
25 | }
26 |
27 | /**
28 | * 当ListView数据发生变化时,调用此方法来更新ListView
29 | *
30 | * @param list
31 | */
32 | public void updateListView(List list) {
33 | this.list = list;
34 | notifyDataSetChanged();
35 | }
36 |
37 | public int getCount() {
38 | return this.list.size();
39 | }
40 |
41 | public Object getItem(int position) {
42 | return list.get(position);
43 | }
44 |
45 | public long getItemId(int position) {
46 | return position;
47 | }
48 |
49 | public View getView(final int position, View view, ViewGroup arg2) {
50 | ViewHolder viewHolder = null;
51 | final SearchSideBar.ContactSortModel mContactSortModel = list.get(position);
52 | if (view == null) {
53 | view = LayoutInflater.from(mContext).inflate(R.layout.listviewsortbarfilter_item, null);
54 | viewHolder = new ViewHolder(view);
55 | view.setTag(viewHolder);
56 | } else {
57 | viewHolder = (ViewHolder) view.getTag();
58 | }
59 |
60 | int section = getSectionForPosition(position);
61 | if (position == getPositionForSection(section)) {
62 | viewHolder.tvLetter.setVisibility(View.VISIBLE);
63 | viewHolder.tvLetter.setText(mContactSortModel.getSortLetters());
64 | } else {
65 | viewHolder.tvLetter.setVisibility(View.GONE);
66 | }
67 |
68 | viewHolder.contactsName.setText(this.list.get(position).getName());
69 | viewHolder.contactsItemIcon.setImageURI(Uri.parse(list.get(position).getLogo()));
70 | // Glide.with(mContext).load(list.get(position).getLogo()).into(viewHolder.contactsItemIcon);
71 | return view;
72 |
73 | }
74 |
75 |
76 | class ViewHolder {
77 | TextView tvLetter;
78 | private ImageView contactsItemIcon;
79 | private TextView contactsName;
80 |
81 | ViewHolder(View mView) {
82 | tvLetter = (TextView) mView.findViewById(R.id.tv_catagory);
83 | contactsItemIcon = (ImageView) mView.findViewById(R.id.contacts_item_icon);
84 | contactsName = (TextView) mView.findViewById(R.id.contacts_name);
85 | }
86 | }
87 |
88 | public int getSectionForPosition(int position) {
89 | return list.get(position).getSortLetters().charAt(0);
90 | }
91 |
92 | public int getPositionForSection(int section) {
93 | for (int i = 0; i < getCount(); i++) {
94 | String sortStr = list.get(i).getSortLetters();
95 | char firstChar = sortStr.toUpperCase().charAt(0);
96 | if (firstChar == section) {
97 | return i;
98 | }
99 | }
100 | return -1;
101 | }
102 |
103 | @Override
104 | public Object[] getSections() {
105 | return null;
106 | }
107 | }
--------------------------------------------------------------------------------
/SearchSidebar/src/main/java/com/lujianchao/SearchSideBar/SearchSidebar/PinyinUtils.java:
--------------------------------------------------------------------------------
1 | package com.lujianchao.SearchSideBar.SearchSidebar;
2 |
3 | import net.sourceforge.pinyin4j.PinyinHelper;
4 | import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
5 | import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
6 | import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
7 | import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
8 | import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
9 |
10 | /**
11 | * @author: 肖丽娟
12 | * @description:
13 | * @projectName: SelectCityDome
14 | * @date: 2016-03-01
15 | * @time: 15:45
16 | */
17 | public class PinyinUtils {
18 | /**
19 | * 获得汉语拼音首字母
20 | *
21 | * @param chines 汉字
22 | * @return
23 | */
24 | public static String getAlpha(String chines) {
25 | String pinyinName = "";
26 | char[] nameChar = chines.toCharArray();
27 | HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
28 | defaultFormat.setCaseType(HanyuPinyinCaseType.UPPERCASE);
29 | defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
30 | for (int i = 0; i < nameChar.length; i++) {
31 | if (nameChar[i] > 128) {
32 | try {
33 | pinyinName += PinyinHelper.toHanyuPinyinStringArray(
34 | nameChar[i], defaultFormat)[0].charAt(0);
35 | } catch (BadHanyuPinyinOutputFormatCombination e) {
36 | e.printStackTrace();
37 | }
38 | } else {
39 | pinyinName += nameChar[i];
40 | }
41 | }
42 | return pinyinName;
43 | }
44 |
45 | /**
46 | * 将字符串中的中文转化为拼音,英文字符不变
47 | *
48 | * @param inputString 汉字
49 | * @return
50 | */
51 | public static String getPingYin(String inputString) {
52 | HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
53 | format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
54 | format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
55 | format.setVCharType(HanyuPinyinVCharType.WITH_V);
56 | String output = "";
57 | if (inputString != null && inputString.length() > 0 && !"null".equals(inputString)) {
58 | char[] input = inputString.trim().toCharArray();
59 | try {
60 | for (int i = 0; i < input.length; i++) {
61 | if (Character.toString(input[i]).matches("[\\u4E00-\\u9FA5]+")) {
62 | String[] temp = PinyinHelper.toHanyuPinyinStringArray(input[i], format);
63 | output += temp[0];
64 | } else
65 | output += Character.toString(input[i]);
66 | }
67 | } catch (BadHanyuPinyinOutputFormatCombination e) {
68 | e.printStackTrace();
69 | }
70 | } else {
71 | return "*";
72 | }
73 | return output;
74 | }
75 |
76 | /**
77 | * 汉字转换位汉语拼音首字母,英文字符不变
78 | *
79 | * @param chines 汉字
80 | * @return 拼音
81 | */
82 | public static String converterToFirstSpell(String chines) {
83 | String pinyinName = "";
84 | char[] nameChar = chines.toCharArray();
85 | HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
86 | defaultFormat.setCaseType(HanyuPinyinCaseType.UPPERCASE);
87 | defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
88 | for (int i = 0; i < nameChar.length; i++) {
89 | if (nameChar[i] > 128) {
90 | try {
91 | pinyinName += PinyinHelper.toHanyuPinyinStringArray(
92 | nameChar[i], defaultFormat)[0].charAt(0);
93 | } catch (BadHanyuPinyinOutputFormatCombination e) {
94 | e.printStackTrace();
95 | }
96 | } else {
97 | pinyinName += nameChar[i];
98 | }
99 | }
100 | return pinyinName;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/SearchSidebar/src/main/java/com/lujianchao/SearchSideBar/SearchSidebar/SideBar.java:
--------------------------------------------------------------------------------
1 | package com.lujianchao.SearchSideBar.SearchSidebar;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.graphics.Typeface;
8 | import android.util.AttributeSet;
9 | import android.view.MotionEvent;
10 | import android.view.View;
11 | import android.widget.TextView;
12 |
13 |
14 | import com.lujianchao.SearchSideBar.R;
15 |
16 | import java.util.ArrayList;
17 | import java.util.Arrays;
18 | import java.util.List;
19 |
20 | /**
21 | * ListView右侧的字母索引View
22 | */
23 | public class SideBar extends View {
24 |
25 | public static String[] INDEX_STRING = {"#", "A", "B", "C", "D", "E", "F", "G", "H", "I",
26 | "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
27 | "W", "X", "Y", "Z"};
28 |
29 | private OnTouchingLetterChangedListener onTouchingLetterChangedListener;
30 | private List letterList;
31 | private int choose = -1;
32 | private Paint paint = new Paint();
33 | private TextView mTextDialog;
34 |
35 | public SideBar(Context context) {
36 | this(context, null);
37 | }
38 |
39 | public SideBar(Context context, AttributeSet attrs) {
40 | this(context, attrs, 0);
41 | }
42 |
43 | public SideBar(Context context, AttributeSet attrs, int defStyle) {
44 | super(context, attrs, defStyle);
45 | init();
46 | }
47 |
48 | private void init() {
49 | setBackgroundColor(Color.parseColor("#00FFFFFF"));
50 | letterList = Arrays.asList(INDEX_STRING);
51 | }
52 |
53 | protected void onDraw(Canvas canvas) {
54 | super.onDraw(canvas);
55 | int height = getHeight();// 获取对应高度
56 | int width = getWidth();// 获取对应宽度
57 | int singleHeight = height / letterList.size();// 获取每一个字母的高度
58 | for (int i = 0; i < letterList.size(); i++) {
59 | paint.setColor(Color.parseColor("#606060"));
60 | paint.setTypeface(Typeface.DEFAULT_BOLD);
61 | paint.setAntiAlias(true);
62 | paint.setTextSize(30);
63 | // 选中的状态
64 | if (i == choose) {
65 | paint.setColor(Color.parseColor("#4F41FD"));
66 | paint.setFakeBoldText(true);
67 | }
68 | // x坐标等于中间-字符串宽度的一半.
69 | float xPos = width / 2 - paint.measureText(letterList.get(i)) / 2;
70 | float yPos = singleHeight * i + singleHeight / 2;
71 | canvas.drawText(letterList.get(i), xPos, yPos, paint);
72 | paint.reset();// 重置画笔
73 | }
74 | }
75 |
76 | @Override
77 | public boolean dispatchTouchEvent(MotionEvent event) {
78 | final int action = event.getAction();
79 | final float y = event.getY();// 点击y坐标
80 | final int oldChoose = choose;
81 | final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener;
82 | final int c = (int) (y / getHeight() * letterList.size());// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数.
83 |
84 | switch (action) {
85 | case MotionEvent.ACTION_UP:
86 | setBackgroundColor(Color.parseColor("#00FFFFFF"));
87 | choose = -1;
88 | invalidate();
89 | if (mTextDialog != null) {
90 | mTextDialog.setVisibility(View.GONE);
91 | }
92 | break;
93 | default:
94 | setBackgroundResource(R.drawable.bg_sidebar);
95 | if (oldChoose != c) {
96 | if (c >= 0 && c < letterList.size()) {
97 | if (listener != null) {
98 | listener.onTouchingLetterChanged(letterList.get(c));
99 | }
100 | if (mTextDialog != null) {
101 | mTextDialog.setText(letterList.get(c));
102 | mTextDialog.setVisibility(View.VISIBLE);
103 | }
104 | choose = c;
105 | invalidate();
106 | }
107 | }
108 | break;
109 | }
110 | return true;
111 | }
112 |
113 | public void setIndexText(ArrayList indexStrings) {
114 | this.letterList = indexStrings;
115 | if (indexStrings.size() > 20) {
116 | } else if (indexStrings.size() > 15) {
117 | getLayoutParams().height = indexStrings.size() * 80;
118 |
119 | } else if (indexStrings.size() > 10) {
120 | getLayoutParams().height = indexStrings.size() * 120;
121 |
122 | } else {
123 | getLayoutParams().height = indexStrings.size() * 180;
124 | }
125 | invalidate();
126 | }
127 |
128 | /**
129 | * 为SideBar设置显示当前按下的字母的TextView
130 | *
131 | * @param mTextDialog
132 | */
133 | public void setTextView(TextView mTextDialog) {
134 | this.mTextDialog = mTextDialog;
135 | }
136 |
137 | /**
138 | * 向外公开的方法
139 | *
140 | * @param onTouchingLetterChangedListener
141 | */
142 | public void setOnTouchingLetterChangedListener(
143 | OnTouchingLetterChangedListener onTouchingLetterChangedListener) {
144 | this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;
145 | }
146 |
147 | /**
148 | * 接口
149 | */
150 | public interface OnTouchingLetterChangedListener {
151 | void onTouchingLetterChanged(String s);
152 | }
153 | }
--------------------------------------------------------------------------------
/SearchSidebar/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/SearchSidebar/src/main/java/com/lujianchao/SearchSideBar/SearchSidebar/SearchSideBar.java:
--------------------------------------------------------------------------------
1 | package com.lujianchao.SearchSideBar.SearchSidebar;
2 |
3 | import android.content.Context;
4 | import android.text.Editable;
5 | import android.text.TextUtils;
6 | import android.text.TextWatcher;
7 | import android.util.AttributeSet;
8 | import android.view.View;
9 | import android.widget.AdapterView;
10 | import android.widget.LinearLayout;
11 | import android.widget.ListView;
12 | import android.widget.TextView;
13 |
14 | import com.lujianchao.SearchSideBar.R;
15 |
16 | import java.util.ArrayList;
17 | import java.util.Collections;
18 | import java.util.Comparator;
19 | import java.util.List;
20 |
21 | /**
22 | * Created by Lu JianChao on 2016/6/29.
23 | * https://github.com/hnsugar
24 | */
25 | public class SearchSideBar extends LinearLayout {
26 | private ListView sortListView;
27 | private SideBar sideBar;
28 | private Context mContext;
29 | private TextView dialog;
30 | private SortAdapter adapter;
31 | private SearchEditText mEtSearchName;
32 | private List SourceDateList;
33 | private onItemClickListener mOnItemClickListener;
34 |
35 | public SearchSideBar(Context context, AttributeSet attrs) {
36 | super(context, attrs);
37 | mContext = context;
38 | addView(View.inflate(context, R.layout.listviewsortbarfilter, null));
39 | }
40 |
41 | public void setMembers(List mMembers, onItemClickListener mListener) {
42 | this.SourceDateList = mMembers;
43 | this.mOnItemClickListener = mListener;
44 | initViews();
45 | }
46 |
47 | private void initViews() {
48 | mEtSearchName = (SearchEditText) findViewById(R.id.et_search);
49 | sideBar = (SideBar) findViewById(R.id.sidrbar);
50 | dialog = (TextView) findViewById(R.id.dialog);
51 | sortListView = (ListView) findViewById(R.id.sortListView);
52 | initDatas();
53 | initEvents();
54 | setAdapter();
55 | }
56 |
57 | private void setAdapter() {
58 |
59 | filledData(SourceDateList);
60 | Collections.sort(SourceDateList, new PinyinComparator());
61 | adapter = new SortAdapter(mContext, SourceDateList);
62 | sortListView.setAdapter(adapter);
63 | }
64 |
65 | private void initEvents() {
66 | //设置右侧触摸监听
67 | sideBar.setOnTouchingLetterChangedListener(new SideBar.OnTouchingLetterChangedListener() {
68 | @Override
69 | public void onTouchingLetterChanged(String s) {
70 | //该字母首次出现的位置
71 | int position = adapter.getPositionForSection(s.charAt(0));
72 | if (position != -1) {
73 | sortListView.setSelection(position);
74 | }
75 | }
76 | });
77 |
78 | //ListView的点击事件
79 | sortListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
80 |
81 | @Override
82 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
83 | if (mOnItemClickListener != null) {
84 | mOnItemClickListener.onItem(position, (ContactSortModel) adapter.getItem(position));
85 | }
86 | }
87 | });
88 |
89 | //根据输入框输入值的改变来过滤搜索
90 | mEtSearchName.addTextChangedListener(new TextWatcher() {
91 | @Override
92 | public void beforeTextChanged(CharSequence s, int start, int count, int after) {
93 |
94 | }
95 |
96 | @Override
97 | public void onTextChanged(CharSequence s, int start, int before, int count) {
98 | //当输入框里面的值为空,更新为原来的列表,否则为过滤数据列表
99 | filterData(s.toString());
100 | }
101 |
102 | @Override
103 | public void afterTextChanged(Editable s) {
104 |
105 | }
106 | });
107 | }
108 |
109 | private void initDatas() {
110 | sideBar.setTextView(dialog);
111 | }
112 |
113 | /**
114 | * 根据输入框中的值来过滤数据并更新ListView
115 | *
116 | * @param filterStr
117 | */
118 | private void filterData(String filterStr) {
119 | List mSortList = new ArrayList<>();
120 | if (TextUtils.isEmpty(filterStr)) {
121 | mSortList = SourceDateList;
122 | } else {
123 | mSortList.clear();
124 | for (ContactSortModel sortModel : SourceDateList) {
125 | String name = sortModel.getName();
126 | if (name.toUpperCase().indexOf(filterStr.toString().toUpperCase()) != -1 || PinyinUtils.getPingYin(name).toUpperCase().startsWith(filterStr.toString().toUpperCase())) {
127 | mSortList.add(sortModel);
128 | }
129 | }
130 | }
131 | // 根据a-z进行排序
132 | Collections.sort(mSortList, new PinyinComparator());
133 | adapter.updateListView(mSortList);
134 | }
135 |
136 | /**
137 | * 计算出首字母
138 | * @param mMembers
139 | * @return
140 | */
141 | private List filledData(List mMembers) {
142 | List mSortList = mMembers;
143 | ArrayList indexString = new ArrayList<>();
144 |
145 | for (int i = 0; i < mSortList.size(); i++) {
146 | String pinyin = PinyinUtils.getPingYin(mSortList.get(i).getName());
147 | String sortString = pinyin.substring(0, 1).toUpperCase();
148 | if (sortString.matches("[A-Z]")) {
149 | mSortList.get(i).setSortLetters(sortString.toUpperCase());
150 | if (!indexString.contains(sortString)) {
151 | indexString.add(sortString);
152 | }
153 | } else {
154 | if (!indexString.contains("#")) {
155 | indexString.add("#");
156 | }
157 | }
158 |
159 | }
160 | Collections.sort(indexString);
161 | sideBar.setIndexText(indexString);
162 | return mSortList;
163 | }
164 |
165 |
166 | /**
167 | * 用来对ListView中的数据根据A-Z进行排序,前面两个if判断主要是将不是以汉字开头的数据放在后面
168 | */
169 | public class PinyinComparator implements Comparator {
170 |
171 | public int compare(ContactSortModel o1, ContactSortModel o2) {
172 | //这里主要是用来对ListView里面的数据根据ABCDEFG...来排序
173 | if (o1.getSortLetters().equals("@")
174 | || o2.getSortLetters().equals("#")) {
175 | return 1;
176 | } else if (o1.getSortLetters().equals("#")
177 | || o2.getSortLetters().equals("@")) {
178 | return -1;
179 | } else {
180 | return o1.getSortLetters().compareTo(o2.getSortLetters());
181 | }
182 | }
183 | }
184 |
185 |
186 | public static class ContactSortModel {
187 |
188 | private String name;//显示的数据
189 | private String ID;
190 | private String Logo;
191 | private String sortLetters = "#";//显示数据拼音的首字母
192 | private String tag;
193 |
194 | public String getTag() {
195 | return tag;
196 | }
197 |
198 | public void setTag(String mTag) {
199 | tag = mTag;
200 | }
201 |
202 | public String getName() {
203 | return name;
204 | }
205 |
206 | public void setName(String name) {
207 | this.name = name;
208 | }
209 |
210 | public String getSortLetters() {
211 | return sortLetters;
212 | }
213 |
214 | public void setSortLetters(String sortLetters) {
215 | this.sortLetters = sortLetters;
216 | }
217 |
218 | public String getID() {
219 | return ID;
220 | }
221 |
222 | public void setID(String mID) {
223 | ID = mID;
224 | }
225 |
226 | public String getLogo() {
227 | return Logo;
228 | }
229 |
230 | public void setLogo(String mLogo) {
231 | Logo = mLogo;
232 | }
233 |
234 | @Override
235 | public String toString() {
236 | return "ContactSortModel{" +
237 | "name='" + name + '\'' +
238 | ", ID='" + ID + '\'' +
239 | ", Logo='" + Logo + '\'' +
240 | ", sortLetters='" + sortLetters + '\'' +
241 | '}';
242 | }
243 | }
244 |
245 | public interface onItemClickListener {
246 | public void onItem(int position, ContactSortModel mModel);
247 | }
248 |
249 | }
250 |
251 |
--------------------------------------------------------------------------------
/SearchSidebar/applist.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | generateDebugSources
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/SearchSidebar/SearchSidebar.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | generateDebugSources
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------