October 21, 2021
Google Material Design

Thiết kế Layout profile theo Material Design

Material Design là phong cách thiết kế được Google tung ra cùng lúc với Android 5.0 Lollipop. Phong cách thiết kết của Material Design là các lớp nội dụng được xếp chồng lên nhau. Sử dụng những tông màu đập với độ tương phản hài hòa kèm theo theo các chuyển động tự nhiên của nút, menu… tạo cho người dùng một trải nghiệm mới mẻ và thật hơn.

Để sử dụng được Coordinatorlayout bạn cần import thư viện
android.support:design
bằng cách thêm vào file build.gradle như sau:

Để sử dụng được Coordinatorlayout bạn cần  import thư viện
android.support:design
bằng cách thêm vào file build.gradle  như sau:

Bay giờ mình sẽ tạo 1 project với giao diện profile giống Zalo:
File activity_mai.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="265dp"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="265dp"
            android:fitsSystemWindows="true"
            app:contentScrim="@color/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
            <ImageView
                android:id="@+id/imgProfileCover"
                android:layout_width="match_parent"
                android:layout_height="265dp"
                android:scaleType="centerCrop"
                app:layout_collapseMode="parallax"
                app:layout_collapseParallaxMultiplier="0.7" />
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="265dp"
                android:alpha="0.3"
                android:background="@color/black_semi_transparent"
                app:layout_collapseMode="parallax"
                app:layout_collapseParallaxMultiplier="0.7"/>

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                app:contentInsetLeft="0dp"
                app:contentInsetStart="0dp">

                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:orientation="horizontal">

                    <LinearLayout
                        android:id="@+id/lnBack"
                        android:layout_width="40dp"
                        android:layout_height="40dp"
                        android:gravity="center"
                        android:layout_centerInParent="true"
                        android:layout_alignParentLeft="true"
                        android:background="@drawable/bg_oval_tranparent_grey">

                        <ImageView
                            android:layout_width="15dp"
                            android:layout_height="15dp"
                            android:layout_gravity="center"
                            android:src="@mipmap/ic_arrow_left" />
                    </LinearLayout> <!-- back -->

                    <de.hdodenhof.circleimageview.CircleImageView
                        android:id="@+id/imgAvatarSmall"
                        android:layout_width="40dp"
                        android:layout_height="45dp"
                        android:layout_marginLeft="50dp"
                        app:civ_border_width="1dp"
                        app:civ_border_color="#ffffff"
                        android:visibility="gone"
                        android:layout_centerVertical="true"/>
                    <TextView
                        android:id="@+id/tvDisplayNameSmall"
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:layout_centerVertical="true"
                        android:layout_marginLeft="105dp"
                        android:layout_gravity="top|left"
                        android:text="Tín Lượng"
                        android:gravity="center"
                        android:visibility="gone"
                        android:textSize="18sp"
                        android:textColor="#ffffff" />



                </RelativeLayout>
            </android.support.v7.widget.Toolbar>

        </android.support.design.widget.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>


    <android.support.v4.widget.NestedScrollView
        android:id="@+id/nested_scroll_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="8dp"
                android:text="@string/description"/>
        </LinearLayout>

    </android.support.v4.widget.NestedScrollView>

    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/imgAvatar"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_gravity="top|left"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="150dp"
        app:civ_border_width="1dp"
        app:civ_border_color="#ffffff"
        app:finalHeight="40dp"
        app:finalXPosition="50dp"
        app:finalYPosition="8dp"
        app:finalToolbarHeight="?attr/actionBarSize"
        app:layout_behavior="com.tinluong.profilezalo.widget.AvatarImageBehavior" />

    <TextView
        android:id="@+id/tvDisplayName"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:layout_gravity="top|left"
        android:gravity="center"
        android:layout_marginLeft="95dp"
        android:layout_marginTop="165dp"
        app:finalHeight="40dp"
        app:finalXPosition="105dp"
        app:finalYPosition="8dp"
        android:textColor="#ffffff"
        android:textSize="20sp"
        app:finalToolbarHeight="?attr/actionBarSize"
        app:layout_behavior="com.tinluong.profilezalo.widget.NameBehavior"/>

</android.support.design.widget.CoordinatorLayout>

Ở đây mình tạo 2 class ImageAvatarBehavior và NameBehavior. Hai class này kế thừa từ Coordinatorlayout.Behavior cho phép mình tùy chỉnh kích thước, canh trái, phải… khi mình scroll layout chính.

Một điểm khác biệt của Material Design là sử dụng Toolbar để thay thế cho ActionBar. Nên trong file style.xml bạn phải sử dụng như sau:

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
</style>

Trong Class MainActivity.java bạn phải overrite hàm onOffsetChanged để hiển thị avatar và name trên thanh toolbar khi AppBarlayout ẩn.

@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
if (scrollRange == -1) {
   scrollRange = appBarLayout.getTotalScrollRange();
}
if (scrollRange + verticalOffset==0) {
   isShow = true;
   imgAvatarSmall.setVisibility(View.VISIBLE);
   tvDisplayNameSmall.setVisibility(View.VISIBLE);

} else if (isShow) {
   isShow = false;
   imgAvatarSmall.setVisibility(View.GONE);
   tvDisplayNameSmall.setVisibility(View.GONE);
}

     }

Một vài điều bạn cần nắm để có thể sử dụng tốt layout của thư viện

android.support:design

AppBarLayout

Về cơ bản thì nó là một LinearLayout theo chiều dọc, nó nhận nhiệm vụ bắt các sự kiện scroll của các thẻ con bên trong nó.
Nhờ có AppBarLayout mà CollapsingToolbarLayout có thể scroll mượt mà.

CollapsingToolbarLayout

Làm nhiệm vụ bao bọc lấy thanh Toolbar, implement Collapsing App Bar.
Một số flag trong CollapsingToolbarLayout mà các bạn cần lưu ý để thiết kế.

  • layout_scrollFlags
    • scroll:
      • Tất cả những view nào muốn có thể scroll được đều phải add thẻ này. nếu không có thì view đó sẽ bị ghim vào trên đầu layout và không thể scroll.
    • enterAlways:
      • Cho phép hiển thị ngay khi người dùng scroll xuống mà k cần phải kéo hết toàn bộ layout, cho phép hiển thị layout nhanh chóng.
  • exitUntilCollapsed:
    • Cho phép luôn luôn hiển thị view của bạn cho đến khi các bạn scroll đến height = minHeight

Hi vọng sau bài viết này bạn có thể tự thiết kế cho mình 1 layout profile Material Design đẹp, mang lại trải nghiệm thực hơn cho người dùng.

Các bạn có thể download project mẫu của mình để có thể tham khảo ProfileZalo.zip.

Pham Van Tuyen

Anh Tuyen Pham là Tổng giám đốc của Cloud Ace Việt Nam và là GDG Cloud HCM Chapter Lead. Anh là diễn giả quen thuộc tại các sự kiện do Google tổ chức tại Việt Nam như Kubernetes Vietnam, Google Cloud Next Extended. Anh đã có các chứng chỉ của Google Cloud như Google Cloud Architect và Data Engineer.

View all posts by Pham Van Tuyen →