├── .gitignore ├── ChinaCitySelection.iml ├── README.md ├── app ├── .gitignore ├── app.iml ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── knight │ │ └── chinacityselection │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── assets │ ├── city.db │ └── city.json │ ├── java │ └── knight │ │ └── chinacityselection │ │ ├── ClientApplication.java │ │ ├── MainActivity.java │ │ ├── adapter │ │ └── GridViewAdapter.java │ │ ├── db │ │ ├── City.java │ │ └── CityDB.java │ │ └── views │ │ └── GridPop.java │ └── res │ ├── drawable │ ├── arrow_down.png │ ├── arrow_up.png │ ├── city_select.xml │ ├── city_select_normal_shape.xml │ ├── city_select_pop_window_action_bar_shape.xml │ ├── city_select_pressed_shape.xml │ └── image1.jpg │ ├── layout │ ├── activity_main.xml │ ├── city_select_btn_item.xml │ └── pop_grid_view.xml │ ├── menu │ └── menu_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshot ├── screen1.PNG ├── screen2.PNG ├── screen3.PNG └── screen4.PNG └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | 8 | /.idea 9 | 10 | -------------------------------------------------------------------------------- /ChinaCitySelection.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 38 | 209 | 222 | 223 | 224 | 225 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # China city selection 2 | select china city or county with popwindow 3 | 4 | 5 | ## Screenshots 6 | ![Image](https://raw.githubusercontent.com/andyiac/ChinaCitySelection/master/screenshot/screen1.PNG) 7 | ![Image](https://raw.githubusercontent.com/andyiac/ChinaCitySelection/master/screenshot/screen2.PNG) 8 | 9 | ![Image](https://raw.githubusercontent.com/andyiac/ChinaCitySelection/master/screenshot/screen3.PNG) 10 | ![Image](https://raw.githubusercontent.com/andyiac/ChinaCitySelection/master/screenshot/screen4.PNG) 11 | 12 | 13 | ## License 14 | Copyright (c) 2014 andyiacZhang 15 | 16 | Licensed under the Apache License, Version 2.0 (the "License"); 17 | you may not use this file except in compliance with the License. 18 | You may obtain a copy of the License at 19 | 20 | http://www.apache.org/licenses/LICENSE-2.0 21 | 22 | Unless required by applicable law or agreed to in writing, software 23 | distributed under the License is distributed on an "AS IS" BASIS, 24 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 25 | See the License for the specific language governing permissions and 26 | limitations under the License. 27 | 28 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 115 | 286 | 299 | 300 | 301 | 302 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 21 5 | buildToolsVersion "21.1.2" 6 | 7 | defaultConfig { 8 | applicationId "knight.chinacityselection" 9 | minSdkVersion 9 10 | targetSdkVersion 22 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | compile 'com.android.support:appcompat-v7:22.0.0' 25 | compile 'com.jakewharton:butterknife:6.1.0' 26 | compile 'com.jakewharton.timber:timber:2.7.1' 27 | compile 'com.android.support:gridlayout-v7:22.0.0' 28 | compile 'com.android.support:support-v4:22.0.0' 29 | } 30 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Android_sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/knight/chinacityselection/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package knight.chinacityselection; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/assets/city.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andyiac/ChinaCitySelection/3d8a027aff7eb111b3090fa29cdf75556c570465/app/src/main/assets/city.db -------------------------------------------------------------------------------- /app/src/main/java/knight/chinacityselection/ClientApplication.java: -------------------------------------------------------------------------------- 1 | package knight.chinacityselection; 2 | 3 | import android.app.Application; 4 | import android.os.Environment; 5 | 6 | import java.io.File; 7 | import java.io.FileOutputStream; 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | 11 | import knight.chinacityselection.db.CityDB; 12 | 13 | public class ClientApplication extends Application { 14 | private static ClientApplication mApplication; 15 | private static CityDB mCityDB; 16 | 17 | @Override 18 | public void onCreate() { 19 | super.onCreate(); 20 | mApplication = this; 21 | initCityList(); 22 | } 23 | 24 | public static ClientApplication getInstance() { 25 | return mApplication; 26 | } 27 | 28 | public synchronized CityDB getCityDB() { 29 | if (mCityDB == null) 30 | mCityDB = openCityDB(); 31 | return mCityDB; 32 | } 33 | 34 | private void initCityList() { 35 | mCityDB = openCityDB();// 这个必须最先复制完,所以我放在单线程中处理 36 | } 37 | 38 | private CityDB openCityDB() { 39 | String path = "/data" 40 | + Environment.getDataDirectory().getAbsolutePath() 41 | + File.separator + "knight.chinacityselection" + File.separator 42 | + CityDB.CITY_DB_NAME; 43 | File db = new File(path); 44 | if (!db.exists()) { 45 | try { 46 | InputStream is = getAssets().open("city.db"); 47 | FileOutputStream fos = new FileOutputStream(db); 48 | int len = -1; 49 | byte[] buffer = new byte[1024]; 50 | while ((len = is.read(buffer)) != -1) { 51 | fos.write(buffer, 0, len); 52 | fos.flush(); 53 | } 54 | fos.close(); 55 | is.close(); 56 | } catch (IOException e) { 57 | e.printStackTrace(); 58 | System.exit(0); 59 | } 60 | } 61 | return new CityDB(this, path); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/knight/chinacityselection/MainActivity.java: -------------------------------------------------------------------------------- 1 | package knight.chinacityselection; 2 | 3 | import android.graphics.drawable.Drawable; 4 | import android.os.Bundle; 5 | import android.support.v4.app.FragmentActivity; 6 | import android.view.View; 7 | import android.widget.Button; 8 | 9 | import knight.chinacityselection.views.GridPop; 10 | 11 | 12 | public class MainActivity extends FragmentActivity { 13 | 14 | 15 | private GridPop gridpop; 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.activity_main); 21 | 22 | initView(); 23 | 24 | } 25 | 26 | private void initView() { 27 | 28 | Button btn1 = (Button) findViewById(R.id.id_btn_1); 29 | Button btn2 = (Button) findViewById(R.id.id_btn_2); 30 | 31 | shiftBtnRightDrawableUp(btn1); 32 | shiftBtnRightDrawableUp(btn2); 33 | 34 | gridpop = new GridPop(MainActivity.this, R.layout.pop_grid_view); 35 | 36 | btn1.setOnClickListener(new View.OnClickListener() { 37 | @Override 38 | public void onClick(View v) { 39 | if (gridpop != null) { 40 | gridpop.toggle(v); 41 | } 42 | } 43 | }); 44 | btn2.setOnClickListener(new View.OnClickListener() { 45 | @Override 46 | public void onClick(final View v) { 47 | if (gridpop != null) { 48 | gridpop.toggle(v); 49 | } 50 | } 51 | }); 52 | 53 | } 54 | 55 | //设置默认btn的状态 56 | private void shiftBtnRightDrawableUp(Button btn) { 57 | Drawable mDrawableUp = getResources().getDrawable(R.drawable.arrow_up); 58 | mDrawableUp.setBounds(1, 1, 50, 50); 59 | btn.setCompoundDrawablesWithIntrinsicBounds(null, null, mDrawableUp, null); 60 | } 61 | 62 | } 63 | 64 | 65 | -------------------------------------------------------------------------------- /app/src/main/java/knight/chinacityselection/adapter/GridViewAdapter.java: -------------------------------------------------------------------------------- 1 | package knight.chinacityselection.adapter; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import android.widget.Button; 9 | 10 | import java.util.ArrayList; 11 | 12 | import knight.chinacityselection.R; 13 | 14 | public class GridViewAdapter extends BaseAdapter { 15 | 16 | private ArrayList adapterList; 17 | private Context mContext; 18 | private LayoutInflater inflater; 19 | 20 | public GridViewAdapter(Context context, ArrayList dataList) { 21 | mContext = context; 22 | inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 23 | adapterList = dataList; 24 | } 25 | 26 | @Override 27 | public int getCount() { 28 | return adapterList.size(); 29 | } 30 | 31 | @Override 32 | public Object getItem(int position) { 33 | return position; 34 | } 35 | 36 | @Override 37 | public long getItemId(int position) { 38 | return position; 39 | } 40 | 41 | @Override 42 | public View getView(int position, View convertView, ViewGroup parent) { 43 | convertView = inflater.inflate(R.layout.city_select_btn_item, null); 44 | Button btn = (Button) convertView.findViewById(R.id.id_item_btn); 45 | btn.setText(adapterList.get(position)); 46 | return convertView; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/knight/chinacityselection/db/City.java: -------------------------------------------------------------------------------- 1 | package knight.chinacityselection.db; 2 | 3 | import java.io.Serializable; 4 | 5 | public class City implements Serializable { 6 | 7 | private static final long serialVersionUID = 1L; 8 | private String province; 9 | private String city; 10 | // private String number; 11 | private String firstPY; 12 | private String allPY; 13 | private String allFristPY; 14 | 15 | /** 16 | * 经度 17 | */ 18 | private Double longitude; 19 | 20 | /** 21 | * 纬度 22 | */ 23 | private Double latitude; 24 | 25 | public City() { 26 | // TODO Auto-generated constructor stub 27 | } 28 | 29 | public City(String province, String city,Double lat, Double lon) { 30 | super(); 31 | this.province = province; 32 | this.city = city; 33 | // this.number = number; 34 | this.firstPY = firstPY; 35 | this.allPY = allPY; 36 | this.allFristPY = allFristPY; 37 | this.latitude = lat; 38 | this.longitude = lon; 39 | } 40 | 41 | public String getProvince() { 42 | return province; 43 | } 44 | 45 | public void setProvince(String province) { 46 | this.province = province; 47 | } 48 | 49 | public String getCity() { 50 | return city; 51 | } 52 | 53 | public void setCity(String city) { 54 | this.city = city; 55 | } 56 | 57 | // public String getNumber() { 58 | // return number; 59 | // } 60 | // 61 | // public void setNumber(String number) { 62 | // this.number = number; 63 | // } 64 | 65 | public String getFirstPY() { 66 | return firstPY; 67 | } 68 | 69 | public void setFirstPY(String firstPY) { 70 | this.firstPY = firstPY; 71 | } 72 | 73 | public String getAllPY() { 74 | return allPY; 75 | } 76 | 77 | public void setAllPY(String allPY) { 78 | this.allPY = allPY; 79 | } 80 | 81 | public String getAllFristPY() { 82 | return allFristPY; 83 | } 84 | 85 | public void setAllFristPY(String allFristPY) { 86 | this.allFristPY = allFristPY; 87 | } 88 | 89 | public Double getLongitude() { 90 | return longitude; 91 | } 92 | 93 | public void setLongitude(Double longitude) { 94 | this.longitude = longitude; 95 | } 96 | 97 | public Double getLatitude() { 98 | return latitude; 99 | } 100 | 101 | public void setLatitude(Double latitude) { 102 | this.latitude = latitude; 103 | } 104 | 105 | @Override 106 | public String toString() { 107 | return "City [province=" + province + ", city=" + city 108 | + ", firstPY=" + firstPY + ", allPY=" + allPY 109 | + ", allFristPY=" + allFristPY + "]"; 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /app/src/main/java/knight/chinacityselection/db/CityDB.java: -------------------------------------------------------------------------------- 1 | package knight.chinacityselection.db; 2 | 3 | import android.content.Context; 4 | import android.database.Cursor; 5 | import android.database.sqlite.SQLiteDatabase; 6 | import android.text.TextUtils; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | public class CityDB { 12 | public static final String CITY_DB_NAME = "kuaihuo.db"; 13 | private static final String CITY_TABLE_NAME = "city"; 14 | private SQLiteDatabase db; 15 | 16 | public CityDB(Context context, String path) { 17 | db = context.openOrCreateDatabase(path, Context.MODE_PRIVATE, null); 18 | } 19 | 20 | public List getAllCity() { 21 | List list = new ArrayList(); 22 | Cursor c = db.rawQuery("SELECT * from " + CITY_TABLE_NAME, null); 23 | while (c.moveToNext()) { 24 | String province = c.getString(c.getColumnIndex("province")); 25 | String city = c.getString(c.getColumnIndex("city")); 26 | Double latitude = c.getDouble(c.getColumnIndex("latitude")); 27 | Double longitude = c.getDouble(c.getColumnIndex("longitude")); 28 | City item = new City(province, city, latitude, longitude); 29 | list.add(item); 30 | } 31 | return list; 32 | } 33 | 34 | 35 | public List getAllProvince() { 36 | 37 | List list = new ArrayList<>(); 38 | 39 | Cursor c = db.rawQuery("SELECT distinct province from " + CITY_TABLE_NAME, null); 40 | while (c.moveToNext()) { 41 | String province = c.getString(c.getColumnIndex("province")); 42 | list.add(province); 43 | } 44 | return list; 45 | } 46 | 47 | 48 | /** 49 | * 拿到省的所有 地级市 50 | * 51 | * @return 52 | */ 53 | public List getProvinceAllCity(String province) { 54 | 55 | List list = new ArrayList<>(); 56 | 57 | Cursor c = db.rawQuery("SELECT distinct city from " + CITY_TABLE_NAME + " where province = ? ", new String[]{province}); 58 | while (c.moveToNext()) { 59 | String city = c.getString(c.getColumnIndex("city")); 60 | list.add(city); 61 | } 62 | return list; 63 | } 64 | 65 | /** 66 | * 拿到所有的 县或区 67 | * 68 | * @return 69 | */ 70 | public List getAllCountry(String province, String city) { 71 | 72 | List list = new ArrayList<>(); 73 | 74 | Cursor c = db.rawQuery("SELECT country from " + CITY_TABLE_NAME + " where province = ? and city = ?", new String[]{province, city}); 75 | while (c.moveToNext()) { 76 | String country = c.getString(c.getColumnIndex("country")); 77 | list.add(country); 78 | } 79 | return list; 80 | } 81 | 82 | public City getCity(String city) { 83 | if (TextUtils.isEmpty(city)) 84 | return null; 85 | City item = getCityInfo(parseName(city)); 86 | if (item == null) { 87 | item = getCityInfo(city); 88 | } 89 | return item; 90 | } 91 | 92 | /** 93 | * 去掉市或县搜索 94 | * 95 | * @param city 96 | * @return 97 | */ 98 | private String parseName(String city) { 99 | if (city.contains("市")) {// 如果为空就去掉市字再试试 100 | String subStr[] = city.split("市"); 101 | city = subStr[0]; 102 | } else if (city.contains("县")) {// 或者去掉县字再试试 103 | String subStr[] = city.split("县"); 104 | city = subStr[0]; 105 | } 106 | return city; 107 | } 108 | 109 | private City getCityInfo(String city) { 110 | Cursor c = db.rawQuery("SELECT * from " + CITY_TABLE_NAME 111 | + " where city=?", new String[]{city}); 112 | if (c.moveToFirst()) { 113 | String province = c.getString(c.getColumnIndex("province")); 114 | String name = c.getString(c.getColumnIndex("city")); 115 | Double latitude = c.getDouble(c.getColumnIndex("latitude")); 116 | Double longitude = c.getDouble(c.getColumnIndex("longitude")); 117 | 118 | City item = new City(province, name, latitude, longitude); 119 | return item; 120 | } 121 | return null; 122 | } 123 | 124 | 125 | /** 126 | * 查询附近的城市 127 | * 画正方形 128 | */ 129 | public List getNearbyCityList(String sCity) { 130 | City city = getCity(sCity); 131 | List nearbyCitysList = new ArrayList(); 132 | //根据常跑地信息画正方形地域 133 | double lat = city.getLatitude() + 0.9; 134 | double lon = city.getLongitude() + 0.9; 135 | double lat1 = city.getLatitude() - 0.9; 136 | double lon1 = city.getLongitude() - 0.9; 137 | 138 | Cursor c = db.rawQuery("SELECT * from " + CITY_TABLE_NAME + " WHERE LATITUDE < " + lat + " AND LATITUDE > " + lat1 + 139 | " AND LONGITUDE <" + lon + " AND LONGITUDE > " + lon1, null); 140 | while (c.moveToNext()) { 141 | String nearbyCity = c.getString(c.getColumnIndex("city")); 142 | nearbyCitysList.add(nearbyCity); 143 | } 144 | return nearbyCitysList; 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /app/src/main/java/knight/chinacityselection/views/GridPop.java: -------------------------------------------------------------------------------- 1 | package knight.chinacityselection.views; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.graphics.drawable.ColorDrawable; 6 | import android.graphics.drawable.Drawable; 7 | import android.view.KeyEvent; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.View.OnKeyListener; 11 | import android.widget.AdapterView; 12 | import android.widget.Button; 13 | import android.widget.GridView; 14 | import android.widget.LinearLayout.LayoutParams; 15 | import android.widget.PopupWindow; 16 | import android.widget.RelativeLayout; 17 | 18 | import java.util.ArrayList; 19 | 20 | import knight.chinacityselection.ClientApplication; 21 | import knight.chinacityselection.R; 22 | import knight.chinacityselection.adapter.GridViewAdapter; 23 | import knight.chinacityselection.db.CityDB; 24 | 25 | /** 26 | * 省市县选择 27 | * by andyiac 2015年3月29日 28 | */ 29 | public class GridPop extends PopupWindow { 30 | private Context context; 31 | private LayoutInflater layoutInflater; 32 | public View allView; 33 | private int resId; 34 | private GridView allItemGrid; 35 | 36 | private GridView gv; 37 | private CityDB cityDB; 38 | private GridViewAdapter gridViewAdapter; 39 | 40 | //选择城市标志位 41 | private FlagCitySelected flagCitySelected = FlagCitySelected.ZERO; 42 | 43 | private String mCurrentProvince; 44 | 45 | private ArrayList mCurrentStringArray; 46 | 47 | private RelativeLayout mRLPopTitleAction; 48 | 49 | private Button mCurrentClickedBtn; 50 | 51 | public interface onCitySelectedListener { 52 | public void onCitySelected(String city); 53 | } 54 | 55 | private onCitySelectedListener mOnCitySelectedListener; 56 | 57 | public void setOnCitySelectedListener(onCitySelectedListener l) { 58 | this.mOnCitySelectedListener = l; 59 | } 60 | 61 | public GridPop(Context context, int resourceId) { 62 | super(context); 63 | this.context = context; 64 | this.resId = resourceId; 65 | initAllPop(); 66 | initData(); 67 | 68 | initView(); 69 | } 70 | 71 | /** 72 | * 初始化TitleAction 73 | */ 74 | private void initTitleAction() { 75 | updateTitleAction(); 76 | } 77 | 78 | /** 79 | * 更新TitleAction 80 | */ 81 | private void updateTitleAction() { 82 | 83 | if (flagCitySelected.ordinal() == FlagCitySelected.ZERO.ordinal()) { 84 | mRLPopTitleAction.setVisibility(View.GONE); 85 | } else { 86 | mRLPopTitleAction.setVisibility(View.VISIBLE); 87 | } 88 | } 89 | 90 | private void initView() { 91 | 92 | mCurrentStringArray = (ArrayList) cityDB.getAllProvince(); 93 | 94 | gv = getAllItemGrid(); 95 | gridViewAdapter = new GridViewAdapter(context, mCurrentStringArray); 96 | 97 | gv.setAdapter(gridViewAdapter); 98 | gv.setOnItemClickListener(new AdapterView.OnItemClickListener() { 99 | 100 | @Override 101 | public void onItemClick(AdapterView parent, View view, int position, long id) { 102 | switch (flagCitySelected) { 103 | case ZERO: 104 | mOnCitySelectedListener.onCitySelected(mCurrentStringArray.get(position)); 105 | mCurrentProvince = mCurrentStringArray.get(position); 106 | flagCitySelected = FlagCitySelected.PROVINCE; 107 | update2AllCity(mCurrentProvince); 108 | break; 109 | case PROVINCE: 110 | mOnCitySelectedListener.onCitySelected(mCurrentStringArray.get(position)); 111 | String city = mCurrentStringArray.get(position); 112 | flagCitySelected = FlagCitySelected.CITY; 113 | update2AllCountry(mCurrentProvince, city); 114 | break; 115 | case CITY: 116 | mOnCitySelectedListener.onCitySelected(mCurrentStringArray.get(position)); 117 | flagCitySelected = FlagCitySelected.ZERO; 118 | GridPop.this.dismiss(); 119 | update2AllProvince(); 120 | break; 121 | } 122 | updateTitleAction(); 123 | } 124 | }); 125 | 126 | 127 | mRLPopTitleAction = (RelativeLayout) allView.findViewById(R.id.layout_id_pop_grid); 128 | initTitleAction(); 129 | 130 | //初始化 pop window action title 131 | Button backBtn = (Button) allView.findViewById(R.id.id_btn_pop_grid_back); 132 | backBtn.setOnClickListener(new View.OnClickListener() { 133 | @Override 134 | public void onClick(View v) { 135 | 136 | switch (flagCitySelected) { 137 | case PROVINCE: 138 | flagCitySelected = FlagCitySelected.ZERO; 139 | update2AllProvince(); 140 | break; 141 | case CITY: 142 | flagCitySelected = FlagCitySelected.PROVINCE; 143 | update2AllCity(mCurrentProvince); 144 | break; 145 | } 146 | 147 | updateTitleAction(); 148 | } 149 | }); 150 | 151 | Button allAreaBtn = (Button) allView.findViewById(R.id.id_btn_pop_grid_all); 152 | allAreaBtn.setOnClickListener(new View.OnClickListener() { 153 | @Override 154 | public void onClick(View v) { 155 | GridPop.this.dismiss(); 156 | } 157 | }); 158 | } 159 | 160 | private void initData() { 161 | cityDB = ClientApplication.getInstance().getCityDB(); 162 | } 163 | 164 | public void initAllPop() { 165 | layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 166 | allView = layoutInflater.inflate(resId, null); 167 | allView.setFocusable(true); 168 | allView.setFocusableInTouchMode(true); 169 | allItemGrid = (GridView) allView.findViewById(R.id.id_grid_view); 170 | allView.setFocusableInTouchMode(true); 171 | allView.setOnKeyListener(new OnKeyListener() { 172 | @Override 173 | public boolean onKey(View v, int keyCode, KeyEvent event) { 174 | if (isShowing()) { 175 | dismiss(); 176 | return true; 177 | } 178 | return false; 179 | } 180 | }); 181 | 182 | setContentView(allView); 183 | setWidth(LayoutParams.MATCH_PARENT); 184 | setHeight(LayoutParams.WRAP_CONTENT); 185 | setBackgroundDrawable(new ColorDrawable(Color.rgb(252, 252, 252))); 186 | setTouchable(true); 187 | setFocusable(true); 188 | setOutsideTouchable(false); 189 | setOnDismissListener(new OnDismissListener() { 190 | @Override 191 | public void onDismiss() { 192 | shiftBtnRightDrawableUp(); 193 | } 194 | }); 195 | 196 | } 197 | 198 | /** 199 | * @return 返回该pop中GridView, 可以其他地方设置该GridView 200 | */ 201 | public GridView getAllItemGrid() { 202 | return allItemGrid; 203 | } 204 | 205 | /** 206 | * 所有省 207 | */ 208 | private void update2AllProvince() { 209 | flagCitySelected = FlagCitySelected.ZERO; 210 | updateTitleAction(); 211 | mCurrentStringArray.clear(); 212 | mCurrentStringArray.addAll(cityDB.getAllProvince()); 213 | gridViewAdapter.notifyDataSetChanged(); 214 | } 215 | 216 | /** 217 | * 所有 市 218 | * 219 | * @param province 220 | */ 221 | private void update2AllCity(String province) { 222 | mCurrentStringArray.clear(); 223 | ArrayList cityList = (ArrayList) cityDB.getProvinceAllCity(province); 224 | mCurrentStringArray.addAll(cityList); 225 | gridViewAdapter.notifyDataSetChanged(); 226 | } 227 | 228 | /** 229 | * 所有县 230 | * 231 | * @param province 232 | * @param city 233 | */ 234 | private void update2AllCountry(String province, String city) { 235 | ArrayList cityList = (ArrayList) cityDB.getAllCountry(province, city); 236 | if (cityList.size() <= 1) { 237 | flagCitySelected = FlagCitySelected.ZERO; 238 | GridPop.this.dismiss(); 239 | update2AllProvince(); 240 | return; 241 | } 242 | mCurrentStringArray.clear(); 243 | mCurrentStringArray.addAll(cityList); 244 | gridViewAdapter.notifyDataSetChanged(); 245 | } 246 | 247 | /** 248 | * toggle gridPop windows 249 | * 250 | * @param v 251 | */ 252 | public void toggle(final View v) { 253 | 254 | mCurrentClickedBtn = (Button) v; 255 | if (this.isShowing()) { 256 | this.dismiss(); 257 | } else { 258 | update2AllProvince(); 259 | shiftBtnRightDrawableDown(); 260 | this.showAsDropDown(v, 0, 2); 261 | this.setOnCitySelectedListener(new GridPop.onCitySelectedListener() { 262 | @Override 263 | public void onCitySelected(String city) { 264 | ((Button) v).setText(city); 265 | } 266 | }); 267 | } 268 | } 269 | 270 | private void shiftBtnRightDrawableUp() { 271 | Drawable mDrawableUp = context.getResources().getDrawable(R.drawable.arrow_up); 272 | mDrawableUp.setBounds(1, 1, 50, 50); 273 | mCurrentClickedBtn.setCompoundDrawablesWithIntrinsicBounds(null, null, mDrawableUp, null); 274 | } 275 | 276 | private void shiftBtnRightDrawableDown() { 277 | Drawable mDrawableDown = context.getResources().getDrawable(R.drawable.arrow_down); 278 | mDrawableDown.setBounds(1, 1, 50, 50); 279 | mCurrentClickedBtn.setCompoundDrawablesWithIntrinsicBounds(null, null, mDrawableDown, null); 280 | } 281 | 282 | /** 283 | * 标志位 284 | */ 285 | private enum FlagCitySelected { 286 | ZERO, PROVINCE, CITY, COUNTRY 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andyiac/ChinaCitySelection/3d8a027aff7eb111b3090fa29cdf75556c570465/app/src/main/res/drawable/arrow_down.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/arrow_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andyiac/ChinaCitySelection/3d8a027aff7eb111b3090fa29cdf75556c570465/app/src/main/res/drawable/arrow_up.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/city_select.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/city_select_normal_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/city_select_pop_window_action_bar_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/city_select_pressed_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andyiac/ChinaCitySelection/3d8a027aff7eb111b3090fa29cdf75556c570465/app/src/main/res/drawable/image1.jpg -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 13 | 14 |