7278b39f1546000d1a6d2b33359bebcd4c9ad085.svn-base 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. package com.hjq.dialog;
  2. import android.app.Dialog;
  3. import android.content.Context;
  4. import android.os.Build;
  5. import android.support.annotation.NonNull;
  6. import android.support.design.widget.TabLayout;
  7. import android.support.v4.app.FragmentActivity;
  8. import android.support.v7.widget.RecyclerView;
  9. import android.util.DisplayMetrics;
  10. import android.util.TypedValue;
  11. import android.view.Gravity;
  12. import android.view.View;
  13. import android.view.ViewGroup;
  14. import android.view.WindowManager;
  15. import android.widget.ImageView;
  16. import android.widget.TextView;
  17. import com.hjq.base.BaseDialog;
  18. import com.hjq.base.BaseDialogFragment;
  19. import com.hjq.base.BaseRecyclerViewAdapter;
  20. import org.json.JSONArray;
  21. import org.json.JSONException;
  22. import org.json.JSONObject;
  23. import java.io.ByteArrayOutputStream;
  24. import java.io.IOException;
  25. import java.io.InputStream;
  26. import java.util.ArrayList;
  27. import java.util.List;
  28. /**
  29. * desc : 省市区选择对话框
  30. */
  31. public final class AddressDialog {
  32. public static final class Builder
  33. extends BaseDialogFragment.Builder<WaitDialog.Builder>
  34. implements BaseRecyclerViewAdapter.OnItemClickListener,
  35. View.OnClickListener, TabLayout.BaseOnTabSelectedListener, Runnable {
  36. private TextView mTitleView;
  37. private ImageView mCloseView;
  38. private TabLayout mTabLayout;
  39. private RecyclerView mRecyclerView1;
  40. private RecyclerView mRecyclerView2;
  41. private RecyclerView mRecyclerView3;
  42. private ImageView mHintView;
  43. private AddressDialogAdapter mAdapter1;
  44. private AddressDialogAdapter mAdapter2;
  45. private AddressDialogAdapter mAdapter3;
  46. private OnListener mListener;
  47. private String mProvince = null;
  48. private String mCity = null;
  49. private String mArea = null;
  50. private boolean mIgnoreArea;
  51. public Builder(FragmentActivity activity) {
  52. super(activity);
  53. setContentView(R.layout.dialog_address);
  54. setAnimStyle(BaseDialog.AnimStyle.BOTTOM);
  55. setGravity(Gravity.BOTTOM);
  56. DisplayMetrics displayMetrics = new DisplayMetrics();
  57. ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(displayMetrics);
  58. setWidth(MATCH_PARENT);
  59. setHeight(displayMetrics.heightPixels / 2);
  60. mTitleView = findViewById(R.id.tv_dialog_address_title);
  61. mCloseView = findViewById(R.id.iv_dialog_address_closer);
  62. mTabLayout = findViewById(R.id.tb_dialog_address_tab);
  63. mRecyclerView1 = findViewById(R.id.rv_dialog_address_list1);
  64. mRecyclerView2 = findViewById(R.id.rv_dialog_address_list2);
  65. mRecyclerView3 = findViewById(R.id.rv_dialog_address_list3);
  66. mHintView = findViewById(R.id.iv_dialog_address_hint);
  67. mAdapter1 = new AddressDialogAdapter(getContext());
  68. mAdapter2 = new AddressDialogAdapter(getContext());
  69. mAdapter3 = new AddressDialogAdapter(getContext());
  70. mCloseView.setOnClickListener(this);
  71. mAdapter1.setOnItemClickListener(this);
  72. mAdapter2.setOnItemClickListener(this);
  73. mAdapter3.setOnItemClickListener(this);
  74. mRecyclerView1.setAdapter(mAdapter1);
  75. mRecyclerView2.setAdapter(mAdapter2);
  76. mRecyclerView3.setAdapter(mAdapter3);
  77. mTabLayout.addTab(mTabLayout.newTab().setText(getText(R.string.dialog_select_hint)), true);
  78. mTabLayout.addOnTabSelectedListener(this);
  79. // 显示省份列表
  80. mAdapter1.setData(ProvinceUtils.getProvinceList(getContext()));
  81. }
  82. public Builder setTitle(int resId) {
  83. return setTitle(getText(resId));
  84. }
  85. public Builder setTitle(CharSequence text) {
  86. mTitleView.setText(text);
  87. return this;
  88. }
  89. /**
  90. * 设置默认省份
  91. */
  92. public Builder setProvince(String name) {
  93. if (name != null && !"".equals(name)) {
  94. List<AddressBean> data = mAdapter1.getData();
  95. if (data != null && !data.isEmpty()) {
  96. for (int i = 0; i < data.size(); i++) {
  97. if (name.equals(data.get(i).getName())) {
  98. onItemClick(mRecyclerView1, null, i);
  99. }
  100. }
  101. }
  102. }
  103. return this;
  104. }
  105. /**
  106. * 设置默认城市
  107. */
  108. public Builder setCity(String name) {
  109. if (mIgnoreArea) {
  110. // 已经忽略了县级区域的选择,不能选定指定的城市
  111. throw new IllegalStateException("The selection of county-level regions has been ignored. The designated city cannot be selected");
  112. }
  113. if (name != null && !"".equals(name)) {
  114. List<AddressBean> data = mAdapter2.getData();
  115. if (data != null && !data.isEmpty()) {
  116. for (int i = 0; i < data.size(); i++) {
  117. if (name.equals(data.get(i).getName())) {
  118. onItemClick(mRecyclerView2, null, i);
  119. }
  120. }
  121. }
  122. }
  123. return this;
  124. }
  125. /**
  126. * 不选择县级区域
  127. */
  128. public Builder setIgnoreArea() {
  129. List<AddressBean> data = mAdapter2.getData();
  130. if (data != null && !data.isEmpty()) {
  131. // 已经指定了城市,不能再忽略县级区域
  132. throw new IllegalStateException("Cities have been designated and county-level areas can no longer be ignored");
  133. }
  134. mIgnoreArea = true;
  135. return this;
  136. }
  137. public Builder setListener(OnListener l) {
  138. mListener = l;
  139. return this;
  140. }
  141. /**
  142. * {@link BaseRecyclerViewAdapter.OnItemClickListener}
  143. */
  144. @Override
  145. public synchronized void onItemClick(RecyclerView recyclerView, View itemView, int position) {
  146. if (recyclerView == mRecyclerView1) {
  147. // 记录当前选择的省份
  148. mProvince = mAdapter1.getItem(position).getName();
  149. mTabLayout.getTabAt(mTabLayout.getSelectedTabPosition()).setText(mProvince);
  150. mTabLayout.addTab(mTabLayout.newTab().setText(getContext().getResources().getString(R.string.dialog_select_hint)), true);
  151. mAdapter2.setData(ProvinceUtils.getCityList(mAdapter1.getItem(position).getNext()));
  152. mRecyclerView1.setVisibility(View.GONE);
  153. mRecyclerView2.setVisibility(View.VISIBLE);
  154. // 如果当前选择的是直辖市,就直接跳过选择城市,直接选择区域
  155. if (mAdapter2.getItemCount() == 1) {
  156. onItemClick(mRecyclerView2, null, 0);
  157. }
  158. } else if (recyclerView == mRecyclerView2) {
  159. // 记录当前选择的城市
  160. mCity = mAdapter2.getItem(position).getName();
  161. mTabLayout.getTabAt(mTabLayout.getSelectedTabPosition()).setText(mCity);
  162. if (mIgnoreArea) {
  163. if (mListener != null) {
  164. mListener.onSelected(getDialog(), mProvince, mCity, mArea);
  165. }
  166. // 延迟关闭
  167. postDelayed(this, 300);
  168. } else {
  169. mTabLayout.addTab(mTabLayout.newTab().setText(getText(R.string.dialog_select_hint)), true);
  170. mAdapter3.setData(ProvinceUtils.getAreaList(mAdapter2.getItem(position).getNext()));
  171. }
  172. mRecyclerView2.setVisibility(View.GONE);
  173. if (mIgnoreArea) {
  174. mHintView.setVisibility(View.VISIBLE);
  175. } else {
  176. mRecyclerView3.setVisibility(View.VISIBLE);
  177. }
  178. } else if (recyclerView == mRecyclerView3) {
  179. // 记录当前选择的区域
  180. mArea = mAdapter3.getItem(position).getName();
  181. mTabLayout.getTabAt(mTabLayout.getSelectedTabPosition()).setText(mArea);
  182. mRecyclerView3.setVisibility(View.INVISIBLE);
  183. mHintView.setVisibility(View.VISIBLE);
  184. if (mListener != null) {
  185. mListener.onSelected(getDialog(), mProvince, mCity, mArea);
  186. }
  187. // 延迟关闭
  188. postDelayed(this, 300);
  189. }
  190. }
  191. /**
  192. * {@link Runnable}
  193. */
  194. @Override
  195. public void run() {
  196. if (getDialogFragment() != null &&
  197. getDialogFragment().isAdded() &&
  198. getDialog() != null &&
  199. getDialog().isShowing()) {
  200. dismiss();
  201. }
  202. }
  203. /**
  204. * {@link View.OnClickListener}
  205. */
  206. @Override
  207. public void onClick(View v) {
  208. if (v == mCloseView) {
  209. dismiss();
  210. if (mListener != null) {
  211. mListener.onCancel(getDialog());
  212. }
  213. }
  214. }
  215. /**
  216. * {@link TabLayout.OnTabSelectedListener}
  217. */
  218. // Tab条目被选中
  219. @Override
  220. public void onTabSelected(TabLayout.Tab tab) {
  221. tab.setText(getText(R.string.dialog_select_hint));
  222. switch (tab.getPosition()) {
  223. case 0:
  224. mProvince = mCity = mArea = null;
  225. if (mTabLayout.getTabAt(2) != null) {
  226. mTabLayout.removeTabAt(2);
  227. }
  228. if (mTabLayout.getTabAt(1) != null) {
  229. mTabLayout.removeTabAt(1);
  230. }
  231. mRecyclerView1.setVisibility(View.VISIBLE);
  232. mRecyclerView2.setVisibility(View.GONE);
  233. mRecyclerView3.setVisibility(View.GONE);
  234. break;
  235. case 1:
  236. mCity = mArea = null;
  237. if (mTabLayout.getTabAt(2) != null) {
  238. mTabLayout.removeTabAt(2);
  239. }
  240. mRecyclerView1.setVisibility(View.GONE);
  241. mRecyclerView2.setVisibility(View.VISIBLE);
  242. mRecyclerView3.setVisibility(View.GONE);
  243. break;
  244. case 2:
  245. mArea = null;
  246. mRecyclerView1.setVisibility(View.GONE);
  247. mRecyclerView2.setVisibility(View.GONE);
  248. mRecyclerView3.setVisibility(View.VISIBLE);
  249. break;
  250. default:
  251. break;
  252. }
  253. }
  254. // Tab条目被取消选中
  255. @Override
  256. public void onTabUnselected(TabLayout.Tab tab) {
  257. }
  258. // Tab条目被重复点击
  259. @Override
  260. public void onTabReselected(TabLayout.Tab tab) {
  261. }
  262. // @Override
  263. // protected BaseDialog createDialog(Context context, int themeResId) {
  264. // if (getGravity() == Gravity.BOTTOM) {
  265. // return new BaseBottomDialog(context, themeResId);
  266. // }
  267. // return super.createDialog(context, themeResId);
  268. // }
  269. }
  270. private static final class AddressDialogAdapter extends BaseRecyclerViewAdapter<AddressBean, BaseRecyclerViewAdapter.ViewHolder> {
  271. private AddressDialogAdapter(Context context) {
  272. super(context);
  273. }
  274. @NonNull
  275. @Override
  276. public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int position) {
  277. TextView textView = new TextView(parent.getContext());
  278. textView.setGravity(Gravity.CENTER_VERTICAL);
  279. TypedValue typedValue = new TypedValue();
  280. if (getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground, typedValue, true)) {
  281. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
  282. textView.setBackground(getDrawable(typedValue.resourceId));
  283. } else {
  284. textView.setBackgroundDrawable(getDrawable(typedValue.resourceId));
  285. }
  286. }
  287. textView.setTextColor(0xFF222222);
  288. textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
  289. textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
  290. textView.setPadding((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, getResources().getDisplayMetrics()),
  291. (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics()),
  292. (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, getResources().getDisplayMetrics()),
  293. (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics()));
  294. return new ViewHolder(textView);
  295. }
  296. @Override
  297. public void onBindViewHolder(@NonNull BaseRecyclerViewAdapter.ViewHolder holder, int position) {
  298. ((TextView) holder.itemView).setText(getItem(position).getName());
  299. }
  300. }
  301. private static final class AddressBean {
  302. private String name; // 省、市、区的名称
  303. private JSONObject next; // 下一级的 Json
  304. private AddressBean(String name, JSONObject next) {
  305. this.name = name;
  306. this.next = next;
  307. }
  308. private String getName() {
  309. return name;
  310. }
  311. private JSONObject getNext() {
  312. return next;
  313. }
  314. }
  315. /**
  316. * 省市区读取工具类
  317. */
  318. private static final class ProvinceUtils {
  319. /**
  320. * 获取省列表
  321. */
  322. private static List<AddressBean> getProvinceList(Context context) {
  323. try {
  324. // 省市区Json数据文件来源:https://github.com/getActivity/ProvinceJson
  325. JSONArray jsonArray = new JSONArray(getAssetsString(context, "province.json"));
  326. int length = jsonArray.length();
  327. ArrayList<AddressBean> list = new ArrayList<>(length);
  328. for (int i = 0; i < length; i++) {
  329. JSONObject jsonObject = jsonArray.getJSONObject(i);
  330. list.add(new AddressBean(jsonObject.getString("name"), jsonObject));
  331. }
  332. return list;
  333. } catch (JSONException e) {
  334. e.printStackTrace();
  335. return null;
  336. }
  337. }
  338. /**
  339. * 获取城市列表
  340. *
  341. * @param jsonObject 城市Json
  342. */
  343. private static List<AddressBean> getCityList(JSONObject jsonObject) {
  344. try {
  345. JSONArray listCity = jsonObject.getJSONArray("city");
  346. int length = listCity.length();
  347. ArrayList<AddressBean> list = new ArrayList<>(length);
  348. for (int i = 0; i < length; i++) {
  349. list.add(new AddressBean(listCity.getJSONObject(i).getString("name"), listCity.getJSONObject(i)));
  350. }
  351. return list;
  352. } catch (JSONException e) {
  353. e.printStackTrace();
  354. return null;
  355. }
  356. }
  357. /**
  358. * 获取区域列表
  359. *
  360. * @param jsonObject 区域 Json
  361. */
  362. private static List<AddressBean> getAreaList(JSONObject jsonObject) {
  363. try {
  364. JSONArray listArea = jsonObject.getJSONArray("area");
  365. int length = listArea.length();
  366. ArrayList<AddressBean> list = new ArrayList<>(length);
  367. for (int i = 0; i < length; i++) {
  368. String string = listArea.getString(i);
  369. list.add(new AddressBean(string, null));
  370. }
  371. return list;
  372. } catch (JSONException e) {
  373. e.printStackTrace();
  374. return null;
  375. }
  376. }
  377. /**
  378. * 获取资产目录下面文件的字符串
  379. */
  380. private static String getAssetsString(Context context, String file) {
  381. try {
  382. InputStream inputStream = context.getAssets().open(file);
  383. ByteArrayOutputStream outStream = new ByteArrayOutputStream();
  384. byte[] buffer = new byte[512];
  385. int length;
  386. while ((length = inputStream.read(buffer)) != -1) {
  387. outStream.write(buffer, 0, length);
  388. }
  389. outStream.close();
  390. inputStream.close();
  391. return outStream.toString();
  392. } catch (IOException e) {
  393. e.printStackTrace();
  394. return null;
  395. }
  396. }
  397. }
  398. public interface OnListener {
  399. /**
  400. * 选择完成后回调
  401. *
  402. * @param province 省
  403. * @param city 市
  404. * @param area 区
  405. */
  406. void onSelected(Dialog dialog, String province, String city, String area);
  407. /**
  408. * 点击取消时回调
  409. */
  410. void onCancel(Dialog dialog);
  411. }
  412. }