[Android] JSon trong Android – Phần 3: Thiết kế giao diện Old Lover

Chào các bạn, ở 2 phần trước chúng ta đã tìm hiểu JSon và cách xuất JSon từ Database bằng Php, mọi việc đều ổn. Và trong phần 3 này, chúng ta sẽ đi thiết kế giao diện cho Old Lover – Người yêu cũ. 😉

Ứng dụng được thực hiện trên Android studio 1.3
compileSdkVersion 22
buildToolsVersion “22.0.1”
minSdkVersion 14
targetSdkVersion 22

Chúng ta cùng xem lại video về Old Lover để hình dung lại giao diện app.

Cấu hình và các thứ cần thiết

Trước tiên chúng ta sẽ chuẩn bị một số thứ trong build.gradle, string, drawable, color, style,… Tất nhiên trong quá trình làm thì làm đến đâu mình thêm bớt đến đó nhưng khi viết hướng dẫn thì mình phải đưa ra hết trước để tránh các bạn bị lỗi hoặc thao tác khó khăn.

Cấu hình build.gradle và AndroidManifest

File build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 22
    buildToolsVersion "22.0.1"

    defaultConfig {
        applicationId "cachhoc.net.demojson"
        minSdkVersion 14
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:design:22.2.0'
    compile 'com.android.support:recyclerview-v7:22.0.+'
    compile 'com.android.support:cardview-v7:22.0.+'
    compile 'com.loopj.android:android-async-http:1.4.8'
    compile 'com.wdullaer:materialdatetimepicker:1.4.2'
}

Các bạn để ý mình có dùng một số thư viện như

  • android.support:design phục vụ cho việc thiết kế theo Material, Toolbar, FloadActionButton,…

  • recyclerview và cardview phục vụ cho list là chủ yếu

  • com.loopj.android:android-async-http thư viện cho phép thao tác đẩy hoặc lấy JSon giữa Android và Web. Các bạn có thể xem thêm tại đây: https://github.com/loopj/android-async-http

  • com.wdullaer:materialdatetimepicker dùng cho datetime picker như trong video, xem thêm tại https://github.com/wdullaer/MaterialDateTimePicker

File AndroidManifest.xml

Trong này quan trọng nhất là chúng ta cấp quyền truy cập internet cho ứng dụng.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="cachhoc.net.demojson" >

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/old_lover"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".LoginActivity"
            android:label="@string/old_lover"
            android:windowSoftInputMode="adjustPan" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".MainActivity"
            android:label="@string/old_lover" />
        <activity
            android:name=".RegisterActivity"
            android:label="@string/title_activity_register" >
        </activity>
        <activity
            android:name=".AddLoverActivity"
            android:label="@string/title_activity_add_lover" >
        </activity>
    </application>

</manifest>

Color, String, Style

File res/values/color.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!--Indigo 500-->
    <color name="primary">#3F51B5</color>
    <!--Indigo 700-->
    <color name="primary_dark">#303F9F</color>
    <!--Pink 500-->
    <color name="accent">#E91E63</color>
    <color name="white">#FFFFFF</color>

    <!-- for change color date picker-->
    <color name="mdtp_accent_color">@color/primary</color>
    <color name="mdtp_accent_color_dark">@color/primary_dark</color>

</resources>

File res/values/string.xml

Sở dĩ mình để các chuỗi mà có thể hiện thị cho người dùng ở string.xml mà không để trong code java vì nó phục vụ cho việc tạo đa ngôn ngữ cho app sau này.

<resources>
    <string name="app_name">DemoJson</string>

    <string name="refresh">Refresh</string>
    <string name="name">Name Lover</string>
    <string name="phone">Phone</string>
    <string name="begin_date">Begin date</string>
    <string name="end_date">End date</string>

    <string name="nick_name">Nick name</string>
    <string name="password">Password</string>
    <string name="re_password">Re Password</string>

    <string name="logout">Logout</string>
    <string name="login">Login</string>
    <string name="remember_me">Remember me</string>
    <string name="login_success">Login success</string>
    <string name="login_fail">Login fail</string>

    <string name="register">Register</string>
    <string name="reset">Reset</string>
    <string name="register_success">Register success</string>
    <string name="register_fail">Nick already exists</string>

    <string name="add_success">Add success</string>
    <string name="add_fail">Add fail</string>

    <string name="wait">Please wait…</string>
    <string name="add">Add</string>
    <string name="no_lover">You not have old lover</string>
    <string name="back_to_exit">Please click BACK again to exit</string>

    <string name="enter_nick">Please enter your nick name</string>
    <string name="enter_pass">Please enter your password</string>
    <string name="enter_repass">Please re enter your password</string>
    <string name="pass_not_match">Password not match</string>

    <string name="old_lover">Old Lover</string>
    <string name="title_activity_login">Login</string>
    <string name="title_activity_register">Register</string>
    <string name="title_activity_add_lover">Add Old Lover</string>
</resources>

File res/values/style.xml

<resources>

    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorPrimary">@color/primary</item>
        <item name="colorPrimaryDark">@color/primary_dark</item>
        <item name="colorAccent">@color/accent</item>
        <item name="windowActionBar">false</item>
        <item name="windowActionBarOverlay">true</item>
        <item name="windowNoTitle">true</item>
        <item name="android:windowBackground">@color/background_material_light</item>
    </style>

    <style name="MyAppDialog" parent="Theme.AppCompat.Light.Dialog">
        <item name="colorPrimary">@color/primary</item>
        <item name="colorPrimaryDark">@color/primary_dark</item>
        <item name="colorAccent">@color/accent</item>
    </style>

</resources>

Các icon

Các icon các bạn có thể tự tạo bằng cách sử dụng AndroidAssetStudio hoặc có thể download bộ icon của mình tại đây.

Vậy là xong các thứ cần thiết.

Thiết kế giao diện các activity

Như các bạn đã thấy, chúng ta sẽ có 4 Activity chính: Login (Đăng nhập), Register (Đăng ký), List Old Lover (Danh sách người yêu cũ) và cuối cùng là (Add) thêm mới.

Để thêm các activity các bạn làm một cách đơn giải là click chuột phải vào thư mục layout hoặc package trong java chọn new -> Activity -> Black Activity. Khi đó cả file layout xml, java và trong manifest đều có.

Các file trong res/layout
res old lover

Toolbar thay cho Actionbar

Các bạn để ý trong file style.xml ở trên, mình có đặt theme là Theme.AppCompat.Light.NoActionBar nên các activity sẽ không có actionbar. Thay vào đó mình sẽ sử dụng Toolbar nằm trong gói android.support.v7.widget để phục vụ cho việc thiết kế giao diện Material.

<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

Activity Login

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

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

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_below="@+id/toolbar"
        android:layout_centerHorizontal="true"
        android:layout_gravity="center"
        android:src="@drawable/ic_launch" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_below="@+id/imageView"
        android:orientation="vertical"
        android:padding="10dp">

        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <EditText
                android:id="@+id/edit_nick"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/nick_name"
                android:textColor="@color/accent" />
        </android.support.design.widget.TextInputLayout>

        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <EditText
                android:id="@+id/edit_pass"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/password"
                android:inputType="textPassword"
                android:textColor="@color/accent" />
        </android.support.design.widget.TextInputLayout>

        <CheckBox
            android:id="@+id/cb_remember"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/remember_me" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_marginTop="10dp">

            <Button
                android:id="@+id/btn_login"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:foreground="?android:attr/selectableItemBackground"
                android:text="@string/login" />

            <Button
                android:id="@+id/btn_register"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:foreground="?android:attr/selectableItemBackground"
                android:text="@string/register" />
        </LinearLayout>
    </LinearLayout>

</RelativeLayout>

Các bạn để ý mình có sử dụng EditText nằm trong android.support.design.widget.TextInputLayout, điều này sẽ giúp chúng ta tạo được EditText có hind và hind này sẽ tự động chạy lên trên thành 1 lable khi nó được forcus như trong video.

Activity Register

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

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

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_below="@+id/toolbar"
        android:layout_centerHorizontal="true"
        android:layout_gravity="center"
        android:src="@drawable/ic_launch" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_below="@+id/imageView"
        android:orientation="vertical"
        android:padding="10dp">

        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <EditText
                android:id="@+id/edit_nick"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/nick_name"
                android:textColor="@color/accent" />
        </android.support.design.widget.TextInputLayout>

        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <EditText
                android:id="@+id/edit_pass"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/password"
                android:inputType="textPassword"
                android:textColor="@color/accent" />
        </android.support.design.widget.TextInputLayout>

        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <EditText
                android:id="@+id/edit_re_pass"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/re_password"
                android:inputType="textPassword"
                android:textColor="@color/accent" />
        </android.support.design.widget.TextInputLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:orientation="horizontal">

            <Button
                android:id="@+id/btn_register"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:foreground="?android:attr/selectableItemBackground"
                android:text="@string/register" />

            <Button
                android:id="@+id/btn_reset"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:foreground="?android:attr/selectableItemBackground"
                android:text="@string/reset" />
        </LinearLayout>
    </LinearLayout>

</RelativeLayout>

Activity Add Lover

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

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

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_below="@+id/toolbar"
        android:orientation="vertical"
        android:padding="10dp">

        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <EditText
                android:id="@+id/edit_name"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/name"
                android:textColor="@color/accent" />
        </android.support.design.widget.TextInputLayout>

        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <EditText
                android:id="@+id/edit_phone"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/phone"
                android:textColor="@color/accent" />
        </android.support.design.widget.TextInputLayout>


        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:orientation="horizontal">

            <Button
                android:id="@+id/btn_begin_date"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:foreground="?android:attr/selectableItemBackground"
                android:text="@string/begin_date" />

            <Button
                android:id="@+id/btn_end_date"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:foreground="?android:attr/selectableItemBackground"
                android:text="@string/end_date" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:orientation="horizontal">

            <Button
                android:id="@+id/btn_add"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:foreground="?android:attr/selectableItemBackground"
                android:text="@string/add" />

            <Button
                android:id="@+id/btn_reset"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:foreground="?android:attr/selectableItemBackground"
                android:text="@string/reset" />
        </LinearLayout>
    </LinearLayout>

</RelativeLayout>

Activity Main – List Old Lover

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <include layout="@layout/toolbar" />

    <LinearLayout
        android:id="@+id/layout_progress"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/toolbar"
        android:gravity="center"
        android:orientation="vertical">

        <ProgressBar
            android:id="@+id/progress"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/tv_notify"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center" />
    </LinearLayout>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_lover"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/layout_progress"
        android:scrollbars="vertical" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab_add"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:layout_gravity="center"
        android:layout_marginBottom="16dp"
        android:layout_marginRight="16dp"
        android:src="@drawable/ic_add"
        app:borderWidth="0dp"
        app:elevation="6dp"
        app:pressedTranslationZ="12dp" />

</RelativeLayout>

Trong Activity này chúng ta có 1 layout là layout_progress, nó chứa 1 ProgressBar để hiển thị “xoay xoay” khi load dữ liệu từ web về, 1 TextView để thông báo lỗi nếu có lỗi. Sau khi load dữ liệu xong, nếu không có lỗi chúng sẽ ẩn đi.

Ngoài ra trong Activity này chúng ta cần các item cho RecyclerView và 2 menu là logutrefresh

File res/layout/item.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/item_container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="5dp"
    android:layout_marginLeft="8dp"
    android:layout_marginRight="8dp"
    android:layout_marginTop="5dp"
    android:foreground="?android:attr/selectableItemBackground"
    android:orientation="vertical"
    card_view:cardCornerRadius="2dp"
    card_view:cardElevation="@dimen/cardview_default_elevation">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="?attr/listPreferredItemHeight"
        android:gravity="center_vertical"
        android:orientation="vertical"
        android:paddingBottom="8dp"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="8dp">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/tv_name"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_toLeftOf="@+id/tv_begin_date"
                android:text="@string/name"
                android:textColor="@color/primary_text_default_material_light"
                android:textSize="@dimen/abc_text_size_subhead_material" />

            <TextView
                android:id="@+id/tv_begin_date"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:paddingTop="3dp"
                android:text="@string/begin_date"
                android:textColor="@color/secondary_text_default_material_light"
                android:textSize="@dimen/abc_text_size_caption_material" />
        </RelativeLayout>

        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/tv_phone"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_toLeftOf="@+id/tv_end_date"
                android:paddingTop="3dp"
                android:text="@string/phone"
                android:textColor="@color/secondary_text_default_material_light"
                android:textSize="@dimen/abc_text_size_caption_material" />

            <TextView
                android:id="@+id/tv_end_date"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:paddingTop="3dp"
                android:text="@string/end_date"
                android:textColor="@color/secondary_text_default_material_light"
                android:textSize="@dimen/abc_text_size_caption_material" />
        </RelativeLayout>
    </LinearLayout>

</android.support.v7.widget.CardView>

File res/menu/menu_main.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainActivity">

    <item
        android:id="@+id/action_logout"
        android:icon="@drawable/ic_logout"
        android:orderInCategory="100"
        android:title="@string/logout"
        app:showAsAction="always" />

    <item
        android:id="@+id/action_refresh"
        android:icon="@drawable/ic_refresh"
        android:orderInCategory="100"
        android:title="@string/refresh"
        app:showAsAction="always" />

</menu>

Vậy là việc thiết kế giao diện đã xong. Trong phần tiếp theo chúng ta sẽ xử lý code java hoàn thiện ứng dụng.

Bài viết được thực hiện trong loạt bài hướng dẫn JSon trong Android bởi nguyenvanquan7826