├── .gitignore
├── .idea
├── .name
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── gradle.xml
├── inspectionProfiles
│ ├── Project_Default.xml
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
└── runConfigurations.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── libs
│ ├── nineoldandroids-2.4.0.jar
│ └── pinyin4j-2.5.0.jar
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── lyx
│ │ └── robert
│ │ └── quicksearch
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── lyx
│ │ │ └── robert
│ │ │ └── quicksearch
│ │ │ ├── Bean
│ │ │ ├── ContactBean.java
│ │ │ └── PinYinStyle.java
│ │ │ ├── activities
│ │ │ └── MainActivity.java
│ │ │ ├── adapter
│ │ │ ├── AlphabetAdp.java
│ │ │ └── ContactAdapter.java
│ │ │ ├── utils
│ │ │ ├── DisplayUtil.java
│ │ │ ├── PinYinUtil.java
│ │ │ └── SwipeManager.java
│ │ │ └── view
│ │ │ ├── ClearEditText.java
│ │ │ ├── SideLetterBar.java
│ │ │ └── SwipeLayout.java
│ └── res
│ │ ├── anim
│ │ ├── pop_push_down_out.xml
│ │ └── pop_push_up_in.xml
│ │ ├── drawable-hdpi
│ │ ├── ic_launcher.png
│ │ ├── icon_delete.png
│ │ ├── icon_side_delete.png
│ │ ├── icon_side_phone.png
│ │ └── icon_side_sms.png
│ │ ├── drawable-mdpi
│ │ └── ic_launcher.png
│ │ ├── drawable-xhdpi
│ │ └── ic_launcher.png
│ │ ├── drawable-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── icon_sms.png
│ │ ├── drawable-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── drawable
│ │ ├── bg.xml
│ │ ├── header_selector.xml
│ │ └── search_bg.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── item_contact.xml
│ │ ├── layout_alphabet.xml
│ │ └── layout_slip.xml
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── lyx
│ └── robert
│ └── quicksearch
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | QuickSearch
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
22 |
23 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # QuickSearch-A-Z
2 | Android侧栏A-Z的快速滑动搜索想必大家并不陌生,很多应用里面都有这样的功能出现。最常见的如电话联系人列表、好友列表、城市列表等等。快速搜索就是方便我们快速定位到我们要找的信息。比如我们想找姓氏为刘的,那么我们只需要点击一下L就能搜索到好友里面的姓氏拼音首字母以L开头的,当然姓氏刘也就搜出来的,有可能以L开头的姓氏比较多,比如李、郎、鲁、柳、雷、刘、林、蓝、吕等,而我们想找到刘这个姓我们可以让含有L的这些姓氏全都显示出来供我们来选择。
3 | 如有问题或了解实现详情请前往博客http://blog.csdn.net/u014452224/article/details/53341253
4 | #如果对您有帮助还请您别忘了点下star
5 | 
6 |
7 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 24
5 | buildToolsVersion "24.0.2"
6 |
7 | defaultConfig {
8 | applicationId "lyx.robert.quicksearch"
9 | minSdkVersion 15
10 | targetSdkVersion 24
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 | testCompile 'junit:junit:4.12'
25 | compile 'com.android.support:appcompat-v7:24.2.0'
26 | compile files('libs/pinyin4j-2.5.0.jar')
27 | compile files('libs/android-support-v4.jar')
28 | compile files('libs/nineoldandroids-2.4.0.jar')
29 | }
30 |
--------------------------------------------------------------------------------
/app/libs/nineoldandroids-2.4.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyxRobert/QuickSearch-A-Z/c3895888e03565631b8ff1ed4f47f02a5ba84080/app/libs/nineoldandroids-2.4.0.jar
--------------------------------------------------------------------------------
/app/libs/pinyin4j-2.5.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyxRobert/QuickSearch-A-Z/c3895888e03565631b8ff1ed4f47f02a5ba84080/app/libs/pinyin4j-2.5.0.jar
--------------------------------------------------------------------------------
/app/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 D:\androidstudio\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 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/lyx/robert/quicksearch/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package lyx.robert.quicksearch;
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 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/java/lyx/robert/quicksearch/Bean/ContactBean.java:
--------------------------------------------------------------------------------
1 | package lyx.robert.quicksearch.Bean;
2 |
3 | import lyx.robert.quicksearch.utils.PinYinUtil;
4 |
5 | public class ContactBean implements Comparable{
6 | private String pinyin;
7 | public String name;
8 | public PinYinStyle pinYinStyle=new PinYinStyle();
9 | //使用成员变量生成构造方法:alt+shift+s->o
10 |
11 |
12 | public ContactBean(String name) {
13 | super();
14 | this.name = name;
15 | //一开始就转化好拼音
16 | setPinyin(PinYinUtil.getPinyin(name));
17 | }
18 |
19 | @Override
20 | public int compareTo(ContactBean another) {
21 | return getPinyin().compareTo(another.getPinyin());
22 | }
23 |
24 | public String getPinyin() {
25 | return pinyin;
26 | }
27 |
28 | public void setPinyin(String pinyin) {
29 | this.pinyin = pinyin;
30 | }
31 |
32 | public String getName() {
33 | return name;
34 | }
35 |
36 | public void setName(String name) {
37 | this.name = name;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/lyx/robert/quicksearch/Bean/PinYinStyle.java:
--------------------------------------------------------------------------------
1 | package lyx.robert.quicksearch.Bean;
2 |
3 | /**
4 | *@author xiaobo.cui 2014年11月26日 上午10:40:15
5 | *
6 | */
7 | public class PinYinStyle {
8 | public String briefnessSpell = "";//简拼
9 | public String completeSpell = "";//全拼
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/java/lyx/robert/quicksearch/activities/MainActivity.java:
--------------------------------------------------------------------------------
1 | package lyx.robert.quicksearch.activities;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Collections;
5 | import java.util.List;
6 | import java.util.regex.Matcher;
7 | import java.util.regex.Pattern;
8 |
9 | import android.app.Activity;
10 | import android.os.Bundle;
11 | import android.os.Handler;
12 | import android.text.Editable;
13 | import android.text.TextUtils;
14 | import android.text.TextWatcher;
15 | import android.view.View;
16 | import android.widget.AbsListView;
17 | import android.widget.AdapterView;
18 | import android.widget.ListView;
19 | import android.widget.RelativeLayout;
20 | import android.widget.TextView;
21 | import com.nineoldandroids.view.ViewPropertyAnimator;
22 |
23 | import lyx.robert.quicksearch.Bean.ContactBean;
24 | import lyx.robert.quicksearch.adapter.ContactAdapter;
25 | import lyx.robert.quicksearch.utils.PinYinUtil;
26 | import lyx.robert.quicksearch.view.SideLetterBar;
27 | import lyx.robert.quicksearch.R;
28 | import lyx.robert.quicksearch.Bean.PinYinStyle;
29 | import lyx.robert.quicksearch.utils.SwipeManager;
30 | import lyx.robert.quicksearch.adapter.AlphabetAdp;
31 | import lyx.robert.quicksearch.view.ClearEditText;
32 |
33 |
34 | public class MainActivity extends Activity {
35 | private SideLetterBar sideLetterBar;
36 | private ListView lv_contact;
37 | private ListView lv_alphabet;
38 | private TextView tv_alphabet;
39 | private TextView tv_notice;
40 | private ClearEditText et_clear;
41 | private ListalphabetList;
42 | RelativeLayout rel_notice;
43 | ContactAdapter adapter ;
44 | private String[] data = new String[] {
45 | "15129372345","15129372334","15129372335","15129372343","15129372347","151293723423",
46 | //A
47 | "安先生", "敖先生", "艾先生", "爱先生",
48 | //B
49 | "巴先生", "白先生", "鲍先生","包先生", "班先生", "毕先生","边先生", "卞先生", "薄先生",
50 | //C
51 | "蔡先生", "岑先生", "曹先生","陈先生", "程先生", "褚先生","昌先生", "车先生", "常先生",
52 | //D
53 | "戴先生", "狄先生", "窦先生","董先生", "杜先生","杜先生","杜先生", "丁先生","邓先生", "段先生", "党先生",
54 | //E
55 | "鄂先生",
56 | //F
57 | "费先生", "范先生","樊先生", "方先生", "房先生","丰先生", "封先生", "冯先生","法先生",
58 | //G
59 | "盖先生", "甘先生", "高先生"," 葛先生", "耿先生", "古先生","顾先生", "关先生", "郭先生",
60 | //H
61 | "海先生", "郝先生", "韩先生","何先生", "贺先生", "胡先生","扈先生", "黄先生", "华先生",
62 | //J
63 | "姬先生", "季先生", "纪先生","金先生", "焦先生", "姜先生","贾先生", "郏先生", "靳先生",
64 | //K
65 | "寇先生", "孔先生", "康先生","柯先生", "况先生", "亢先生","夔先生", "蒯先生", "隗先生",
66 | //L
67 | "李先生", "郎先生", "鲁先生","柳先生", "雷先生", "刘先生","林先生", "蓝先生", "吕先生",
68 | //M
69 | "马先生", "满先生", "苗先生","穆先生", "毛先生", "麻先生","孟先生", "梅先生", "莫先生",
70 | //N
71 | "那先生", "能先生", "倪先生","年先生", "宁先生", "聂先生","牛先生", "农先生", "聂先生",
72 | //O
73 | "欧先生", "欧阳先生",
74 | //P
75 | "潘先生", "庞先生", "裴先生","彭先生", "皮先生", "濮先生","蓬先生", "逄先生", "浦先生",
76 | //Q
77 | "戚先生", "齐先生", "祁先生","乔先生", "屈先生", "钱先生","秦先生", "邱先生", "裘先生",
78 | //R
79 | "冉先生", "饶先生", "任先生","阮先生", "芮先生", "戎先生","容先生", "荣先生", "融先生",
80 | //S
81 | "宋先生", "舒先生", "苏先生","孙先生", "索先生", "沈先生","邵先生", "施先生", "石先生",
82 | //T
83 | "邰先生", "谭先生", "陶先生","唐先生", "汤先生", "田先生","佟先生", "屠先生", "滕先生",
84 | //W
85 | "万先生", "邬先生", "乌先生","吴先生", "伍先生", "武先生","王先生", "韦先生", "魏先生",
86 | //X
87 | "奚先生", "席先生", "习先生","夏先生", "萧先生", "熊先生","项先生", "徐先生", "许先生",
88 | //Y
89 | "燕先生", "鄢先生", "颜先生","闫先生", "阎先生", "晏先生","姚先生", "杨先生", "叶先生",
90 | //Z
91 | "翟先生", "张先生", "章先生","赵先生", "甄先生", "曾先生","周先生", "郑先生", "祝先生",
92 | };
93 |
94 | private ArrayList contactList;
95 | @Override
96 | protected void onCreate(Bundle savedInstanceState) {
97 | super.onCreate(savedInstanceState);
98 | setContentView(R.layout.activity_main);
99 | contactList = dataList();
100 | //2.对数据进行排序
101 | initView();
102 | initEvent();
103 | initData();
104 | }
105 | private void initView() {
106 | sideLetterBar = (SideLetterBar) findViewById(R.id.sideLetterBar);
107 | lv_contact = (ListView) findViewById(R.id.lv_contact);
108 | lv_alphabet = (ListView) findViewById(R.id.lv_alphabet);
109 | tv_notice = (TextView) findViewById(R.id.tv_notice);
110 | rel_notice = (RelativeLayout) findViewById(R.id.rel_notice);
111 | et_clear = (ClearEditText) findViewById(R.id.et_clear);
112 | tv_alphabet = (TextView) findViewById(R.id.tv_alphabet);
113 | rel_notice.post(new Runnable() {
114 | @Override
115 | public void run() {
116 | tv_notice.getHeight();
117 | RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) rel_notice.getLayoutParams();
118 | params.height = tv_notice.getHeight()*5;
119 | params.width = tv_notice.getWidth();
120 | rel_notice.setLayoutParams(params);
121 | }
122 | });
123 | }
124 | private void initEvent() {
125 | sideLetterBar.setOnTouchLetterListener(new SideLetterBar.OnTouchLetterListener() {
126 | @Override
127 | public void onTouchLetter(String letter) {
128 | alphabetList.clear();
129 | ViewPropertyAnimator.animate(rel_notice).alpha(1f).setDuration(0).start();
130 | //根据当前触摸的字母,去集合中找那个item的首字母和letter一样,然后将对应的item放到屏幕顶端
131 | for (int i = 0; i < contactList.size(); i++) {
132 | String firstAlphabet = contactList.get(i).getPinyin().charAt(0)+"";
133 | if(letter.equals(firstAlphabet)){
134 | lv_contact.setSelection(i);
135 | rel_notice.setVisibility(View.VISIBLE);
136 | break;
137 | }
138 | if(letter.equals("#")){
139 | lv_contact.setSelection(0);
140 | rel_notice.setVisibility(View.GONE);
141 | }
142 | }
143 | for (int i = 0; i < contactList.size(); i++) {
144 | String firstAlphabet = contactList.get(i).getPinyin().toString().trim().charAt(0)+"";
145 |
146 | if(letter.equals(firstAlphabet)){
147 | //说明找到了,那么应该讲当前的item放到屏幕顶端
148 | tv_notice.setText(letter);
149 | if(!alphabetList.contains(String.valueOf(contactList.get(i).getName().trim().charAt(0)))){
150 | alphabetList.add(String.valueOf(contactList.get(i).getName().trim().charAt(0)));
151 | }
152 | }
153 |
154 | }
155 | showCurrentWord(letter);
156 | //显示当前触摸的字母
157 |
158 | AlphabetAdp alphabetAdp = new AlphabetAdp(MainActivity.this,alphabetList);
159 | lv_alphabet.setAdapter(alphabetAdp);
160 | alphabetAdp.notifyDataSetChanged();
161 | }
162 | });
163 | lv_contact.setOnScrollListener(new AbsListView.OnScrollListener() {
164 | @Override
165 | public void onScrollStateChanged(AbsListView absListView, int scrollState) {
166 | if(scrollState== AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL){
167 | //如果垂直滑动,则需要关闭已经打开的layout
168 | SwipeManager.getInstance().closeCurrentLayout();
169 | }
170 |
171 | }
172 |
173 | @Override
174 | public void onScroll(AbsListView absListView, int firstVisibleItem,
175 | int visibleItemCount, int totalItemCount) {
176 | int pos = lv_contact.getFirstVisiblePosition();
177 | if (contactList.size()>0){
178 | tv_alphabet.setVisibility(View.VISIBLE);
179 | String text = contactList.get(pos).getPinyin().charAt(0)+"";
180 | Pattern p = Pattern.compile("[0-9]*");
181 | Matcher m1 = p.matcher(text);
182 | if(m1.matches()){
183 | tv_alphabet.setText("#");
184 | }else {
185 | tv_alphabet.setText(text);
186 | }
187 | }else {
188 | tv_alphabet.setVisibility(View.GONE);
189 | }
190 | }
191 | });
192 | et_clear.addTextChangedListener(new TextWatcher() {
193 |
194 | @Override
195 | public void onTextChanged(CharSequence s, int start, int before, int count) {
196 | //当输入框里面的值为空,更新为原来的列表,否则为过滤数据列表
197 | fuzzySearch(s.toString());
198 | }
199 |
200 | @Override
201 | public void beforeTextChanged(CharSequence s, int start, int count,
202 | int after) {
203 |
204 | }
205 |
206 | @Override
207 | public void afterTextChanged(Editable s) {
208 | }
209 | });
210 | lv_alphabet.setOnItemClickListener(new AdapterView.OnItemClickListener() {
211 | @Override
212 | public void onItemClick(AdapterView> adapterView, View view, int position, long id) {
213 | String alphabet = alphabetList.get(position).trim();
214 | setIsVisiable();
215 | for (int i = 0;i();
236 | }
237 |
238 | protected void showCurrentWord(String letter) {
239 | tv_notice.setText(letter);
240 | setIsVisiable();
241 | }
242 | private Handler handler = new Handler();
243 | private void setIsVisiable(){
244 | handler.removeCallbacksAndMessages(null);
245 | handler.postDelayed(new Runnable() {
246 | @Override
247 | public void run() {
248 | ViewPropertyAnimator.animate(rel_notice).alpha(0f).setDuration(1000).start();
249 | }
250 | }, 4000);
251 | }
252 | private ArrayList dataList() {
253 | // 虚拟数据
254 | ArrayList mSortList = new ArrayList();
255 | for(int i=0;i filterDateList = new ArrayList();
265 | // 虚拟数据
266 | if (TextUtils.isEmpty(str)){
267 | sideLetterBar.setVisibility(View.VISIBLE);
268 | filterDateList = dataList();
269 | }else {
270 | filterDateList.clear();
271 | sideLetterBar.setVisibility(View.GONE);
272 | for(ContactBean contactBean : dataList()){
273 | String name = contactBean.getName();
274 | Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
275 | Matcher m = p.matcher(str);
276 | if(m.matches()){
277 | str = PinYinUtil.getPinyin(str);
278 | }
279 | if(PinYinUtil.getPinyin(name).contains(str.toUpperCase())|| contactBean.pinYinStyle.briefnessSpell.toUpperCase().contains(str.toUpperCase())
280 | || contactBean.pinYinStyle.completeSpell.toUpperCase().contains(str.toUpperCase())){
281 | filterDateList.add(contactBean);
282 | }
283 | }
284 | }
285 | contactList = filterDateList;
286 | adapter = new ContactAdapter(this,filterDateList);
287 | lv_contact.setAdapter(adapter);
288 | adapter.notifyDataSetChanged();
289 | }
290 | public PinYinStyle parsePinYinStyle(String content) {
291 | PinYinStyle pinYinStyle = new PinYinStyle();
292 | if (content != null && content.length() > 0) {
293 | //其中包含的中文字符
294 | String[] enStrs = new String[content.length()];
295 | for (int i=0;i 0) {
300 | //拼接简拼
301 | pinYinStyle.briefnessSpell += enStrs[i].charAt(0);
302 | }
303 | }
304 | }
305 | return pinYinStyle;
306 | }
307 | }
--------------------------------------------------------------------------------
/app/src/main/java/lyx/robert/quicksearch/adapter/AlphabetAdp.java:
--------------------------------------------------------------------------------
1 | package lyx.robert.quicksearch.adapter;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.BaseAdapter;
7 | import android.widget.TextView;
8 |
9 | import java.util.List;
10 |
11 | import lyx.robert.quicksearch.R;
12 |
13 | /**
14 | * Created by ytx on 2016/11/15.
15 | */
16 | public class AlphabetAdp extends BaseAdapter{
17 | private Context context;
18 | ListmList;
19 |
20 | public AlphabetAdp(Context context, List mList) {
21 | this.context = context;
22 | this.mList = mList;
23 | }
24 |
25 | @Override
26 | public int getCount() {
27 | return mList!=null?mList.size():0;
28 | }
29 |
30 | @Override
31 | public Object getItem(int i) {
32 | return mList.get(i);
33 | }
34 |
35 | @Override
36 | public long getItemId(int i) {
37 | return i;
38 | }
39 |
40 | @Override
41 | public View getView(int position, View convertView, ViewGroup parent) {
42 | ViewHolder holder;
43 | if(convertView==null){
44 | holder = new ViewHolder();
45 | convertView = View.inflate(context, R.layout.layout_alphabet,null);
46 | holder.tv_alphabet = (TextView) convertView.findViewById(R.id.tv_alphabet);
47 | convertView.setTag(holder);
48 | }else {
49 | holder = (ViewHolder) convertView.getTag();
50 | }
51 | holder.tv_alphabet.setText(mList.get(position));
52 | return convertView;
53 | }
54 | class ViewHolder{
55 | TextView tv_alphabet;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/lyx/robert/quicksearch/adapter/ContactAdapter.java:
--------------------------------------------------------------------------------
1 | package lyx.robert.quicksearch.adapter;
2 |
3 | import java.util.ArrayList;
4 |
5 | import android.content.Context;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.BaseAdapter;
9 | import android.widget.TextView;
10 |
11 | import lyx.robert.quicksearch.Bean.ContactBean;
12 | import lyx.robert.quicksearch.Bean.PinYinStyle;
13 | import lyx.robert.quicksearch.R;
14 | import lyx.robert.quicksearch.view.SwipeLayout;
15 |
16 | public class ContactAdapter extends BaseAdapter implements SwipeLayout.SwipeListener {
17 | private Context context;
18 | private ArrayList list;
19 | public PinYinStyle sortToken;
20 | public ContactAdapter(Context context, ArrayList list) {
21 | super();
22 | this.context = context;
23 | this.list = list;
24 | sortToken = new PinYinStyle();
25 | }
26 |
27 | @Override
28 | public int getCount() {
29 | return list.size();
30 | }
31 | @Override
32 | public Object getItem(int position) {
33 | return null;
34 | }
35 | @Override
36 | public long getItemId(int position) {
37 | return 0;
38 | }
39 | @Override
40 | public View getView(int position, View convertView, ViewGroup parent) {
41 | if(convertView==null){
42 | convertView = View.inflate(context, R.layout.item_contact,null);
43 | }
44 |
45 | ViewHolder holder = ViewHolder.getHolder(convertView);
46 | //设置数据
47 | ContactBean contactBean = list.get(position);
48 | holder.tv_contact_name.setText(contactBean.getName());
49 | holder.swp_slip.setTag(position);
50 | holder.swp_slip.setOnSwipeListener(this);
51 | String currentAlphabet=contactBean.getPinyin().charAt(0)+"";
52 | if(position>0){
53 | String lastAlphabet = list.get(position-1).getPinyin().charAt(0)+"";
54 | //获取上一个item的首字母
55 |
56 | if(currentAlphabet.equals(lastAlphabet)){
57 | //首字母相同,需要隐藏当前item的字母的TextView
58 | holder.tv_first_alphabet.setVisibility(View.GONE);
59 | }else {
60 | //不相同就要显示当前的首字母
61 | holder.tv_first_alphabet.setVisibility(View.VISIBLE);
62 | holder.tv_first_alphabet.setText(currentAlphabet);
63 | }
64 | }else {
65 | holder.tv_first_alphabet.setVisibility(View.VISIBLE);
66 | holder.tv_first_alphabet.setText(currentAlphabet);
67 | }
68 | return convertView;
69 | }
70 |
71 | @Override
72 | public void onOpen(Object obj) {
73 | }
74 | @Override
75 | public void onClose(Object obj) {
76 | }
77 |
78 | static class ViewHolder{
79 | TextView tv_contact_name;
80 | TextView tv_first_alphabet;
81 | SwipeLayout swp_slip;
82 | public ViewHolder(View convertView){
83 | tv_contact_name = (TextView) convertView.findViewById(R.id.tv_contact_name);
84 | tv_first_alphabet = (TextView) convertView.findViewById(R.id.tv_first_alphabet);
85 | swp_slip = (SwipeLayout) convertView.findViewById(R.id.swp_slip);
86 | }
87 | public static ViewHolder getHolder(View convertView){
88 | ViewHolder holder = (ViewHolder) convertView.getTag();
89 | if(holder==null){
90 | holder = new ViewHolder(convertView);
91 | convertView.setTag(holder);
92 | }
93 | return holder;
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/app/src/main/java/lyx/robert/quicksearch/utils/DisplayUtil.java:
--------------------------------------------------------------------------------
1 | package lyx.robert.quicksearch.utils;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * dp、sp 转换为 px 的工具类
7 | *
8 | */
9 | public class DisplayUtil {
10 |
11 | /**
12 | * 将px值转换为dip或dp值,保证尺寸大小不变
13 | *
14 | * @param pxValue
15 | * @param scale
16 | * (DisplayMetrics类中属性density)
17 | * @return
18 | */
19 | public static int px2dip(Context context, float pxValue) {
20 | final float scale = context.getResources().getDisplayMetrics().density;
21 | return (int) (pxValue / scale + 0.5f);
22 | }
23 |
24 | /**
25 | * 将dip或dp值转换为px值,保证尺寸大小不变
26 | *
27 | * @param dipValue
28 | * @param scale
29 | * (DisplayMetrics类中属性density)
30 | * @return
31 | */
32 | public static int dip2px(Context context, float dipValue) {
33 | final float scale = context.getResources().getDisplayMetrics().density;
34 | return (int) (dipValue * scale + 0.5f);
35 | }
36 |
37 | /**
38 | * 将px值转换为sp值,保证文字大小不变
39 | *
40 | * @param pxValue
41 | * @param fontScale
42 | * (DisplayMetrics类中属性scaledDensity)
43 | * @return
44 | */
45 | public static int px2sp(Context context, float pxValue) {
46 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
47 | return (int) (pxValue / fontScale + 0.5f);
48 | }
49 |
50 | /**
51 | * 将sp值转换为px值,保证文字大小不变
52 | *
53 | * @param spValue
54 | * @param fontScale
55 | * (DisplayMetrics类中属性scaledDensity)
56 | * @return
57 | */
58 | public static int sp2px(Context context, float spValue) {
59 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
60 | return (int) (spValue * fontScale + 0.5f);
61 | }
62 | }
--------------------------------------------------------------------------------
/app/src/main/java/lyx/robert/quicksearch/utils/PinYinUtil.java:
--------------------------------------------------------------------------------
1 | package lyx.robert.quicksearch.utils;
2 |
3 | import android.text.TextUtils;
4 |
5 | import net.sourceforge.pinyin4j.PinyinHelper;
6 | import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
7 | import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
8 | import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
9 | import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
10 |
11 | public class PinYinUtil {
12 | /**
13 | * 获取汉字的拼音,会销毁一定的资源,所以不应该被频繁调用
14 | * @param chinese
15 | */
16 | public static String getPinyin(String chinese){
17 | if(TextUtils.isEmpty(chinese)) return null;
18 |
19 | //用来设置转化的拼音的大小写,或者声调
20 | HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
21 | format.setCaseType(HanyuPinyinCaseType.UPPERCASE);//设置转化的拼音是大写字母
22 | format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);//设置转化的拼音不带声调
23 |
24 | //1.由于只能对单个汉字转化,所以需要将字符串转化为字符数组,然后对每个字符转化,最后拼接起来
25 | char[] charArray = chinese.toCharArray();
26 | String pinyin = "";
27 | for (int i = 0; i < charArray.length; i++) {
28 | //2.过滤空格
29 | if(Character.isWhitespace(charArray[i]))continue;
30 |
31 | //3.需要判断是否是汉字
32 | //汉字占2个字节,一个字节范围是-128~127,那么汉字肯定大于127
33 | if(charArray[i]>127){
34 | //可能是汉字
35 | try {
36 | //由于多音字的存在,比如单 dan shan,
37 | String[] pinyinArr = PinyinHelper.toHanyuPinyinStringArray(charArray[i],format);
38 | if(pinyinArr!=null){
39 | pinyin += pinyinArr[0];//此处即使有多音字,那么也只能取第一个拼音
40 | }else {
41 | //说明没有找到对应的拼音,汉字有问题,或者可能不是汉字,则忽略
42 | }
43 | } catch (BadHanyuPinyinOutputFormatCombination e) {
44 | e.printStackTrace();
45 | //说明转化失败,不是汉字,比如O(∩_∩)O~,那么则忽略
46 | }
47 | }else {
48 | //肯定不是汉字,应该是键盘上能够直接输入的字符,这些字符能够排序,但不能获取拼音
49 | //所以可以直接拼接
50 | pinyin += charArray[i];
51 | }
52 | }
53 | return pinyin;
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/app/src/main/java/lyx/robert/quicksearch/utils/SwipeManager.java:
--------------------------------------------------------------------------------
1 | package lyx.robert.quicksearch.utils;
2 |
3 | import lyx.robert.quicksearch.view.SwipeLayout;
4 |
5 | public class SwipeManager {
6 | private SwipeManager(){}
7 | private static SwipeManager mInstance = new SwipeManager();
8 |
9 | public static SwipeManager getInstance(){
10 | return mInstance;
11 | }
12 |
13 | private SwipeLayout currentLayout;//用来记录当前打开的SwipeLayout
14 | public void setSwipeLayout(SwipeLayout layout){
15 | this.currentLayout = layout;
16 | }
17 |
18 | public void clearCurrentLayout(){
19 | currentLayout = null;
20 | }
21 |
22 | public void closeCurrentLayout(){
23 | if(currentLayout!=null){
24 | currentLayout.close();
25 | }
26 | }
27 |
28 | public boolean isSwipe(SwipeLayout swipeLayout){
29 | if(currentLayout==null){
30 | //说明当前没有打开的layout
31 | return true;
32 | }else {
33 | //说明有打开的layout
34 | return currentLayout==swipeLayout;
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/java/lyx/robert/quicksearch/view/ClearEditText.java:
--------------------------------------------------------------------------------
1 | package lyx.robert.quicksearch.view;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 | import android.text.Editable;
6 | import android.text.TextWatcher;
7 | import android.util.AttributeSet;
8 | import android.view.MotionEvent;
9 | import android.view.View;
10 | import android.view.View.OnFocusChangeListener;
11 | import android.widget.EditText;
12 |
13 | import lyx.robert.quicksearch.R;
14 |
15 | public class ClearEditText extends EditText implements
16 | OnFocusChangeListener, TextWatcher {
17 | /**
18 | * 删除按钮的引用
19 | */
20 | private Drawable mClearDrawable;
21 |
22 | public ClearEditText(Context context) {
23 | this(context, null);
24 | }
25 |
26 | public ClearEditText(Context context, AttributeSet attrs) {
27 | //这里构造方法也很重要,不加这个很多属性不能再XML里面定义
28 | this(context, attrs, android.R.attr.editTextStyle);
29 | }
30 |
31 | public ClearEditText(Context context, AttributeSet attrs, int defStyle) {
32 | super(context, attrs, defStyle);
33 | init();
34 | }
35 |
36 |
37 | private void init() {
38 | //获取EditText的DrawableRight,假如没有设置我们就使用默认的图片
39 | mClearDrawable = getCompoundDrawables()[2];
40 | if (mClearDrawable == null) {
41 | mClearDrawable = getResources()
42 | .getDrawable(R.drawable.icon_delete);
43 | }
44 | mClearDrawable.setBounds(0, 0, mClearDrawable.getIntrinsicWidth(), mClearDrawable.getIntrinsicHeight());
45 | setClearIconVisible(false);
46 | setOnFocusChangeListener(this);
47 | addTextChangedListener(this);
48 | }
49 |
50 |
51 | /**
52 | * 因为我们不能直接给EditText设置点击事件,所以我们用记住我们按下的位置来模拟点击事件
53 | * 当我们按下的位置 在 EditText的宽度 - 图标到控件右边的间距 - 图标的宽度 和
54 | * EditText的宽度 - 图标到控件右边的间距之间我们就算点击了图标,竖直方向没有考虑
55 | */
56 | @Override
57 | public boolean onTouchEvent(MotionEvent event) {
58 | if (getCompoundDrawables()[2] != null) {
59 | if (event.getAction() == MotionEvent.ACTION_UP) {
60 | boolean touchable = event.getX() > (getWidth()
61 | - getPaddingRight() - mClearDrawable.getIntrinsicWidth())
62 | && (event.getX() < ((getWidth() - getPaddingRight())));
63 | if (touchable) {
64 | this.setText("");
65 | }
66 | }
67 | }
68 |
69 | return super.onTouchEvent(event);
70 | }
71 |
72 | /**
73 | * 当ClearEditText焦点发生变化的时候,判断里面字符串长度设置清除图标的显示与隐藏
74 | */
75 | @Override
76 | public void onFocusChange(View v, boolean hasFocus) {
77 | if (hasFocus) {
78 | setClearIconVisible(getText().length() > 0);
79 | } else {
80 | setClearIconVisible(false);
81 | }
82 | }
83 |
84 |
85 | /**
86 | * 设置清除图标的显示与隐藏,调用setCompoundDrawables为EditText绘制上去
87 | * @param visible
88 | */
89 | protected void setClearIconVisible(boolean visible) {
90 | Drawable right = visible ? mClearDrawable : null;
91 | setCompoundDrawables(getCompoundDrawables()[0],
92 | getCompoundDrawables()[1], right, getCompoundDrawables()[3]);
93 | }
94 |
95 | /**
96 | * 当输入框里面内容发生变化的时候回调的方法
97 | */
98 | @Override
99 | public void onTextChanged(CharSequence s, int start, int count,
100 | int after) {
101 | setClearIconVisible(s.length() > 0);
102 | }
103 |
104 | @Override
105 | public void beforeTextChanged(CharSequence s, int start, int count,
106 | int after) {
107 |
108 | }
109 |
110 | @Override
111 | public void afterTextChanged(Editable s) {
112 |
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/app/src/main/java/lyx/robert/quicksearch/view/SideLetterBar.java:
--------------------------------------------------------------------------------
1 | package lyx.robert.quicksearch.view;
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.Rect;
8 | import android.graphics.Paint.Align;
9 | import android.util.AttributeSet;
10 | import android.view.MotionEvent;
11 | import android.view.View;
12 |
13 | import lyx.robert.quicksearch.utils.DisplayUtil;
14 |
15 | public class SideLetterBar extends View{
16 | private String[] mSideLetter = { "#","A", "B", "C", "D", "E", "F", "G", "H",
17 | "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U",
18 | "V", "W", "X", "Y", "Z",};
19 | private Paint paint;
20 | private int letterWidth;
21 | private float letterHeight;
22 | public SideLetterBar(Context context, AttributeSet attrs, int defStyle) {
23 | super(context, attrs, defStyle);
24 | init(context);
25 | }
26 |
27 | public SideLetterBar(Context context, AttributeSet attrs) {
28 | super(context, attrs);
29 | init(context);
30 | }
31 |
32 | public SideLetterBar(Context context) {
33 | super(context);
34 | init(context);
35 | }
36 |
37 | private void init(Context context){
38 | paint = new Paint(Paint.ANTI_ALIAS_FLAG);//设置抗锯齿
39 | paint.setColor(Color.WHITE);
40 | paint.setTextSize(new DisplayUtil().dip2px(context,16));
41 | paint.setTextAlign(Align.CENTER);////设置文本居中对齐
42 | }
43 |
44 | @Override
45 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
46 | super.onSizeChanged(w, h, oldw, oldh);
47 | letterWidth = getMeasuredWidth();
48 | //得到一个字母要显示的高度
49 | letterHeight = getMeasuredHeight()*1f/mSideLetter .length;
50 | }
51 |
52 | @Override
53 | protected void onDraw(Canvas canvas) {
54 | super.onDraw(canvas);
55 | for (int i = 0; i < mSideLetter .length; i++) {
56 | float x = letterWidth/2;
57 | float y = letterHeight/2 + getTextHeight(mSideLetter [i])/2 + i*letterHeight;
58 |
59 | paint.setColor(lastIndex==i?Color.BLACK:Color.WHITE);
60 |
61 | canvas.drawText(mSideLetter [i], x, y, paint);
62 | }
63 | }
64 | private int lastIndex = -1;//标记上次的触摸字母的索引
65 | @Override
66 | public boolean onTouchEvent(MotionEvent event) {
67 | switch (event.getAction()) {
68 | case MotionEvent.ACTION_DOWN:
69 | case MotionEvent.ACTION_MOVE:
70 | float touchY = event.getY();
71 | int index = (int) (touchY/letterHeight);//得到字母对应的索引
72 | if(lastIndex!=index){
73 | //判断当前触摸字母跟上次触摸的是不是同一个字母
74 | if(index>=0 && indexMath.abs(delatY)){
108 | //表示移动是偏向于水平方向,那么应该SwipeLayout应该处理,请求listview不要拦截
109 | requestDisallowInterceptTouchEvent(true);
110 | }
111 | //更新downX,downY
112 | downX = moveX;
113 | downY = moveY;
114 | break;
115 | case MotionEvent.ACTION_UP:
116 |
117 | break;
118 | }
119 | mDrag.processTouchEvent(event);
120 | return true;
121 | }
122 |
123 | private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
124 | //返回值就是当前捕捉到的也就是你当前拖拽的某个子View
125 | @Override
126 | public boolean tryCaptureView(View child, int pointerId) {
127 | return child==contentView||child==slipView;
128 | }
129 | //返回值是可以水平拖拽的范围
130 | @Override
131 | public int getViewHorizontalDragRange(View child) {
132 | return slipWidth;
133 | }
134 | //手指触摸移动时实时回调, left表示要移动到的x位置,dx表示移动的距离
135 | @Override
136 | public int clampViewPositionHorizontal(View child, int left, int dx) {
137 | if(child==contentView){
138 | if(left>0)left = 0;
139 | if(left<-slipWidth)left = -slipWidth;
140 | }else if (child==slipView) {
141 | if(left>contentWidth)left = contentWidth;
142 | if(left<(contentWidth-slipWidth))left = contentWidth-slipWidth;
143 | }
144 | return left;
145 | }
146 | //拖拽的子View完全挪出屏幕则防止过度绘制
147 | @Override
148 | public void onViewPositionChanged(View changedView, int left, int top,
149 | int dx, int dy) {
150 | super.onViewPositionChanged(changedView, left, top, dx, dy);
151 | if(changedView==contentView){
152 | //手动移动slipView
153 | slipView.layout(slipView.getLeft()+dx,slipView.getTop()+dy,
154 | slipView.getRight()+dx, slipView.getBottom()+dy);
155 | }else if (slipView==changedView) {
156 | //手动移动contentView
157 | contentView.layout(contentView.getLeft()+dx,contentView.getTop()+dy,
158 | contentView.getRight()+dx, contentView.getBottom()+dy);
159 | }
160 |
161 | //判断开和关闭的逻辑
162 | if(contentView.getLeft()==0 && currentState!=SwipeState.Close){
163 | //说明应该将state更改为关闭
164 | currentState = SwipeState.Close;
165 |
166 | //回调接口关闭的方法
167 | if(swipeListener!=null){
168 | swipeListener.onClose(getTag());
169 | }
170 |
171 | //说明当前的SwipeLayout已经关闭,需要让Manager清空一下
172 | SwipeManager.getInstance().clearCurrentLayout();
173 | }else if (contentView.getLeft()==-slipWidth && currentState!=SwipeState.Open) {
174 | //说明应该将state更改为开
175 | currentState = SwipeState.Open;
176 |
177 | //回调接口打开的方法
178 | if(swipeListener!=null){
179 | swipeListener.onOpen(getTag());
180 | }
181 | //当前的Swipelayout已经打开,需要让Manager记录一下下
182 | SwipeManager.getInstance().setSwipeLayout(SwipeLayout.this);
183 | }
184 | }
185 | //手指释放时回调此方法
186 | @Override
187 | public void onViewReleased(View releasedChild, float xvel, float yvel) {
188 | super.onViewReleased(releasedChild, xvel, yvel);
189 | if(contentView.getLeft()<-slipWidth/2){
190 | //如果滑动的内容大于侧滑内容的一半应当打开
191 | open();
192 | }else {
193 | //否则就是关闭
194 | close();
195 | }
196 | }
197 | };
198 | /**
199 | * 打开的方法
200 | */
201 | public void open() {
202 | mDrag.smoothSlideViewTo(contentView,-slipWidth,contentView.getTop());
203 | ViewCompat.postInvalidateOnAnimation(SwipeLayout.this);
204 | }
205 | /**
206 | * 关闭的方法
207 | */
208 | public void close() {
209 | mDrag.smoothSlideViewTo(contentView,0,contentView.getTop());
210 | ViewCompat.postInvalidateOnAnimation(SwipeLayout.this);
211 | }
212 | public void computeScroll() {
213 | if(mDrag.continueSettling(true)){
214 | ViewCompat.postInvalidateOnAnimation(this);
215 | }
216 | }
217 |
218 | private SwipeListener swipeListener;
219 | public void setOnSwipeListener(SwipeListener listener){
220 | this.swipeListener = listener;
221 | }
222 |
223 | public interface SwipeListener{
224 | void onOpen(Object obj);
225 | void onClose(Object obj);
226 | }
227 | }
228 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/pop_push_down_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/pop_push_up_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyxRobert/QuickSearch-A-Z/c3895888e03565631b8ff1ed4f47f02a5ba84080/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/icon_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyxRobert/QuickSearch-A-Z/c3895888e03565631b8ff1ed4f47f02a5ba84080/app/src/main/res/drawable-hdpi/icon_delete.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/icon_side_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyxRobert/QuickSearch-A-Z/c3895888e03565631b8ff1ed4f47f02a5ba84080/app/src/main/res/drawable-hdpi/icon_side_delete.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/icon_side_phone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyxRobert/QuickSearch-A-Z/c3895888e03565631b8ff1ed4f47f02a5ba84080/app/src/main/res/drawable-hdpi/icon_side_phone.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/icon_side_sms.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyxRobert/QuickSearch-A-Z/c3895888e03565631b8ff1ed4f47f02a5ba84080/app/src/main/res/drawable-hdpi/icon_side_sms.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyxRobert/QuickSearch-A-Z/c3895888e03565631b8ff1ed4f47f02a5ba84080/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyxRobert/QuickSearch-A-Z/c3895888e03565631b8ff1ed4f47f02a5ba84080/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyxRobert/QuickSearch-A-Z/c3895888e03565631b8ff1ed4f47f02a5ba84080/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/icon_sms.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyxRobert/QuickSearch-A-Z/c3895888e03565631b8ff1ed4f47f02a5ba84080/app/src/main/res/drawable-xxhdpi/icon_sms.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyxRobert/QuickSearch-A-Z/c3895888e03565631b8ff1ed4f47f02a5ba84080/app/src/main/res/drawable-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/header_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/search_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
11 |
12 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
12 |
13 |
22 |
33 |
40 |
41 |
42 |
50 |
59 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_contact.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
17 |
21 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_alphabet.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_slip.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
15 |
24 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #9A9999
7 | #c0392b
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | "QuickSearch "
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/test/java/lyx/robert/quicksearch/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package lyx.robert.quicksearch;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.0.0'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyxRobert/QuickSearch-A-Z/c3895888e03565631b8ff1ed4f47f02a5ba84080/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------