Thiết Kế Giao Diện Ứng Dụng Android với Android Material

Bạn có thể đã nghe nhiều về Android Material Design . Nó được giới thiệu trong phiên bản Android Lollipop .
Trong Android Material Design có rất nhiều thứ mới mà đã được giới thiệu như Material Theme New Widgets,Custom Shadows, Vector drawbles, Custom Animations.
Nếu bạn chưa từng làm việc với Android Material Design thì có lẽ bài viết này sẽ là sự khởi đầu tốt cho bạn. Trong bài viết này tôi sẽ giới thiệu những bước cơ bản nhất của Android Material Design. Những link bên dưới có thể giúp bạn hiểu hơn về Material Design.

Material Design Color Customization

Material Design cung cấp một bộ những thuộc tính cho việc tuỳ chỉnh Material Design Color Theme. Nhưng chúng ta chỉ sử dụng 5 thuộc tính chính trong việc tuỳ chỉnh tất cả các Theme.

  • colorPrimaryDark đây là màu cơ bản nhất của ứng dụng, chủ yếu được áp dụng cho background của notification bar.
  • colorPrimary đây là màu chính của app , màu này sẽ được áp như là toolbar background.
  • textColorPrimary đây là màu chính của text, thường áp dụng cho title của toolbar.
  • windowBackground đây là màu background mặc định của app.
  • navigationBarColor định nghĩ màu background của footer navigation bar.

Bạn có thể chọn cho ứng dụng của mình một bộ thuộc tính màu sắc mà bạn yêu thích tại đây

Creating Material Design Theme

  • Trong Android sau khi bạn đã tạo một new project.
  • Bước tiếp theo bạn cần làm là mở res ⇒ values ⇒ strings.xml và thêm những giá trị bên dưới.
<resources>
<string name="app_name">Material Design</string>
<string name="action_settings">Settings</string>
<string name="action_search">Search</string>
<string name="drawer_open">Open</string>
<string name="drawer_close">Close</string>
 
<string name="nav_item_home">Home</string>
<string name="nav_item_friends">Friends</string>
<string name="nav_item_notifications">Messages</string>
 
<!-- navigation drawer item labels  -->
<string-array name="nav_drawer_labels">
    <item>@string/nav_item_home</item>
    <item>@string/nav_item_friends</item>
    <item>@string/nav_item_notifications</item>
</string-array>
 
<string name="title_messages">Messages</string>
<string name="title_friends">Friends</string>
<string name="title_home">Home</string>
</resources>

Mở res ⇒ values ⇒ colors.xml và thêm những giá trị color .Nếu bạn không tìm thấy file colors.xml thì bạn hãy tạo 1 file mới với cùng tên.

<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#F50057</color>
<color name="colorPrimaryDark">#C51162</color>
<color name="textColorPrimary">#FFFFFF</color>
<color name="windowBackground">#FFFFFF</color>
<color name="navigationBarColor">#000000</color>
<color name="colorAccent">#FF80AB</color>
</resources>
  • Mở res ⇒ values ⇒ dimens.xml và thêm những giá trị bên dưới.
<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
    <dimen name="nav_drawer_width">260dp</dimen>
</resources>
  • Mở styles.xml bên dưới res ⇒ values và thêm những giá trị styles bên dưới.
<resources>
 
    <style name="MyMaterialTheme" parent="MyMaterialTheme.Base">
 
    </style>
 
    <style name="MyMaterialTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
 
</resources>
  • Bây giờ bên dưới res tạo một folder values-v21. Bên trong folder này tạo một file styleskhác với giá trị như bên dưới. Những styles này được áp dụng duy nhất tới Android Lollipop.
<resources>
 
    <style name="MyMaterialTheme" parent="MyMaterialTheme.Base">
        <item name="android:windowContentTransitions">true</item>
        <item name="android:windowAllowEnterTransitionOverlap">true</item>
        <item name="android:windowAllowReturnTransitionOverlap">true</item>
        <item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
        <item name="android:windowSharedElementExitTransition">@android:transition/move</item>
    </style>
 
</resources>
  • Bây giờ chúng ta đã có một Material Design Styles đơn giản . Để áp dụng tới Theme mởAndroidManifest.xml và chỉnh sửa lại thuộc tính của Tag <application>android:theme="@style/MyMaterialTheme" Sau khi áp dụng ThemeAndroidManifest.xml sẽ trông giống như bên dưới:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="info.androidhive.materialdesign" >
 
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/MyMaterialTheme" >
        <activity
            android:name=".activity.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
 </manifest>

Bây giờ nếu bạn chạy project, bạn sẽ nhìn thấy color của notification bar thay đổi theo màu sắc chúng ta đã đề cập styles trên.

Adding the Toolbar (Action Bar)

Việc adding toolbar là rất dễ dàng. Tất cả những gì bạn cần làm là tạo ra 1 file layout riêng, và thêm vào file layout đó những thành phần bạn muốn hiển thị trên toolbar.

  • Tạo 1 file layout có tên là toolbar.xml dưới folder res ⇒ layout và thêm thành phầnandroid.support.v7.widget.Toolbar. Bên dưới chúng ta sẽ tạo toolbar với chiều cao và theme xác định.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    local:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    local:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
  • Mở file layout của Activity MainActivity.class và add toolbar bằng cách sử dụng tag <include> như bên dưới .
activity_main.xml
<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"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:orientation="vertical">

        <include
            android:id="@+id/toolbar"
            layout="@layout/toolbar" />
    </LinearLayout>

</RelativeLayout>

  • Download icon search và import nó vào trong android studio như một Image Asset
  • Import một Image Asset vào trong Android Studio : click chuột phải trên res ⇒ New ⇒ Image Asset. Nó sẽ hiển thị một bạn 1 cửa sổ popup để import resource. Browse tới icon search mà bạn đã download về trước đó. Lựa chọn Action Bar and Tab Icons cho Asset Type và resouce name là ic_search_action .
  • Khi icon đã được import, mở menu_main.xml được đặt res ⇒ menu và thêm menu item search như bên dưới .
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_search"
        android:title="@string/action_search"
        android:orderInCategory="100"
        android:icon="@drawable/ic_action_search"
        app:showAsAction="ifRoom" />

    <item
        android:id="@+id/action_settings"
        android:title="@string/action_settings"
        android:orderInCategory="100"
        app:showAsAction="never" />
</menu>
  • Bây giờ mở MainActivity.java và thêm những thay đổi.
public class MainActivity extends AppCompatActivity {
 
    private Toolbar mToolbar;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        mToolbar = (Toolbar) findViewById(R.id.toolbar);
 
        setSupportActionBar(mToolbar);
        getSupportActionBar().setDisplayShowHomeEnabled(true);
    }
 
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }
 
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
 
        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }
 
        return super.onOptionsItemSelected(item);
    }
}

Bây giờ bạn chạy ứng dụng bạn sẽ nhìn thấy kết quả như bên dưới:

Adding Navigation Drawer

Việc thêm Navigation Drawer tương tự như những cái chúng ta đã làm trước lollipop nhưng thay vì sử dụng ListView Chúng ta sử dụng RecyclerView trong material design. Vậy chúng ta hãy cùng tìm hiểu làm thế nào để xây dựng navigation drawer với recyclerview.

  • Trong project tạo 3 package name tương ứng là activities, adapter, model . Điều này sẽ làm cho bố cục tổ chức project của chúng ta thêm rõ ràng hơn.
  • Mở build.gradle và thêm dependencies. Sau đó Build ⇒ Rebuild Project.
compile 'com.android.support:appcompat-v7:22.2.0'
compile 'com.android.support:recyclerview-v7:22.2.+'
  • Dưới package modle tạo một class tên là NavDrawerItem.java. Class này định nghĩ các item trong navigation drawer
public class NavDrawerItem {
    private boolean showNotify;
    private String title;

    public NavDrawerItem() {

    }

    public NavDrawerItem(boolean showNotify, String title) {
        this.showNotify = showNotify;
        this.title = title;
    }

    public boolean isShowNotify() {
        return showNotify;
    }

    public void setShowNotify(boolean showNotify) {
        this.showNotify = showNotify;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}

Bên dưới res ⇒ layout Tạo một file layout tên nav_drawer_row.xml và thêm code như bên dưới. Đây là file layout cho mỗi item trong navigation drawer.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true">

<TextView
    android:id="@+id/title"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:paddingLeft="30dp"
    android:paddingTop="10dp"
    android:paddingBottom="10dp"
    android:textSize="15dp"
    android:textStyle="bold" />
</RelativeLayout>
  • Tạo một file layout khác tên là fragment_navigation_drawer.xml và thêm code như bên dưới. Layout này thể hiện toàn bộ phần view của navigation drawer. Trong layout này có chứa phần header thể hiện thông tin người dùng và recyclerview thể hiện cái item .
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white">

    <RelativeLayout
        android:id="@+id/nav_header_container"
        android:layout_width="match_parent"
        android:layout_height="140dp"
        android:layout_alignParentTop="true"
        android:background="@color/colorPrimary">

        <ImageView
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:src="@drawable/ic_profile"
            android:scaleType="fitCenter"
            android:layout_centerInParent="true" />

    </RelativeLayout>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/drawerList"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/nav_header_container"
        android:layout_marginTop="15dp" />

</RelativeLayout>
  • RecyclerView là một customview ,vì vậy chúng ta cần 1 Adapter. Do đó bên dưới package name adapter chúng ta tạo một class NavigationDrawerAdapter.java và thêm những phần code như bên dưới.
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.Collections;
import java.util.List;

public class NavigationDrawerAdapter extends RecyclerView.Adapter<NavigationDrawerAdapter.MyViewHolder> {
    List<NavDrawerItem> data = Collections.emptyList();
    private LayoutInflater inflater;
    private Context context;

    public NavigationDrawerAdapter(Context context, List<NavDrawerItem> data) {
        this.context = context;
        inflater = LayoutInflater.from(context);
        this.data = data;
    }

    public void delete(int position) {
        data.remove(position);
        notifyItemRemoved(position);
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = inflater.inflate(R.layout.nav_drawer_row, parent, false);
        MyViewHolder holder = new MyViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        NavDrawerItem current = data.get(position);
        holder.title.setText(current.getTitle());
    }

    @Override
    public int getItemCount() {
        return data.size();
    }

    class MyViewHolder extends RecyclerView.ViewHolder {
        TextView title;

        public MyViewHolder(View itemView) {
            super(itemView);
            title = (TextView) itemView.findViewById(R.id.title);
        }
    }
}
  • Bên dưới package activities, tạo một fragment có tên FragmentDrawer.java. Trong Android Studio, tạo một fragment mới, click chuột phải activitie ⇒ New ⇒ Fragment ⇒ Fragment (Blank) và bận nhâp tên framgent bạn muốn.

Implementing Navigation Drawer Item Selection

Trong ví dụ này chúng ta đã tạo ra 3 item trong navigation drawer (Home, Friend, Message) do đó chúng ta cần tạo ra 3 fragment riêng biệt tương ứng.

  • Chúng ta tạo 1 file layout có tên là fragment_home.xml và add code như bên dưới:
<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"
    tools:context="info.androidhive.materialdesign.activity.HomeFragment">

    <TextView
        android:id="@+id/label"
        android:layout_alignParentTop="true"
        android:layout_marginTop="100dp"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:textSize="45dp"
        android:text="HOME"
        android:textStyle="bold"/>

    <TextView
        android:layout_below="@id/label"
        android:layout_centerInParent="true"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="12dp"
        android:layout_marginTop="10dp"
        android:gravity="center_horizontal"
        android:text="Edit fragment_home.xml to change the appearance" />

</RelativeLayout>
  • Chúng ta cũng tạo một fragment có tên là HomeFragment.java như bên dưới:
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class HomeFragment extends Fragment {

    public HomeFragment() {
        // Required empty public constructor
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_home, container, false);

        // Inflate the layout for this fragment
        return rootView;
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
    }

    @Override
    public void onDetach() {
        super.onDetach();
    }
}
  • Tương tự như trên chúng ta tạo 2 fragment FriendsFragment.java, MessagesFragment.java và những file layout tương ứng fragment_friends.xml and fragment_messages.xml
  • Bây giờ chúng ta mở lại MainActivity.java và thêm một số thay đổi. Phương thứcdisplayView() sẽ hiển thị những fragment tương ứng với navigation menu item được chọn.
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity implements FragmentDrawer.FragmentDrawerListener {

    private static String TAG = MainActivity.class.getSimpleName();

    private Toolbar mToolbar;
    private FragmentDrawer drawerFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mToolbar = (Toolbar) findViewById(R.id.toolbar);

        setSupportActionBar(mToolbar);
        getSupportActionBar().setDisplayShowHomeEnabled(true);

        drawerFragment = (FragmentDrawer)
                getSupportFragmentManager().findFragmentById(R.id.fragment_navigation_drawer);
        drawerFragment.setUp(R.id.fragment_navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), mToolbar);
        drawerFragment.setDrawerListener(this);

        // display the first navigation drawer view on app launch
        displayView(0);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        if(id == R.id.action_search){
            Toast.makeText(getApplicationContext(), "Search action is selected!", Toast.LENGTH_SHORT).show();
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onDrawerItemSelected(View view, int position) {
            displayView(position);
    }

    private void displayView(int position) {
        Fragment fragment = null;
        String title = getString(R.string.app_name);
        switch (position) {
            case 0:
                fragment = new HomeFragment();
                title = getString(R.string.title_home);
                break;
            case 1:
                fragment = new FriendsFragment();
                title = getString(R.string.title_friends);
                break;
            case 2:
                fragment = new MessagesFragment();
                title = getString(R.string.title_messages);
                break;
            default:
                break;
        }

        if (fragment != null) {
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            fragmentTransaction.replace(R.id.container_body, fragment);
            fragmentTransaction.commit();

            // set the toolbar title
            getSupportActionBar().setTitle(title);
        }
    }
}

Bây giờ là lúc chúng ta nhìn thấy thành quả bằng cách chạy ứng bạn sẽ nhìn thấy kết quả như bên dưới.

AndroidCoBan via Viblo

Nguyễn Linh

Chia sẻ để cùng tiến bộ...