一步步实现一个城市选择器

城市选择器

今天我们一起实现一个城市选择器。O.O

代码下载:
城市选择器 - 下载频道 - CSDN.NET
http://download.csdn.net/detail/baidu_31093133/9675482

效果图预览

主要包含以下内容:

1、自动定位所在城市
2、热门城市列表展示
3、所有城市列表的展示
4、输入城市名或者城市拼音搜索对应城市
5、右侧的slidebar城市列表导航栏

请大家先下载Demo然后再一边看demo一边看博客。因为博客里很多代码因为比较简单就不贴了。

首先我们先搭建基本的UI:

分析效果图,我们需要一个顶部title view,一个搜索框,一个定位功能的view,一个展示热门城市的view,一个侧边栏view和一个listview。

###顶部title View:

这里有一些需要注意的地方:
我们在新建工程的时候,android studio会自动生成一个style作为我们的主题:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
</style>    

android:theme="@style/AppTheme"  

这个默认的主题是带有actionbar的,如果我们要去掉这个actionbar,首先需要把DarkActionBar改为NoActionBar,因为使用AppCompatActivity的时候,Activity必须使用Theme.AppCompat主题及其子主题,所以我们的自定义的HD_NoActionBar样式必须继承这个主题:

 <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
</style>
<style name="HD_NoActionBar" parent="AppTheme">
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowActionBar">false</item>
</style>

然后引用这个style:

android:theme="@style/AppTheme.NoActionBar"

接下来写我们的头布局 title_view.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="@color/light_blue">

    <ImageView
        android:id="@+id/back"
        style="@style/Widget.AppCompat.ActionButton"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:paddingLeft="16dp"
        android:paddingRight="16dp"
        android:scaleType="center"
        android:src="@mipmap/ic_back"
        tools:ignore="ContentDescription" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="@string/select_city"
        android:textSize="20sp"
        android:textColor="@color/white" />
</RelativeLayout>

<View
    android:layout_width="match_parent"
    android:layout_height="1dp"
    android:background="@color/white"/>

布局返回按钮用一个ImageView,title用一个Textview。

然后在我们的主布局里使用标签引入头布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/light_blue"
android:orientation="vertical">

<include layout="@layout/title_view" />

现在的效果是这样的:

title

搜索框布局 search view

search_view/xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="36dp"
android:layout_marginBottom="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"
android:gravity="center_vertical"
android:background="@drawable/search_box_bg">

<ImageView
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:paddingLeft="8dp"
    android:paddingRight="8dp"
    android:src="@mipmap/ic_search"
    android:scaleType="center"
    tools:ignore="ContentDescription" />

<EditText
    android:id="@+id/et_search"
    android:layout_weight="1"
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:background="@null"
    android:gravity="center_vertical"
    android:hint="@string/hint_search_box"
    android:textColorHint="@color/deep_blue"
    android:inputType="text"
    android:singleLine="true"
    android:textColor="@color/deep_blue"
    android:textSize="14sp"
    tools:ignore="RtlHardcoded" />

<ImageView
    android:id="@+id/iv_search_clear"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:paddingLeft="8dp"
    android:paddingRight="8dp"
    android:src="@mipmap/ic_search_clear"
    android:visibility="gone"
    tools:ignore="ContentDescription" />

然后在主布局里引入这个布局:

<include layout="@layout/search_view"/>

搜索框的布局也非常简单,就不说明了。

现在的效果:

###城市列表

接下来的定位城市、热门城市、以及所有城市的列表我们使用一个Listview搞定,让Listview加载三种不同的布局来展示。

定位城市和所有城市列表好说,这个热门城市的UI该怎么做呢?我们准备使用gridview来做,在listview里嵌套gridview会遇到gridview只能显示一行的问题,我们先重现这个问题,然后再分析怎么解决。

listview需要一个adapter适配器,adapter需要一个数据源,我们的数据源存放在一个db数据库里,所以我们要构建一个数据库操作类,从数据库中取出这些城市然后展示出来。这一段的代码比较多,前方高能预警(__)

我们把要做的事情按步骤划分:

1、导入数据库文件
2、构建City对象,用户存储城市信息
3、创建DBManager用来操作数据库,将查询到的数据传递给adapter
4、编写定位城市、热门城市、所有城市三种不同的item布局
5、编写adapter,在adapter里加载三种item布局
6、编写gridview热门城市的item布局
7、实现gridview的adapter

####1、建立assets文件,并把db文件放在assets目录下:

####2、City对象

City.java:

    public class City {
   
    private String name;
    private String pinyin;

    public City() {
   }

    public City(String name, String pinyin) {
   
        this.name = name;
        this.pinyin = pinyin;
    }

    public String getName() {
   
        return name;
    }

    public void setName(String name) {
   
        this.name = name;
    }

    public String getPinyin() {
   
        return pinyin;
    }

    public void setPinyin(String pinyin) {
   
        this.pinyin = pinyin;
    }
}

####数据库操作类:

DBManager.java:

  public class DBManager {
   
  private static final String ASSETS_NAME = "china_cities.db";
  private static final String DB_NAME = "china_cities.db";
  private static final String TABLE_NAME = "city";
  private static final String NAME = "name";
  private static final String PINYIN = "pinyin";
  private static final int BUFFER_SIZE = 1024;
  private String DB_PATH;
  private Context mContext;

  //初始化
  public DBManager(Context context) {
   
      this.mContext = context;
      DB_PATH = File.separator + "data"
              + Environment.getDataDirectory().getAbsolutePath() + File.separator
              + context.getPackageName() + File.separator + "databases" + File.separator;
  }
  //保存数据库到本地
  @SuppressWarnings("ResultOfMethodCallIgnored")
  public void copyDBFile(){
   
      File dir = new File(DB_PATH);
      if (!dir.exists()){
   
          dir.mkdirs();
      }
      File dbFile = new File(DB_PATH + DB_NAME);
      if (!dbFile.exists()){
   
          InputStream is;
          OutputStream os;
          try {
   
              is = mContext.getResources().getAssets().open(ASSETS_NAME);
              os = new FileOutputStream(dbFile);
              byte[] buffer = new byte[BUFFER_SIZE];
              int length;
              while ((length = is.read(buffer, 0, buffer.length)) > 0){
   
                  os.write(buffer, 0, length);
              }
              os.flush();
              os.close();
              is.close();
          } catch (IOException e) {
   
              e.printStackTrace();
          }
      }
  }
  /**
   * 读取所有城市
   * @return
   */
  public List<City> getAllCities(){
   
      SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(DB_PATH + DB_NAME, null);
      Cursor cursor = db.rawQuery("select * from " + TABLE_NAME, null);
      List<City> result = new ArrayList<>();
      City city;
      while (cursor.moveToNext()){
   
          String name = cursor.getString(cursor.getColumnIndex(NAME));
          String pinyin = cursor.getString(cursor.getColumnIndex(PINYIN));
          city = new City
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值