├── .gitignore
├── .idea
├── caches
│ └── build_file_checksums.ser
├── codeStyles
│ └── Project.xml
├── gradle.xml
├── misc.xml
├── runConfigurations.xml
└── vcs.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── libs
│ └── pinyin4j-2.5.0.jar
├── proguard-rules.pro
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ └── city_db_53.db
│ ├── java
│ │ └── com
│ │ │ └── address
│ │ │ └── xiaolei
│ │ │ └── addressselect
│ │ │ ├── MainActivity.java
│ │ │ ├── adapter
│ │ │ └── PickCityAdapter.java
│ │ │ ├── sqlutil
│ │ │ └── DBManager.java
│ │ │ ├── utils
│ │ │ ├── FileUtil.java
│ │ │ ├── PinyinUtil.java
│ │ │ ├── RxUtils.java
│ │ │ └── UiUtils.java
│ │ │ ├── view
│ │ │ ├── FloatingItemDecoration.java
│ │ │ └── SlideBar.java
│ │ │ └── vo
│ │ │ └── CityVo.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable-xhdpi
│ │ ├── ic_clear_gray.png
│ │ └── ic_search_small_2.png
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── item_city.xml
│ │ └── layout_city_header.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ ├── styles.xml
│ │ └── values.xml
│ └── test
│ └── java
│ └── com
│ └── address
│ └── xiaolei
│ └── addressselect
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── img
├── GIF.gif
├── device-2019-01-17-185749.png
├── device-2019-01-17-185822.png
└── sql.png
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/libraries
5 | /.idea/modules.xml
6 | /.idea/workspace.xml
7 | .DS_Store
8 | /build
9 | /captures
10 |
11 | .externalNativeBuild
12 |
--------------------------------------------------------------------------------
/.idea/caches/build_file_checksums.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sky8650/AddressSelect/8540208b47703b69f83d4893dcd837b715d5014a/.idea/caches/build_file_checksums.ser
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.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 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AddressSelect
2 | 在一些项目中经常会用到把一个列表的数据源按照一定的顺序分组排序例如联系人,日期,地址选择等。
3 | 效果如下图所示
4 |
5 | # Example
6 |
9 |
10 | # Uasage
11 |
12 | ## 从数据库读取数据源
13 | ```
14 | Observable.just(dbManager).map(new Function() {
15 | @Override
16 | public Object apply(DBManager dbManager) throws Exception {
17 | sqLiteDatabase = dbManager.initDataBase(getPackageName());
18 | String[] columns = new String[]//列属性
19 | {"cityType", "cityID", "cityName", "parentId"};
20 | String selection = "cityType=?";
21 | String[] selectionArgs = new String[]{"3"};//type为3时查询的是市
22 | List cityVoList = dbManager.query(sqLiteDatabase, columns, selection, selectionArgs);
23 | sqLiteDatabase.close();
24 | return cityVoList;
25 | }
26 | }).compose(RxUtils.schedulersTransformer()).subscribe(new Consumer>() {
27 | @Override
28 | public void accept(List cityVoList) throws Exception {
29 | doData(cityVoList);
30 | }
31 | });
32 | ```
33 | ## 把数据源进行排序
34 | ```
35 | Observable.fromIterable(cityVoList).
36 | toSortedList(new Comparator() {
37 | @Override
38 | public int compare(CityVo o1, CityVo o2) {
39 | //a-z排序
40 | String a = o1.getPinYin();
41 | String b = o2.getPinYin();
42 | return a.compareTo(b);
43 | }
44 | }).subscribe(new Consumer>() {
45 | @Override
46 | public void accept(List cityVoList) throws Exception {
47 | pickCityAdapter.addHeaderView(headerView);
48 | pickCityAdapter.setNewData(cityVoList);
49 | //添加了头部,所以keys要从1开始
50 | keys.put(1, "A");
51 | letterIndexes.put("#", 0);
52 | letterIndexes.put("A", 1);
53 | for (int i = 0; i < cityVoList.size(); i++) {
54 | if (i < cityVoList.size() - 1) {
55 | //首字母不同,设为ky
56 | String pre = cityVoList.get(i).getPinYin().substring(0, 1).toUpperCase();
57 | String next = cityVoList.get(i + 1).getPinYin().substring(0, 1).toUpperCase();
58 | if (!pre.equals(next)) {
59 | keys.put(i + 2, next);
60 | letterIndexes.put(next, i + 2);
61 | }
62 | }
63 | }
64 | floatingItemDecoration.setKeys(keys);
65 | }
66 | });
67 | ```
68 | ## 项目数据源为本地数据库读取,数据库结构如下(也可从网络动态获取)
69 |
71 |
72 |
73 | ### 备注: 这里用到了一个把汉字转拼音的jar,pinyin4j-2.5.0.jar https://github.com/sky8650/AddressSelect/blob/master/app/libs/pinyin4j-2.5.0.jar
74 |
75 | #### 如果您感觉此项目对您有帮助,请点个star哦…
76 |
77 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 28
5 | defaultConfig {
6 | applicationId "com.address.xiaolei.addressselect"
7 | minSdkVersion 15
8 | targetSdkVersion 28
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | implementation fileTree(include: ['*.jar'], dir: 'libs')
23 | implementation 'com.android.support:appcompat-v7:28.0.0'
24 | implementation 'com.android.support.constraint:constraint-layout:1.1.3'
25 | implementation 'io.reactivex.rxjava2:rxjava:2.1.0'
26 | implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
27 | implementation 'com.android.support:recyclerview-v7:28.0.0'
28 | implementation 'com.trello.rxlifecycle2:rxlifecycle-components:2.0.1'
29 | implementation 'com.jakewharton:butterknife:8.5.1'
30 | api 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30'
31 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'
32 | implementation 'com.google.code.gson:gson:2.8.5'
33 | }
34 |
--------------------------------------------------------------------------------
/app/libs/pinyin4j-2.5.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sky8650/AddressSelect/8540208b47703b69f83d4893dcd837b715d5014a/app/libs/pinyin4j-2.5.0.jar
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
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 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/app/src/main/assets/city_db_53.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sky8650/AddressSelect/8540208b47703b69f83d4893dcd837b715d5014a/app/src/main/assets/city_db_53.db
--------------------------------------------------------------------------------
/app/src/main/java/com/address/xiaolei/addressselect/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.address.xiaolei.addressselect;
2 |
3 | import android.database.sqlite.SQLiteDatabase;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.support.v7.widget.GridLayoutManager;
7 | import android.support.v7.widget.LinearLayoutManager;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.support.v7.widget.SearchView;
10 | import android.util.Log;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.RelativeLayout;
14 | import android.widget.Toast;
15 |
16 | import com.address.xiaolei.addressselect.adapter.PickCityAdapter;
17 | import com.address.xiaolei.addressselect.sqlutil.DBManager;
18 | import com.address.xiaolei.addressselect.utils.PinyinUtil;
19 | import com.address.xiaolei.addressselect.utils.RxUtils;
20 | import com.address.xiaolei.addressselect.utils.UiUtils;
21 | import com.address.xiaolei.addressselect.view.FloatingItemDecoration;
22 | import com.address.xiaolei.addressselect.view.SlideBar;
23 | import com.address.xiaolei.addressselect.vo.CityVo;
24 | import com.chad.library.adapter.base.BaseQuickAdapter;
25 | import com.google.gson.Gson;
26 | import com.google.gson.reflect.TypeToken;
27 |
28 | import java.lang.reflect.Type;
29 | import java.util.Comparator;
30 | import java.util.HashMap;
31 | import java.util.List;
32 |
33 | import butterknife.BindView;
34 | import butterknife.ButterKnife;
35 | import io.reactivex.Observable;
36 | import io.reactivex.functions.Consumer;
37 | import io.reactivex.functions.Function;
38 | import io.reactivex.functions.Predicate;
39 |
40 | /**
41 | * xiaolei
42 | */
43 | public class MainActivity extends AppCompatActivity {
44 | DBManager dbManager;
45 | SQLiteDatabase sqLiteDatabase;
46 | @BindView(R.id.et_city_name)
47 | SearchView etCityName;
48 | @BindView(R.id.ll_search)
49 | RelativeLayout llSearch;
50 | @BindView(R.id.rv_city)
51 | RecyclerView rvCity;
52 | @BindView(R.id.slideBar)
53 | SlideBar slideBar;
54 |
55 | private List cityVoList;
56 | private View headerView;
57 | private PickCityAdapter pickCityAdapter;
58 | //悬浮itemDecoration
59 | private FloatingItemDecoration floatingItemDecoration;
60 | private HashMap keys;
61 | private HashMap letterIndexes = new HashMap<>();
62 | private LinearLayoutManager llm;
63 |
64 | @Override
65 | protected void onCreate(Bundle savedInstanceState) {
66 | super.onCreate(savedInstanceState);
67 | setContentView(R.layout.activity_main);
68 | ButterKnife.bind(this);
69 | initView();
70 | initSearch();
71 | initDb();
72 | }
73 |
74 |
75 | /**
76 | * 初始化视图
77 | */
78 | private void initView() {
79 | pickCityAdapter = new PickCityAdapter();
80 | rvCity.setLayoutManager(new LinearLayoutManager(this));
81 | rvCity.setAdapter(pickCityAdapter);
82 | //头部视图
83 | headerView = getLayoutInflater().inflate(R.layout.layout_city_header, (ViewGroup) rvCity.getParent(),
84 | false);
85 | RecyclerView rvHotCity = (RecyclerView) headerView.findViewById(R.id.rv_hot_city);
86 | rvHotCity.setLayoutManager(new GridLayoutManager(this, 3));
87 | PickCityAdapter hotCityAdapter = new PickCityAdapter();
88 | hotCityAdapter.setNewData(generateHotCity());
89 | rvHotCity.setAdapter(hotCityAdapter);
90 | //分割线
91 | floatingItemDecoration = new FloatingItemDecoration(this,
92 | this.getResources().getColor(R.color.divider_normal), 100, 1);
93 | floatingItemDecoration.setmTitleHeight(UiUtils.dp2px(this, 27));
94 | floatingItemDecoration.setShowFloatingHeaderOnScrolling(true);//悬浮
95 | rvCity.addItemDecoration(floatingItemDecoration);
96 | llm = new LinearLayoutManager(this);
97 | rvCity.setLayoutManager(llm);
98 |
99 | //右侧滑动选择
100 | slideBar.setOnTouchingLetterChangedListener(new SlideBar.OnTouchingLetterChangedListener() {
101 | @Override
102 | public void onTouchingLetterChanged(String s, int offset) {
103 | int position = letterIndexes.get(s) == null ? -1 : letterIndexes.get(s);
104 | llm.scrollToPositionWithOffset(position, offset);
105 | }
106 | });
107 | //列点击事件
108 | pickCityAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
109 | @Override
110 | public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
111 | Toast.makeText(MainActivity.this,pickCityAdapter.getItem(position).getCityName(),
112 | Toast.LENGTH_LONG).show();
113 | }
114 | });
115 | }
116 |
117 |
118 | /**
119 | * 初始化搜索
120 | */
121 |
122 | private void initSearch(){
123 | etCityName.setIconified(false);//设置searchView处于展开状态
124 | etCityName.onActionViewExpanded();// 当展开无输入内容的时候,没有关闭的图标
125 | etCityName.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
126 | @Override
127 | public boolean onQueryTextSubmit(String s) {
128 | searchData(s);
129 | return false;
130 | }
131 |
132 | @Override
133 | public boolean onQueryTextChange(String s) {
134 | slideBar.setVisibility(s.length() > 0 ? View.GONE : View.VISIBLE);
135 | if (s.length() > 0) {
136 | searchData(s);
137 | } else {
138 | doData(cityVoList);
139 | }
140 | return true;
141 | }
142 | });
143 |
144 | }
145 |
146 |
147 |
148 | /**
149 | * 初始化数据库
150 | */
151 | private void initDb() {
152 | dbManager = new DBManager(MainActivity.this);
153 | Observable.just(dbManager).map(new Function() {
154 | @Override
155 | public Object apply(DBManager dbManager) throws Exception {
156 | sqLiteDatabase = dbManager.initDataBase(getPackageName());
157 | String[] columns = new String[]//列属性
158 | {"cityType", "cityID", "cityName", "parentId"};
159 | String selection = "cityType=?";
160 | String[] selectionArgs = new String[]{"3"};//type为3时查询的是市
161 | cityVoList = dbManager.query(sqLiteDatabase, columns, selection, selectionArgs);
162 | sqLiteDatabase.close();
163 | return cityVoList;
164 | }
165 | }).compose(RxUtils.schedulersTransformer()).subscribe(new Consumer>() {
166 | @Override
167 | public void accept(List cityVoList) throws Exception {
168 | doData(cityVoList);
169 | }
170 | });
171 | }
172 |
173 |
174 | /**
175 | *数据排序
176 | */
177 | private void doData(ListcityVoList){
178 | Observable.just(cityVoList).doOnNext(new Consumer>() {
179 | @Override
180 | public void accept(List cityVoList) throws Exception {
181 | setPingyin(cityVoList);
182 | }
183 | }).doOnNext(new Consumer>() {
184 | @Override
185 | public void accept(List cityVoList) throws Exception {
186 | sortData(cityVoList);
187 | }
188 | }).subscribe(new Consumer>() {
189 | @Override
190 | public void accept(List cityVoList) throws Exception {
191 | Log.d("aaaaa","aaaa");
192 | }
193 | });
194 |
195 | }
196 |
197 |
198 | /**
199 | * 处理拼音
200 | */
201 | private List setPingyin(final ListcityVoList){
202 | for (CityVo cityVo :cityVoList){
203 | cityVo.setPinYin(PinyinUtil.getPingYin(cityVo.getCityName()));
204 | }
205 | return cityVoList;
206 | }
207 |
208 | /**
209 | * 排序
210 | */
211 | private void sortData(final ListcityVoList){
212 | keys = new HashMap<>();
213 | Observable.fromIterable(cityVoList).
214 | toSortedList(new Comparator() {
215 | @Override
216 | public int compare(CityVo o1, CityVo o2) {
217 | //a-z排序
218 | String a = o1.getPinYin();
219 | String b = o2.getPinYin();
220 | return a.compareTo(b);
221 | }
222 | }).subscribe(new Consumer>() {
223 | @Override
224 | public void accept(List cityVoList) throws Exception {
225 | pickCityAdapter.addHeaderView(headerView);
226 | pickCityAdapter.setNewData(cityVoList);
227 | //添加了头部,所以keys要从1开始
228 | keys.put(1, "A");
229 | letterIndexes.put("#", 0);
230 | letterIndexes.put("A", 1);
231 | for (int i = 0; i < cityVoList.size(); i++) {
232 | if (i < cityVoList.size() - 1) {
233 | //首字母不同,设为ky
234 | String pre = cityVoList.get(i).getPinYin().substring(0, 1).toUpperCase();
235 | String next = cityVoList.get(i + 1).getPinYin().substring(0, 1).toUpperCase();
236 | if (!pre.equals(next)) {
237 | keys.put(i + 2, next);
238 | letterIndexes.put(next, i + 2);
239 | }
240 | }
241 | }
242 | floatingItemDecoration.setKeys(keys);
243 | }
244 | });
245 | }
246 |
247 | /**
248 | * 搜索数据
249 | */
250 | private void searchData(final String searchKey){
251 | Observable.fromIterable(cityVoList).filter(new Predicate() {
252 | @Override
253 | public boolean test(CityVo cityVo) throws Exception {
254 | if (cityVo.getPinYin().contains(searchKey.trim())||
255 | cityVo.getCityName().contains(searchKey.trim())){
256 | return true;
257 | }
258 | return false;
259 | }
260 | }).compose(RxUtils.schedulersTransformer()).
261 | toList().
262 | subscribe(new Consumer>() {
263 | @Override
264 | public void accept(List cityVoList) throws Exception {
265 | keys = new HashMap();
266 | keys.put(0, searchKey.trim().toUpperCase());
267 | pickCityAdapter.removeAllHeaderView();
268 | pickCityAdapter.setNewData(cityVoList);
269 | floatingItemDecoration.setKeys(keys);
270 |
271 | }
272 | });
273 | }
274 |
275 |
276 |
277 | /**
278 | * 热门城市
279 | *
280 | * @return
281 | */
282 | private List generateHotCity() {
283 | Gson gson = new Gson();
284 | Type type = new TypeToken>(){}.getType();
285 | String jsonString=this.getResources().getString(R.string.hot_city_json);
286 | ListcityVoList = gson.fromJson(jsonString,type);
287 | return cityVoList;
288 | }
289 |
290 |
291 | }
292 |
--------------------------------------------------------------------------------
/app/src/main/java/com/address/xiaolei/addressselect/adapter/PickCityAdapter.java:
--------------------------------------------------------------------------------
1 | package com.address.xiaolei.addressselect.adapter;
2 |
3 | import android.view.View;
4 |
5 | import com.address.xiaolei.addressselect.R;
6 | import com.address.xiaolei.addressselect.vo.CityVo;
7 | import com.chad.library.adapter.base.BaseQuickAdapter;
8 | import com.chad.library.adapter.base.BaseViewHolder;
9 |
10 |
11 | /**
12 | * Created by Cicinnus on 2017/6/8.
13 | */
14 |
15 | public class PickCityAdapter extends BaseQuickAdapter {
16 |
17 |
18 | private OnCityClickListener onCityClickListener;
19 |
20 | public PickCityAdapter() {
21 | super(R.layout.item_city);
22 | }
23 | @Override
24 | protected void convert(BaseViewHolder helper, final CityVo item) {
25 | helper.setText(R.id.tv_city_name, item.getCityName());
26 | }
27 |
28 |
29 | public interface OnCityClickListener{
30 | void onClick(CityVo item);
31 | }
32 |
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/address/xiaolei/addressselect/sqlutil/DBManager.java:
--------------------------------------------------------------------------------
1 | package com.address.xiaolei.addressselect.sqlutil;
2 |
3 | import android.content.Context;
4 | import android.database.Cursor;
5 | import android.database.sqlite.SQLiteDatabase;
6 | import android.util.Log;
7 |
8 | import com.address.xiaolei.addressselect.utils.FileUtil;
9 | import com.address.xiaolei.addressselect.vo.CityVo;
10 |
11 | import java.io.File;
12 | import java.io.FileOutputStream;
13 | import java.io.IOException;
14 | import java.io.InputStream;
15 | import java.util.ArrayList;
16 | import java.util.List;
17 |
18 | /**
19 | * xiaolei
20 | */
21 | public class DBManager {
22 | private String DB_NAME = "city_db_53.db";
23 | private Context mContext;
24 |
25 | public DBManager(Context mContext) {
26 | this.mContext = mContext;
27 | }
28 | //把assets目录下的db文件复制到dbpath下
29 | public SQLiteDatabase initDataBase(String packName) {
30 | String dbPath = FileUtil.getCachePath(mContext)+ "/"+packName
31 | + "/databases/" + DB_NAME;
32 | File file=new File(dbPath);
33 | if (!file.exists()) {
34 | try {
35 | // 先得到文件的上级目录,并创建上级目录,在创建文件
36 | boolean falg1= file.getParentFile().mkdirs();
37 | boolean falg2= file.createNewFile();
38 | Log.d("*************",falg1+"&&&"+falg2);
39 | FileOutputStream out = new FileOutputStream(file);
40 | InputStream in = mContext.getAssets().open(DB_NAME);
41 | byte[] buffer = new byte[1024];
42 | int readBytes = 0;
43 | while ((readBytes = in.read(buffer)) != -1)
44 | out.write(buffer, 0, readBytes);
45 | in.close();
46 | out.close();
47 | } catch (IOException e) {
48 | e.printStackTrace();
49 | }
50 | }
51 | return SQLiteDatabase.openOrCreateDatabase(dbPath, null);
52 | }
53 | //查询
54 | public List query(SQLiteDatabase sqliteDB, String[] columns, String selection, String[] selectionArgs) {
55 | CityVo city = null;
56 | ListcityVoList=new ArrayList<>();
57 | try {
58 | String table = "cityTable";//数据库表名
59 | Cursor cursor = sqliteDB.query(table, columns, selection, selectionArgs,
60 | null, null, null);
61 | while (cursor.moveToNext()) {
62 | String cityType = cursor.getString(cursor.getColumnIndex("cityType"));
63 | String cityId = cursor.getString(cursor.getColumnIndex("cityID"));
64 | String cityName = cursor.getString(cursor.getColumnIndex("cityName"));
65 | String parentId = cursor.getString(cursor.getColumnIndex("parentId"));
66 | city = new CityVo(cityId,cityName, parentId,cityType);
67 | cityVoList.add(city);
68 | }
69 | cursor.close();
70 | } catch (Exception e) {
71 | e.printStackTrace();
72 | }
73 | return cityVoList;
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/app/src/main/java/com/address/xiaolei/addressselect/utils/FileUtil.java:
--------------------------------------------------------------------------------
1 | package com.address.xiaolei.addressselect.utils;
2 |
3 | import android.content.Context;
4 | import android.os.Environment;
5 | import android.util.Log;
6 |
7 | import java.io.File;
8 | import java.io.FileInputStream;
9 | import java.text.DecimalFormat;
10 |
11 |
12 | public class FileUtil {
13 | /**
14 | * 获取缓存目录
15 | * @param context
16 | * @return
17 | */
18 | public static String getCachePath(Context context ){
19 | String cachePath ;
20 | if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
21 | || !Environment.isExternalStorageRemovable()) {
22 | //外部存储可用
23 | cachePath = context.getExternalCacheDir().getPath() ;
24 |
25 | }else {
26 | //外部存储不可用
27 | cachePath = context.getCacheDir().getPath() ;
28 | }
29 | return cachePath ;
30 | }
31 |
32 | /**
33 | * 根据文件路径获取文件
34 | *
35 | * @param filePath 文件路径
36 | * @return 文件
37 | */
38 | public static File getFileByPath(String filePath) {
39 | return isSpace(filePath) ? null : new File(filePath);
40 | }
41 |
42 |
43 |
44 | /**
45 | * 删除目录
46 | *
47 | * @param dir 目录
48 | * @return {@code true}: 删除成功
{@code false}: 删除失败
49 | */
50 | public static boolean deleteDir(File dir) {
51 | if (dir == null) return false;
52 | // 目录不存在返回true
53 | if (!dir.exists()) return true;
54 | // 不是目录返回false
55 | if (!dir.isDirectory()) return false;
56 | // 现在文件存在且是文件夹
57 | File[] files = dir.listFiles();
58 | if (files != null && files.length != 0) {
59 | for (File file : files) {
60 | if (file.isFile()) {
61 | if (!deleteFile(file)) return false;
62 | } else if (file.isDirectory()) {
63 | if (!deleteDir(file)) return false;
64 | }
65 | }
66 | }
67 | return dir.delete();
68 | }
69 |
70 | /**
71 | * 删除文件
72 | *
73 | * @param srcFilePath 文件路径
74 | * @return {@code true}: 删除成功
{@code false}: 删除失败
75 | */
76 | public static boolean deleteFile(String srcFilePath) {
77 | return deleteFile(getFileByPath(srcFilePath));
78 | }
79 |
80 |
81 |
82 | /**
83 | * 删除文件
84 | *
85 | * @param file 文件
86 | * @return {@code true}: 删除成功
{@code false}: 删除失败
87 | */
88 | public static boolean deleteFile(File file) {
89 | return file != null && (!file.exists() || file.isFile() && file.delete());
90 | }
91 |
92 |
93 | /**
94 | * 获取指定文件大小
95 | * @param
96 | * @return
97 | * @throws Exception
98 | */
99 | public static long getFileSize(File file) throws Exception {
100 | long size = 0;
101 | if (file.exists()) {
102 | FileInputStream fis = null;
103 | fis = new FileInputStream(file);
104 | size = fis.available();
105 | } else {
106 | file.createNewFile();
107 | Log.e("获取文件大小", "文件不存在!");
108 | }
109 | return size;
110 | }
111 |
112 | /**
113 | * 获取指定文件夹
114 | * @param f
115 | * @return
116 | * @throws Exception
117 | *
118 | */
119 | public static long getFileSizes(File f) throws Exception {
120 | long size = 0;
121 | File flist[] = f.listFiles();
122 | for (int i = 0; i < flist.length; i++) {
123 | if (flist[i].isDirectory()) {
124 | size = size + getFileSizes(flist[i]);
125 | } else {
126 | size = size + getFileSize(flist[i]);
127 | }
128 | }
129 | return size;
130 | }
131 |
132 | public static String FormatFileSize(long fileS) {
133 | DecimalFormat df = new DecimalFormat("#.00");
134 | String fileSizeString = "";
135 | String wrongSize = "0B";
136 | if (fileS == 0) {
137 | return wrongSize;
138 | }
139 | if (fileS < 1024) {
140 | fileSizeString = df.format((double) fileS) + "B";
141 | } else if (fileS < 1048576) {
142 | fileSizeString = df.format((double) fileS / 1024) + "KB";
143 | } else if (fileS < 1073741824) {
144 | fileSizeString = df.format((double) fileS / 1048576) + "MB";
145 | } else {
146 | fileSizeString = df.format((double) fileS / 1073741824) + "GB";
147 | }
148 | return fileSizeString;
149 | }
150 |
151 | private static boolean isSpace(String s) {
152 | if (s == null) return true;
153 | for (int i = 0, len = s.length(); i < len; ++i) {
154 | if (!Character.isWhitespace(s.charAt(i))) {
155 | return false;
156 | }
157 | }
158 | return true;
159 | }
160 |
161 | }
162 |
--------------------------------------------------------------------------------
/app/src/main/java/com/address/xiaolei/addressselect/utils/PinyinUtil.java:
--------------------------------------------------------------------------------
1 | package com.address.xiaolei.addressselect.utils;
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 : XiaoLei
12 | * date : 2019/1/161337
13 | * desc :
14 | */
15 | public class PinyinUtil {
16 | /**
17 | * 将字符串中的中文转化为拼音,其他字符不变
18 | *
19 | * @param inputString
20 | * @return
21 | */
22 | public static String getPingYin(String inputString) {
23 | HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
24 | format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
25 | format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
26 | format.setVCharType(HanyuPinyinVCharType.WITH_V);
27 |
28 | char[] input = inputString.trim().toCharArray();
29 | String output = "";
30 |
31 | try {
32 | for (int i = 0; i < input.length; i++) {
33 | if (java.lang.Character.toString(input[i]).matches("[\\u4E00-\\u9FA5]+")) {
34 | String[] temp = PinyinHelper.toHanyuPinyinStringArray(input[i], format);
35 | output += temp[0];
36 | } else
37 | output += java.lang.Character.toString(input[i]);
38 | }
39 | } catch (BadHanyuPinyinOutputFormatCombination e) {
40 | e.printStackTrace();
41 | }
42 | return output;
43 | }
44 | /**
45 | * 获取汉字串拼音首字母,英文字符不变
46 | * @param chinese 汉字串
47 | * @return 汉语拼音首字母
48 | */
49 | public static String getFirstSpell(String chinese) {
50 | StringBuffer pybf = new StringBuffer();
51 | char[] arr = chinese.toCharArray();
52 | HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
53 | defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
54 | defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
55 | for (int i = 0; i < arr.length; i++) {
56 | if (arr[i] > 128) {
57 | try {
58 | String[] temp = PinyinHelper.toHanyuPinyinStringArray(arr[i], defaultFormat);
59 | if (temp != null) {
60 | pybf.append(temp[0].charAt(0));
61 | }
62 | } catch (BadHanyuPinyinOutputFormatCombination e) {
63 | e.printStackTrace();
64 | }
65 | } else {
66 | pybf.append(arr[i]);
67 | }
68 | }
69 | return pybf.toString().replaceAll("\\W", "").trim();
70 | }
71 | /**
72 | * 获取汉字串拼音,英文字符不变
73 | * @param chinese 汉字串
74 | * @return 汉语拼音
75 | */
76 | public static String getFullSpell(String chinese) {
77 | StringBuffer pybf = new StringBuffer();
78 | char[] arr = chinese.toCharArray();
79 | HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
80 | defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
81 | defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
82 | for (int i = 0; i < arr.length; i++) {
83 | if (arr[i] > 128) {
84 | try {
85 | pybf.append(PinyinHelper.toHanyuPinyinStringArray(arr[i], defaultFormat)[0]);
86 | } catch (BadHanyuPinyinOutputFormatCombination e) {
87 | e.printStackTrace();
88 | }
89 | } else {
90 | pybf.append(arr[i]);
91 | }
92 | }
93 | return pybf.toString();
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/app/src/main/java/com/address/xiaolei/addressselect/utils/RxUtils.java:
--------------------------------------------------------------------------------
1 | package com.address.xiaolei.addressselect.utils;
2 |
3 | import android.content.Context;
4 | import android.support.v4.app.Fragment;
5 |
6 | import com.trello.rxlifecycle2.LifecycleProvider;
7 | import com.trello.rxlifecycle2.LifecycleTransformer;
8 |
9 | import io.reactivex.Observable;
10 | import io.reactivex.ObservableSource;
11 | import io.reactivex.ObservableTransformer;
12 | import io.reactivex.android.schedulers.AndroidSchedulers;
13 | import io.reactivex.annotations.NonNull;
14 | import io.reactivex.functions.Function;
15 | import io.reactivex.schedulers.Schedulers;
16 |
17 | /**
18 | * author : XiaoLei
19 | * date : 2019/1/1113:33
20 | * desc :有关Rx的工具类
21 | */
22 | public class RxUtils {
23 | /**
24 | * 生命周期绑定
25 | *
26 | * @param lifecycle Activity
27 | */
28 | public static LifecycleTransformer bindToLifecycle(@NonNull Context lifecycle) {
29 | if (lifecycle instanceof LifecycleProvider) {
30 | return ((LifecycleProvider) lifecycle).bindToLifecycle();
31 | } else {
32 | throw new IllegalArgumentException("context not the LifecycleProvider type");
33 | }
34 | }
35 |
36 | /**
37 | * 生命周期绑定
38 | *
39 | * @param lifecycle Fragment
40 | */
41 | public static LifecycleTransformer bindToLifecycle(@NonNull Fragment lifecycle) {
42 | if (lifecycle instanceof LifecycleProvider) {
43 | return ((LifecycleProvider) lifecycle).bindToLifecycle();
44 | } else {
45 | throw new IllegalArgumentException("fragment not the LifecycleProvider type");
46 | }
47 | }
48 |
49 | /**
50 | * 生命周期绑定
51 | *
52 | * @param lifecycle Fragment
53 | */
54 | public static LifecycleTransformer bindToLifecycle(@NonNull LifecycleProvider lifecycle) {
55 | return lifecycle.bindToLifecycle();
56 | }
57 |
58 | /**
59 | * 线程调度器
60 | */
61 | public static ObservableTransformer schedulersTransformer() {
62 | return new ObservableTransformer() {
63 | @Override
64 | public ObservableSource apply(Observable upstream) {
65 | return upstream.subscribeOn(Schedulers.io())
66 | .observeOn(AndroidSchedulers.mainThread());
67 | }
68 | };
69 | }
70 |
71 |
72 |
73 |
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/app/src/main/java/com/address/xiaolei/addressselect/utils/UiUtils.java:
--------------------------------------------------------------------------------
1 | package com.address.xiaolei.addressselect.utils;
2 |
3 | import android.content.Context;
4 | import android.util.DisplayMetrics;
5 |
6 | /**
7 | * Created by Administrator on 2017/1/19.
8 | */
9 |
10 | public class UiUtils {
11 |
12 |
13 | /**
14 | * 动态获取屏幕的宽度
15 | * @param context context
16 | * @return
17 | */
18 | public static int getDeviceWidth(Context context){
19 | DisplayMetrics metrics = context.getResources().getDisplayMetrics();
20 | return metrics.widthPixels;
21 | }
22 |
23 | /**
24 | * 动态获取屏幕的高度
25 | * @param context context
26 | * @return
27 | */
28 | public static int getDeviceHeight(Context context){
29 | DisplayMetrics metrics = context.getResources().getDisplayMetrics();
30 | return metrics.heightPixels;
31 | }
32 |
33 | /**
34 | * 将dp转为px
35 | * @param context context
36 | * @param dpValue dp值
37 | * @return
38 | */
39 | public static int dp2px(Context context, float dpValue){
40 | float scale = context.getResources().getDisplayMetrics().density;
41 | return (int)(dpValue * scale +0.5f);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/java/com/address/xiaolei/addressselect/view/FloatingItemDecoration.java:
--------------------------------------------------------------------------------
1 | package com.address.xiaolei.addressselect.view;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.Paint;
8 | import android.graphics.Rect;
9 | import android.graphics.drawable.ColorDrawable;
10 | import android.graphics.drawable.Drawable;
11 | import android.support.annotation.ColorInt;
12 | import android.support.annotation.Dimension;
13 | import android.support.annotation.DrawableRes;
14 | import android.support.v4.content.ContextCompat;
15 | import android.support.v7.widget.LinearLayoutManager;
16 | import android.support.v7.widget.RecyclerView;
17 | import android.text.TextUtils;
18 | import android.util.TypedValue;
19 | import android.view.View;
20 |
21 | import com.address.xiaolei.addressselect.R;
22 |
23 | import java.util.HashMap;
24 | import java.util.Map;
25 |
26 | /**
27 | * 自定义分割线
28 | */
29 |
30 | public class FloatingItemDecoration extends RecyclerView.ItemDecoration {
31 | private static final String TAG = "FloatingItemDecoration";
32 | private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
33 | private Drawable mDivider;
34 | private int dividerHeight;
35 | private int dividerWidth;
36 | private Map keys=new HashMap<>();
37 | private int mTitleHeight;
38 | private Paint mTextPaint;
39 | private Paint mBackgroundPaint;
40 | private float mTextHeight;
41 | private float mTextBaselineOffset;
42 | private Context mContext;
43 | /**
44 | * 滚动列表的时候是否一直显示悬浮头部
45 | */
46 | private boolean showFloatingHeaderOnScrolling=true;
47 |
48 | public FloatingItemDecoration(Context context) {
49 | final TypedArray a = context.obtainStyledAttributes(ATTRS);
50 | mDivider = a.getDrawable(0);
51 | a.recycle();
52 | this.dividerHeight=mDivider.getIntrinsicHeight();
53 | this.dividerWidth=mDivider.getIntrinsicWidth();
54 | init(context);
55 | }
56 |
57 | /**
58 | * 自定义分割线
59 | *
60 | * @param context
61 | * @param drawableId 分割线图片
62 | */
63 | public FloatingItemDecoration(Context context, @DrawableRes int drawableId) {
64 | mDivider = ContextCompat.getDrawable(context, drawableId);
65 | this.dividerHeight=mDivider.getIntrinsicHeight();
66 | this.dividerWidth=mDivider.getIntrinsicWidth();
67 | init(context);
68 | }
69 |
70 | /**
71 | * 自定义分割线
72 | * 也可以使用{@link Canvas#drawRect(float, float, float, float, Paint)}或者{@link Canvas#drawText(String, float, float, Paint)}等等
73 | * 结合{@link Paint}去绘制各式各样的分割线
74 | * @param context
75 | * @param color 整型颜色值,非资源id
76 | * @param dividerWidth 单位为dp
77 | * @param dividerHeight 单位为dp
78 | */
79 | public FloatingItemDecoration(Context context, @ColorInt int color, @Dimension float dividerWidth, @Dimension float dividerHeight) {
80 | mDivider = new ColorDrawable(color);
81 | this.dividerWidth= (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dividerWidth,context.getResources().getDisplayMetrics());
82 | this.dividerHeight= (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dividerHeight,context.getResources().getDisplayMetrics());
83 | init(context);
84 | }
85 |
86 | private void init(Context mContext){
87 | this.mContext=mContext;
88 | mTextPaint=new Paint();
89 | mTextPaint.setAntiAlias(true);
90 | mTextPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,12,mContext.getResources().getDisplayMetrics()));
91 | mTextPaint.setColor(Color.BLACK);
92 | Paint.FontMetrics fm=mTextPaint.getFontMetrics();
93 | mTextHeight=fm.bottom-fm.top;//计算文字高度
94 | mTextBaselineOffset=fm.bottom;
95 |
96 | mBackgroundPaint=new Paint();
97 | mBackgroundPaint.setAntiAlias(true);
98 | mBackgroundPaint.setColor(mContext.getResources().getColor(R.color.divider_normal));
99 | }
100 |
101 | @Override
102 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
103 | super.onDraw(c, parent, state);
104 | drawVertical(c,parent);
105 | }
106 |
107 | @Override
108 | public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
109 | super.onDrawOver(c, parent, state);
110 | if(!showFloatingHeaderOnScrolling){
111 | return;
112 | }
113 | int firstVisiblePos=((LinearLayoutManager)parent.getLayoutManager()).findFirstVisibleItemPosition();
114 | if(firstVisiblePos== RecyclerView.NO_POSITION){
115 | return;
116 | }
117 | String title=getTitle(firstVisiblePos);
118 | if(TextUtils.isEmpty(title)){
119 | return;
120 | }
121 | boolean flag=false;
122 | if(getTitle(firstVisiblePos+1)!=null&&!title.equals(getTitle(firstVisiblePos+1))){
123 | //说明是当前组最后一个元素,但不一定碰撞了
124 | // Log.e(TAG, "onDrawOver: "+"==============" +firstVisiblePos);
125 | View child=parent.findViewHolderForAdapterPosition(firstVisiblePos).itemView;
126 | if(child.getTop()+child.getMeasuredHeight()= 0) {
166 | if (keys.containsKey(position)) {
167 | return keys.get(position);
168 | }
169 | position--;
170 | }
171 | return null;
172 | }
173 |
174 | private void drawVertical(Canvas c, RecyclerView parent){
175 | int left = parent.getPaddingLeft();
176 | int right = parent.getWidth() - parent.getPaddingRight();
177 | int top=0;
178 | int bottom=0;
179 | for (int i = 0; i < parent.getChildCount(); i++) {
180 | View child=parent.getChildAt(i);
181 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
182 | if(!keys.containsKey(params.getViewAdapterPosition())){
183 | //画普通分割线
184 | top=child.getTop()-params.topMargin-dividerHeight;
185 | bottom=top+dividerHeight;
186 | mDivider.setBounds(left, top, right, bottom);
187 | mDivider.draw(c);
188 | }else{
189 | //画分组
190 | top=child.getTop()-params.topMargin-mTitleHeight;
191 | bottom=top+mTitleHeight;
192 | c.drawRect(left,top,right,bottom,mBackgroundPaint);
193 | // float x=child.getPaddingLeft()+params.leftMargin;
194 | float x= TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,10,mContext.getResources().getDisplayMetrics());
195 | float y=bottom - (mTitleHeight - mTextHeight) / 2 - mTextBaselineOffset;//计算文字baseLine
196 | // Log.e(TAG, "drawVertical: "+bottom );
197 | c.drawText(keys.get(params.getViewLayoutPosition()),x,y,mTextPaint);
198 | }
199 | }
200 | }
201 |
202 | public void setShowFloatingHeaderOnScrolling(boolean showFloatingHeaderOnScrolling) {
203 | this.showFloatingHeaderOnScrolling = showFloatingHeaderOnScrolling;
204 | }
205 |
206 | public void setKeys(Map keys){
207 | this.keys.clear();
208 | this.keys.putAll(keys);
209 | }
210 |
211 | public void setmTitleHeight(int titleHeight){
212 | this.mTitleHeight=titleHeight;
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/app/src/main/java/com/address/xiaolei/addressselect/view/SlideBar.java:
--------------------------------------------------------------------------------
1 | package com.address.xiaolei.addressselect.view;
2 |
3 | /**
4 | * Created by xiaolei on 2017/6/8.
5 | */
6 |
7 | import android.content.Context;
8 | import android.graphics.Canvas;
9 | import android.graphics.Color;
10 | import android.graphics.Paint;
11 | import android.graphics.RectF;
12 | import android.graphics.Typeface;
13 | import android.support.v4.view.MotionEventCompat;
14 | import android.util.AttributeSet;
15 | import android.view.MotionEvent;
16 | import android.view.View;
17 | import android.view.ViewConfiguration;
18 |
19 |
20 | import com.address.xiaolei.addressselect.R;
21 |
22 | import static android.support.v4.widget.ViewDragHelper.INVALID_POINTER;
23 |
24 | /**
25 | * 根据该项目进行了小修改,可以在滑动的同时进行监听
26 | * https://github.com/kongnanlive/SideBar
27 | */
28 |
29 | public class SlideBar extends View {
30 | private static final String TAG = SlideBar.class.getSimpleName();
31 |
32 | public interface OnTouchingLetterChangedListener {
33 | void onTouchingLetterChanged(String s, int offset);
34 | }
35 |
36 | private OnTouchingLetterChangedListener mOnTouchingLetterChangedListener;
37 |
38 | private String[] mLetters = null;
39 | private Paint mPaint;
40 |
41 | private int mChoose = -1;
42 |
43 | private final float mDensity;
44 | private float mY;
45 | private float mHalfWidth, mHalfHeight;
46 | private float mLetterHeight;
47 | private float mAnimStep;
48 |
49 | private int mTouchSlop;
50 | private float mInitialDownY;
51 | private boolean mIsBeingDragged, mStartEndAnim;
52 | private int mActivePointerId = INVALID_POINTER;
53 |
54 | private RectF mIsDownRect = new RectF();
55 |
56 | public SlideBar(Context context) {
57 | this(context, null);
58 | }
59 |
60 | public SlideBar(Context context, AttributeSet attrs) {
61 | this(context, attrs, 0);
62 | }
63 |
64 | public SlideBar(Context context, AttributeSet attrs, int defStyleAttr) {
65 | super(context, attrs, defStyleAttr);
66 | this.mPaint = new Paint();
67 | int mTextColor = Color.GRAY;
68 | this.mPaint.setAntiAlias(true);
69 | this.mPaint.setTextAlign(Paint.Align.CENTER);
70 | this.mPaint.setColor(mTextColor);
71 |
72 | int mResArrayId = R.array.letter_list;
73 | this.mLetters = context.getResources().getStringArray(mResArrayId);
74 |
75 | mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
76 | mDensity = getContext().getResources().getDisplayMetrics().density;
77 |
78 | setPadding(0, 0, 0, dip2px(20));
79 | }
80 |
81 | public void setOnTouchingLetterChangedListener(OnTouchingLetterChangedListener listener) {
82 | this.mOnTouchingLetterChangedListener = listener;
83 | }
84 |
85 | private int getLettersSize() {
86 | return mLetters.length;
87 | }
88 |
89 | @Override
90 | public boolean onTouchEvent(MotionEvent ev) {
91 | final int action = MotionEventCompat.getActionMasked(ev);
92 | switch (action) {
93 | case MotionEvent.ACTION_DOWN:
94 | mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
95 | mIsBeingDragged = false;
96 | final float initialDownY = getMotionEventY(ev, mActivePointerId);
97 | if (initialDownY == -1) {
98 | return false;
99 | }
100 | if (!mIsDownRect.contains(ev.getX(), ev.getY())) {
101 | return false;
102 | }
103 | mInitialDownY = initialDownY;
104 | break;
105 | case MotionEvent.ACTION_MOVE:
106 | if (mActivePointerId == INVALID_POINTER) {
107 | return false;
108 | }
109 |
110 | final float y = getMotionEventY(ev, mActivePointerId);
111 | if (y == -1) {
112 | return false;
113 | }
114 | final float yDiff = Math.abs(y - mInitialDownY);
115 | if (yDiff > mTouchSlop && !mIsBeingDragged) {
116 | mIsBeingDragged = true;
117 | }
118 | if (mIsBeingDragged) {
119 | mY = y;
120 | final float moveY = y - getPaddingTop() - mLetterHeight / 1.64f;
121 | final int characterIndex = (int) (moveY / mHalfHeight * mLetters.length);
122 | if (mChoose != characterIndex) {
123 | if (characterIndex >= 0 && characterIndex < mLetters.length) {
124 | mChoose = characterIndex;
125 | }
126 | mOnTouchingLetterChangedListener.onTouchingLetterChanged(mLetters[mChoose],(int)moveY);
127 | }
128 |
129 | invalidate();
130 | }
131 | break;
132 | case MotionEventCompat.ACTION_POINTER_UP:
133 | onSecondaryPointerUp(ev);
134 | break;
135 | case MotionEvent.ACTION_UP:
136 | case MotionEvent.ACTION_CANCEL:
137 | if (mOnTouchingLetterChangedListener != null) {
138 | if (mIsBeingDragged) {
139 | mOnTouchingLetterChangedListener.onTouchingLetterChanged(mLetters[mChoose],0);
140 | } else {
141 | float downY = ev.getY() - getPaddingTop();
142 | final int characterIndex = (int) (downY / mHalfHeight * mLetters.length);
143 | if (characterIndex >= 0 && characterIndex < mLetters.length) {
144 | mOnTouchingLetterChangedListener.onTouchingLetterChanged(mLetters[characterIndex],0);
145 | }
146 | }
147 | }
148 | mStartEndAnim = mIsBeingDragged;
149 | mIsBeingDragged = false;
150 | mActivePointerId = INVALID_POINTER;
151 |
152 | mChoose = -1;
153 | mAnimStep = 0f;
154 | invalidate();
155 | return false;
156 | }
157 | return true;
158 | }
159 |
160 | @Override
161 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
162 | super.onSizeChanged(w, h, oldw, oldh);
163 | mHalfWidth = w - dip2px(16);
164 | mHalfHeight = h - getPaddingTop() - getPaddingBottom();
165 |
166 | float lettersLen = getLettersSize();
167 |
168 | mLetterHeight = mHalfHeight / lettersLen;
169 | int textSize = (int) (mHalfHeight * 0.7f / lettersLen);
170 | this.mPaint.setTextSize(textSize);
171 |
172 | mIsDownRect.set(w - dip2px(16 * 2), 0, w, h);
173 | }
174 |
175 | @Override
176 | protected void onDraw(Canvas canvas) {
177 | super.onDraw(canvas);
178 | for (int i = 0; i < getLettersSize(); i++) {
179 | float letterPosY = mLetterHeight * (i + 1) + getPaddingTop();
180 | float diff, diffY, diffX;
181 | if (mChoose == i && i != 0 && i != getLettersSize() - 1) {
182 | diffX = 0f;
183 | diffY = 0f;
184 | diff = 2.16f;
185 | } else {
186 | float maxPos = Math.abs((mY - letterPosY) / mHalfHeight * 7f);
187 | diff = Math.max(1f, 2.2f - maxPos);
188 | if (mStartEndAnim && diff != 1f) {
189 | diff -= mAnimStep;
190 | if (diff <= 1f) {
191 | diff = 1f;
192 | }
193 | } else if (!mIsBeingDragged) {
194 | diff = 1f;
195 | }
196 | diffY = maxPos * 50f * (letterPosY >= mY ? -1 : 1);
197 | diffX = maxPos * 100f;
198 | }
199 | canvas.save();
200 | canvas.scale(diff, diff, mHalfWidth * 1.20f + diffX, letterPosY + diffY);
201 | if (diff == 1f) {
202 | this.mPaint.setAlpha(255);
203 | this.mPaint.setTypeface(Typeface.DEFAULT);
204 | } else {
205 | int alpha = (int) (255 * (1 - Math.min(0.9, diff - 1)));
206 | if (mChoose == i)
207 | alpha = 255;
208 | this.mPaint.setAlpha(alpha);
209 | this.mPaint.setTypeface(Typeface.DEFAULT_BOLD);
210 | }
211 | canvas.drawText(mLetters[i], mHalfWidth, letterPosY, this.mPaint);
212 | canvas.restore();
213 | }
214 | if (mChoose == -1 && mStartEndAnim && mAnimStep <= 0.6f) {
215 | mAnimStep += 0.6f;
216 | postInvalidateDelayed(25);
217 | } else {
218 | mAnimStep = 0f;
219 | mStartEndAnim = false;
220 | }
221 | }
222 |
223 | private int dip2px(int dipValue) {
224 | return (int) (dipValue * mDensity + 0.5f);
225 | }
226 |
227 | private float getMotionEventY(MotionEvent ev, int activePointerId) {
228 | final int index = MotionEventCompat.findPointerIndex(ev, activePointerId);
229 | if (index < 0) {
230 | return -1;
231 | }
232 | return MotionEventCompat.getY(ev, index);
233 | }
234 |
235 | private void onSecondaryPointerUp(MotionEvent ev) {
236 | final int pointerIndex = MotionEventCompat.getActionIndex(ev);
237 | final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
238 | if (pointerId == mActivePointerId) {
239 | final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
240 | mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
241 | }
242 | }
243 | }
244 |
--------------------------------------------------------------------------------
/app/src/main/java/com/address/xiaolei/addressselect/vo/CityVo.java:
--------------------------------------------------------------------------------
1 | package com.address.xiaolei.addressselect.vo;
2 |
3 | public class CityVo {
4 | private String cityId;
5 | private String cityName;
6 | private String parentId;
7 | private String cityType;
8 | private String pinYin;
9 |
10 | public String getPinYin() {
11 | return pinYin;
12 | }
13 |
14 | public void setPinYin(String pinYin) {
15 | this.pinYin = pinYin;
16 | }
17 |
18 | public CityVo(){}
19 |
20 | public CityVo(String cityId, String cityName, String parentId, String cityType) {
21 | this.cityId = cityId;
22 | this.cityName = cityName;
23 | this.parentId = parentId;
24 | this.cityType = cityType;
25 | }
26 |
27 | public String getCityId() {
28 | return cityId;
29 | }
30 |
31 | public void setCityId(String cityId) {
32 | this.cityId = cityId;
33 | }
34 |
35 | public String getCityName() {
36 | return cityName;
37 | }
38 |
39 | public void setCityName(String cityName) {
40 | this.cityName = cityName;
41 | }
42 |
43 | public String getParentId() {
44 | return parentId;
45 | }
46 |
47 | public void setParentId(String parentId) {
48 | this.parentId = parentId;
49 | }
50 |
51 | public String getCityType() {
52 | return cityType;
53 | }
54 |
55 | public void setCityType(String cityType) {
56 | this.cityType = cityType;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_clear_gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sky8650/AddressSelect/8540208b47703b69f83d4893dcd837b715d5014a/app/src/main/res/drawable-xhdpi/ic_clear_gray.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_search_small_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sky8650/AddressSelect/8540208b47703b69f83d4893dcd837b715d5014a/app/src/main/res/drawable-xhdpi/ic_search_small_2.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
17 |
18 |
19 |
29 |
30 |
31 |
32 |
33 |
38 |
39 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_city.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_city_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
24 |
25 |
33 |
34 |
35 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sky8650/AddressSelect/8540208b47703b69f83d4893dcd837b715d5014a/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sky8650/AddressSelect/8540208b47703b69f83d4893dcd837b715d5014a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sky8650/AddressSelect/8540208b47703b69f83d4893dcd837b715d5014a/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sky8650/AddressSelect/8540208b47703b69f83d4893dcd837b715d5014a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sky8650/AddressSelect/8540208b47703b69f83d4893dcd837b715d5014a/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sky8650/AddressSelect/8540208b47703b69f83d4893dcd837b715d5014a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sky8650/AddressSelect/8540208b47703b69f83d4893dcd837b715d5014a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sky8650/AddressSelect/8540208b47703b69f83d4893dcd837b715d5014a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sky8650/AddressSelect/8540208b47703b69f83d4893dcd837b715d5014a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sky8650/AddressSelect/8540208b47703b69f83d4893dcd837b715d5014a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - #
5 | - A
6 | - B
7 | - C
8 | - D
9 | - E
10 | - F
11 | - G
12 | - H
13 | - I
14 | - J
15 | - K
16 | - L
17 | - M
18 | - N
19 | - O
20 | - P
21 | - Q
22 | - R
23 | - S
24 | - T
25 | - U
26 | - V
27 | - W
28 | - X
29 | - Y
30 | - Z
31 |
32 |
33 |
34 |
35 |
36 | [
37 | {
38 | "citycityId": 10,
39 | "cityName": "上海",
40 | "py": "shanghai"
41 | },
42 | {
43 | "cityId": 1,
44 | "cityName": "北京",
45 | "py": "beijing"
46 | },
47 | {
48 | "cityId": 20,
49 | "cityName": "广州",
50 | "py": "guangzhou"
51 | },
52 | {
53 | "cityId": 30,
54 | "cityName": "深圳",
55 | "py": "shenzhen"
56 | },
57 | {
58 | "cityId": 57,
59 | "cityName": "武汉",
60 | "py": "wuhan"
61 | },
62 | {
63 | "cityId": 40,
64 | "cityName": "天津",
65 | "py": "tianjin"
66 | },
67 | {
68 | "cityId": 42,
69 | "cityName": "西安",
70 | "py": "xian"
71 | },
72 | {
73 | "cityId": 55,
74 | "cityName": "南京",
75 | "py": "nanjing"
76 | },
77 | {
78 | "cityId": 50,
79 | "cityName": "杭州",
80 | "py": "hangzhou"
81 | },
82 | {
83 | "cityId": 59,
84 | "cityName": "成都",
85 | "py": "chengdu"
86 | },
87 | {
88 | "cityId": 45,
89 | "cityName": "重庆",
90 | "py": "chongqing"
91 | }
92 | ]
93 |
94 |
95 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
8 | #2c2c2c
9 |
10 |
11 | #333333
12 | #12a2f1
13 | #ffb400
14 | #999999
15 | #666666
16 | #c8c8c8
17 |
18 | #f0f0f0
19 | #f5f5f5
20 |
21 | #ffffff
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AddressSelect
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/values.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 50dp
4 | 10dp
5 | 4dp
6 | 40dp
7 | 72dp
8 | 12dp
9 | 12sp
10 | 14sp
11 | 16sp
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/test/java/com/address/xiaolei/addressselect/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.address.xiaolei.addressselect;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.1.2'
11 | //jCenter
12 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
13 | //Maven
14 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
15 |
16 | // NOTE: Do not place your application dependencies here; they belong
17 | // in the individual module build.gradle files
18 | }
19 | }
20 |
21 | allprojects {
22 | repositories {
23 | google()
24 | jcenter()
25 | maven { url "https://jitpack.io" }
26 | }
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1537m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sky8650/AddressSelect/8540208b47703b69f83d4893dcd837b715d5014a/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Jan 10 19:12:25 CST 2019
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-4.4-all.zip
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 |
113 |
114 | # For Cygwin, switch paths to Windows format before running java
115 | if $cygwin ; then
116 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
117 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
118 | JAVACMD=`cygpath --unix "$JAVACMD"`
119 |
120 | # We build the pattern for arguments to be converted via cygpath
121 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
122 | SEP=""
123 | for dir in $ROOTDIRSRAW ; do
124 | ROOTDIRS="$ROOTDIRS$SEP$dir"
125 | SEP="|"
126 | done
127 | OURCYGPATTERN="(^($ROOTDIRS))"
128 | # Add a user-defined pattern to the cygpath arguments
129 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
130 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
131 | fi
132 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
133 | i=0
134 | for arg in "$@" ; do
135 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
136 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
137 |
138 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
139 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
140 | else
141 | eval `echo args$i`="\"$arg\""
142 | fi
143 | i=$((i+1))
144 | done
145 | case $i in
146 | (0) set -- ;;
147 | (1) set -- "$args0" ;;
148 | (2) set -- "$args0" "$args1" ;;
149 | (3) set -- "$args0" "$args1" "$args2" ;;
150 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
151 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
152 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
153 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
154 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
155 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
156 | esac
157 | fi
158 |
159 | # Escape application args
160 | save () {
161 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
162 | echo " "
163 | }
164 | APP_ARGS=$(save "$@")
165 |
166 | # Collect all arguments for the java command, following the shell quoting and substitution rules
167 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
168 |
169 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
170 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
171 | cd "$(dirname "$0")"
172 | fi
173 |
174 | exec "$JAVACMD" "$@"
175 |
--------------------------------------------------------------------------------
/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 |
12 | set DIRNAME=%~dp0
13 | if "%DIRNAME%" == "" set DIRNAME=.
14 | set APP_BASE_NAME=%~n0
15 | set APP_HOME=%DIRNAME%
16 |
17 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
18 | set DEFAULT_JVM_OPTS=
19 |
20 | @rem Find java.exe
21 | if defined JAVA_HOME goto findJavaFromJavaHome
22 |
23 | set JAVA_EXE=java.exe
24 | %JAVA_EXE% -version >NUL 2>&1
25 | if "%ERRORLEVEL%" == "0" goto init
26 |
27 | echo.
28 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
29 | echo.
30 | echo Please set the JAVA_HOME variable in your environment to match the
31 | echo location of your Java installation.
32 |
33 | goto fail
34 |
35 | :findJavaFromJavaHome
36 | set JAVA_HOME=%JAVA_HOME:"=%
37 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
38 |
39 | if exist "%JAVA_EXE%" goto init
40 |
41 | echo.
42 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
43 | echo.
44 | echo Please set the JAVA_HOME variable in your environment to match the
45 | echo location of your Java installation.
46 |
47 | goto fail
48 |
49 | :init
50 | @rem Get command-line arguments, handling Windows variants
51 |
52 | if not "%OS%" == "Windows_NT" goto win9xME_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 |
64 | :execute
65 | @rem Setup the command line
66 |
67 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
68 |
69 | @rem Execute Gradle
70 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
71 |
72 | :end
73 | @rem End local scope for the variables with windows NT shell
74 | if "%ERRORLEVEL%"=="0" goto mainEnd
75 |
76 | :fail
77 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
78 | rem the _cmd.exe /c_ return code!
79 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
80 | exit /b 1
81 |
82 | :mainEnd
83 | if "%OS%"=="Windows_NT" endlocal
84 |
85 | :omega
86 |
--------------------------------------------------------------------------------
/img/GIF.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sky8650/AddressSelect/8540208b47703b69f83d4893dcd837b715d5014a/img/GIF.gif
--------------------------------------------------------------------------------
/img/device-2019-01-17-185749.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sky8650/AddressSelect/8540208b47703b69f83d4893dcd837b715d5014a/img/device-2019-01-17-185749.png
--------------------------------------------------------------------------------
/img/device-2019-01-17-185822.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sky8650/AddressSelect/8540208b47703b69f83d4893dcd837b715d5014a/img/device-2019-01-17-185822.png
--------------------------------------------------------------------------------
/img/sql.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sky8650/AddressSelect/8540208b47703b69f83d4893dcd837b715d5014a/img/sql.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------