f9e35ac887026338092929e02a28ab99ff1cb0c5.svn-base 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  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.LEFT);
  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. // Tab条目被重复点击
  258. @Override
  259. public void onTabReselected(TabLayout.Tab tab) {}
  260. // @Override
  261. // protected BaseDialog createDialog(Context context, int themeResId) {
  262. // if (getGravity() == Gravity.BOTTOM) {
  263. // return new BaseBottomDialog(context, themeResId);
  264. // }
  265. // return super.createDialog(context, themeResId);
  266. // }
  267. }
  268. private static final class AddressDialogAdapter extends BaseRecyclerViewAdapter<AddressBean, BaseRecyclerViewAdapter.ViewHolder> {
  269. private AddressDialogAdapter(Context context) {
  270. super(context);
  271. }
  272. @NonNull
  273. @Override
  274. public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int position) {
  275. TextView textView = new TextView(parent.getContext());
  276. textView.setGravity(Gravity.CENTER_VERTICAL);
  277. TypedValue typedValue = new TypedValue();
  278. if (getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground, typedValue, true)) {
  279. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
  280. textView.setBackground(getDrawable(typedValue.resourceId));
  281. } else {
  282. textView.setBackgroundDrawable(getDrawable(typedValue.resourceId));
  283. }
  284. }
  285. textView.setTextColor(0xFF222222);
  286. textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
  287. textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
  288. textView.setPadding((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, getResources().getDisplayMetrics()),
  289. (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics()),
  290. (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, getResources().getDisplayMetrics()),
  291. (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics()));
  292. return new ViewHolder(textView);
  293. }
  294. @Override
  295. public void onBindViewHolder(@NonNull BaseRecyclerViewAdapter.ViewHolder holder, int position) {
  296. ((TextView) holder.itemView).setText(getItem(position).getName());
  297. }
  298. }
  299. private static final class AddressBean {
  300. private String name; // 省、市、区的名称
  301. private JSONObject next; // 下一级的 Json
  302. private AddressBean(String name, JSONObject next) {
  303. this.name = name;
  304. this.next = next;
  305. }
  306. private String getName() {
  307. return name;
  308. }
  309. private JSONObject getNext() {
  310. return next;
  311. }
  312. }
  313. /**
  314. * 省市区读取工具类
  315. */
  316. private static final class ProvinceUtils {
  317. /**
  318. * 获取省列表
  319. */
  320. private static List<AddressBean> getProvinceList(Context context) {
  321. try {
  322. // 省市区Json数据文件来源:https://github.com/getActivity/ProvinceJson
  323. JSONArray jsonArray = new JSONArray(getAssetsString(context, "province.json"));
  324. int length = jsonArray.length();
  325. ArrayList<AddressBean> list = new ArrayList<>(length);
  326. for (int i = 0; i < length; i++) {
  327. JSONObject jsonObject = jsonArray.getJSONObject(i);
  328. list.add(new AddressBean(jsonObject.getString("name"), jsonObject));
  329. }
  330. return list;
  331. } catch (JSONException e) {
  332. e.printStackTrace();
  333. return null;
  334. }
  335. }
  336. /**
  337. * 获取城市列表
  338. *
  339. * @param jsonObject 城市Json
  340. */
  341. private static List<AddressBean> getCityList(JSONObject jsonObject) {
  342. try {
  343. JSONArray listCity = jsonObject.getJSONArray("city");
  344. int length = listCity.length();
  345. ArrayList<AddressBean> list = new ArrayList<>(length);
  346. for (int i = 0; i < length; i++) {
  347. list.add(new AddressBean(listCity.getJSONObject(i).getString("name"), listCity.getJSONObject(i)));
  348. }
  349. return list;
  350. } catch (JSONException e) {
  351. e.printStackTrace();
  352. return null;
  353. }
  354. }
  355. /**
  356. * 获取区域列表
  357. *
  358. * @param jsonObject 区域 Json
  359. */
  360. private static List<AddressBean> getAreaList(JSONObject jsonObject) {
  361. try {
  362. JSONArray listArea = jsonObject.getJSONArray("area");
  363. int length = listArea.length();
  364. ArrayList<AddressBean> list = new ArrayList<>(length);
  365. for (int i = 0; i < length; i++) {
  366. String string = listArea.getString(i);
  367. list.add(new AddressBean(string, null));
  368. }
  369. return list;
  370. } catch (JSONException e) {
  371. e.printStackTrace();
  372. return null;
  373. }
  374. }
  375. /**
  376. * 获取资产目录下面文件的字符串
  377. */
  378. private static String getAssetsString(Context context, String file) {
  379. try {
  380. InputStream inputStream = context.getAssets().open(file);
  381. ByteArrayOutputStream outStream = new ByteArrayOutputStream();
  382. byte[] buffer = new byte[512];
  383. int length;
  384. while ((length = inputStream.read(buffer)) != -1) {
  385. outStream.write(buffer, 0, length);
  386. }
  387. outStream.close();
  388. inputStream.close();
  389. return outStream.toString();
  390. } catch (IOException e) {
  391. e.printStackTrace();
  392. return null;
  393. }
  394. }
  395. }
  396. public interface OnListener {
  397. /**
  398. * 选择完成后回调
  399. *
  400. * @param province 省
  401. * @param city 市
  402. * @param area 区
  403. */
  404. void onSelected(Dialog dialog, String province, String city, String area);
  405. /**
  406. * 点击取消时回调
  407. */
  408. void onCancel(Dialog dialog);
  409. }
  410. }