Trang chủHướng dẫnTạo giao diện sáng-tối bằng cách tích hợp theme DayNight trong Android
Chuyên gia

Tạo giao diện sáng-tối bằng cách tích hợp theme DayNight trong Android

CyStack blog 6 phút để đọc
CyStack blog04/08/2025
Locker Avatar

Ngoc Vo

Marketing Executive @CyStack
Locker logo social
Reading Time: 6 minutes

Trong bài hướng dẫn này, chúng ta sẽ cùng tìm hiểu và sử dụng theme DayNight trong ứng dụng Android. Nó có tác dụng kích hoạt chế độ ban đêm (night mode), rất hữu ích để làm dịu mắt người dùng khi bạn có một ứng dụng chứa nhiều nội dung văn bản.

tích hợp theme DayNight trong Android

Tích hợp theme DayNight trong Android

Android đã phát hành theme DayNight trong thư viện hỗ trợ phiên bản 23.2.0. Nhờ theme này, chúng ta có thể dễ dàng chuyển đổi qua lại giữa chế độ sáng (light mode) và tối (dark mode) cho ứng dụng. Ta có thể thực hiện việc này một cách thủ công hoặc để Android tự động phát hiện thời gian trong ngày ngay trên điện thoại.

Theme này giúp cải thiện khả năng đọc và sử dụng của ứng dụng vào ban đêm bằng cách thay thế nền trắng sáng bằng một nền tối hơn. Nhiều ứng dụng reader đã triển khai theme này.

Để bắt đầu, chúng ta hãy tạo một dự án Android Studio mới với một activity trống.

Thêm theme vào styles.xml

Hãy thay thế theme hiện tại trong ứng dụng của chúng ta bằng theme DayNight.

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

Để thiết lập theme DayNight trong ứng dụng, ta sử dụng phương thức AppCompatDelegate.setDefaultNightMode(). Dưới đây là các tham số được phép sử dụng trong phương thức trên.

  • MODE_NIGHT_YES – Bật night mode thủ công.
  • MODE_NIGHT_NO – Tắt night mode thủ công.
  • MODE_NIGHT_FOLLOW_SYSTEM – Sử dụng cài đặt của hệ thống để xác định thời gian trong ngày và bật/tắt NightMode tương ứng. Đây là tham số mặc định.
  • MODE_NIGHT_AUTO – Tham số này sẽ cố gắng tự động phát hiện thời gian từ API vị trí của thiết bị. Nếu quyền truy cập dịch vụ vị trí không được cấp, nó sẽ sử dụng thời gian hệ thống.

Thêm đoạn mã sau vào phương thức onCreate().

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); //For night mode theme
        //AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); //For day mode theme
        setContentView(R.layout.activity_main);
    }

Theme phải luôn được thiết lập trước khi phương thức setContentView() được gọi.

AppCompatDelegate là gì?

AppCompatDelegate là một class đóng vai trò delegate (ủy quyền), cho phép bạn mở rộng các tính năng hỗ trợ của AppCompat cho bất kỳ activity nào. Hãy cùng xem màn hình activity của chúng ta trông như thế nào trong chế độ ban ngày và ban đêm.

Theme sáng của ứng dụng

Theme tối của ứng dụng

TextView sẽ đổi màu chữ thành trắng ở night mode. Lý do là vì TextView ngầm chứa style mặc định có tên ?attr/colorPrimary, có chức năng tự động chuyển đổi màu sắc dựa trên theme sáng/tối của ứng dụng. Nếu bạn đặt một màu tùy chỉnh như @color/red cho TextView, màu này sẽ không thay đổi giữa hai chế độ. Màu chữ của Toolbar ở chế độ ban ngày là màu đen. Vậy làm thế nào để đổi màu chữ của Toolbar thành trắng ngay trong styles.xml?

<style name="AppTheme" parent="Theme.AppCompat.DayNight">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:textColorPrimary">@android:color/white</item>
        <item name="android:textColorSecondary">@android:color/white</item>
    </style>

Để lấy ra loại night mode hiện tại, ta dùng phương thức AppCompatDelegate.getDefaultNightMode(). Phương thức này trả về một số nguyên tương ứng với mỗi loại đã đề cập ở trên.

Sau khi đã hiểu cách hoạt động cơ bản, chúng ta hãy cùng tạo một ứng dụng có các chức năng sau:

  • Tùy chỉnh resource và style trong chế độ ngày/đêm.
  • Chuyển đổi theme DayNight từ giao diện người dùng.
  • Xem các widget giao diện người dùng khác nhau trông như thế nào trong Night Mode.

Cấu trúc dự án Android có night mode

Cấu trúc ứng dụng tích hợp theme DayNight trong Android

Ví dụ về code cho Android sử dụng theme DayNight

Dưới đây là code cho file class activity_main.xml.

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

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_margin="@android:dimen/app_icon_size"
        android:text="Welcome to this tutorial."
        android:textColor="@color/daynight_textColor"
        android:textSize="18sp" />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="250dp"
        android:layout_height="250dp"
        android:layout_centerInParent="true"
        android:src="@drawable/placeholder" />

    <TextView
        android:id="@+id/txtNightMode"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/switchCompat"
        android:layout_centerHorizontal="true"
        android:paddingRight="8dp"
        android:text="Night Mode"
        android:textColor="@color/daynight_textColor" />

    <android.support.v7.widget.SwitchCompat
        android:id="@+id/switchCompat"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="@android:dimen/app_icon_size"
        android:layout_toRightOf="@+id/txtNightMode"
        android:checked="false"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/imageView"
        android:layout_alignLeft="@+id/txtNightMode"
        android:layout_alignStart="@+id/txtNightMode"
        android:text="CLICK ME"
        android:textColor="@color/daynight_textColor" />
</RelativeLayout>
  • Chúng ta đã đặt một màu chữ và một drawable tùy chỉnh cho ImageView.
  • Để thiết lập các màu sắc và drawable khác nhau cho theme ban ngày và ban đêm, ta cần tạo các thư mục riêng cho tài nguyên.
  • Tài nguyên cho theme ban ngày nằm trong thư mục mặc định.
  • Tài nguyên cho theme ban đêm nằm trong các thư mục có hậu tố -night.
  • Vì vậy, chúng ta đã tạo các thư mục values-nightdrawable-night trong dự án.
  • Tên file drawable, tên màu, và tên style phải giống hệt nhau trong cả hai thư mục đối với những tài nguyên mà bạn muốn chuyển đổi trong theme DayNight.
  • Nếu các tài nguyên trên chỉ được định nghĩa ở một trong hai thư mục, chúng sẽ được sử dụng chung cho cả theme ban ngày và ban đêm.

Code cho styles.xml trong thư mục valuesvalues-night như sau:

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.DayNight">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:textColorPrimary">@android:color/white</item>
    </style>

    <style name="MyDialog" parent="Theme.AppCompat.Light.Dialog.Alert"/>

    <style name="MySwitch">
        <item name="colorControlActivated">@color/switchColor</item>
    </style>
</resources>
<resources>
    <!-- Base application theme. values-night.xml -->
    <style name="AppTheme" parent="Theme.AppCompat.DayNight">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/orange</item>
        <item name="colorPrimaryDark">@color/orangeDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:textColorPrimary">@android:color/white</item>
    </style>

    <style name="MyDialog" parent="Theme.AppCompat.DayNight.Dialog.Alert"/>

    <style name="MySwitch">
        <item name="colorControlActivated">@color/switchColor</item>
    </style>
</resources>

Các style được định nghĩa ở trên được dùng để tùy chỉnh theme DayNight chuẩn. Các định nghĩa tương ứng cho colors.xml được trình bày như sau.

Code tích hợp theme DayNight trong Android

Code tích hợp theme DayNight trong Android

Dưới đây là code cho class MainActivity.java.

package com.journaldev.daynightmode;

import android.content.Intent;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.app.AppCompatDelegate;
import android.support.v7.widget.SwitchCompat;
import android.view.View;
import android.widget.Button;
import android.widget.CompoundButton;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (InitApplication.getInstance().isNightModeEnabled()) {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
        } else {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
        }
        setContentView(R.layout.activity_main);

        SwitchCompat switchCompat = findViewById(R.id.switchCompat);
        Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new AlertDialog.Builder(MainActivity.this, R.style.MyDialog)
                        .setTitle("Title")
                        .setMessage("Message")
                        .show();
            }
        });

        if (AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES)
            switchCompat.setChecked(true);

        switchCompat.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {
                    InitApplication.getInstance().setIsNightModeEnabled(true);
                    Intent intent = getIntent();
                    intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
                    finish();
                    startActivity(intent);

                } else {
                    InitApplication.getInstance().setIsNightModeEnabled(false);
                    Intent intent = getIntent();
                    intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
                    finish();
                    startActivity(intent);
                }

            }
        });

    }
}

Trong đoạn code trên, ta sử dụng Switch để chuyển đổi giữa theme ban ngày và ban đêm trong ứng dụng. Chế độ hiện tại sẽ được lưu vào một đối tượng SharedPreferences. Chúng ta cần làm vậy vì theme của một activity chỉ có thể được thiết lập một lần duy nhất. Do đó, khi Switch được gạt, ta cần lưu chế độ mới vào một đối tượng SharedPreferences.

Ta sử dụng Singleton pattern cho class Application. Bằng cách này, cùng một thực thể của class Application có thể được sử dụng xuyên suốt ứng dụng.

Dưới đây là code cho class InitApplication.java.

package com.journaldev.daynightmode;

import android.app.Application;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;

public class InitApplication extends Application {
    public static final String NIGHT_MODE = "NIGHT_MODE";
    private boolean isNightModeEnabled = false;

    private static InitApplication singleton = null;

    public static InitApplication getInstance() {

        if(singleton == null)
        {
            singleton = new InitApplication();
        }
        return singleton;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        singleton = this;
        SharedPreferences mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
        this.isNightModeEnabled = mPrefs.getBoolean(NIGHT_MODE, false);
    }

    public boolean isNightModeEnabled() {
        return isNightModeEnabled;
    }

    public void setIsNightModeEnabled(boolean isNightModeEnabled) {
        this.isNightModeEnabled = isNightModeEnabled;

        SharedPreferences mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
        SharedPreferences.Editor editor = mPrefs.edit();
        editor.putBoolean(NIGHT_MODE, isNightModeEnabled);
        editor.apply();
    }
}

Đây là nơi chúng ta cập nhật và lấy ra loại night mode từ SharedPreferences.

Giao diện ứng dụng Android hỗ trợ night mode

Ứng dụng tích hợp theme DayNight trong Android

Tổng kết

Đó là tất cả những gì bạn cần biết để bắt đầu sử dụng theme DayNight trong ứng dụng Android của mình để hỗ trợ chuyển đổi giao diện sáng-tối. Bạn có thể tải về toàn bộ dự án ví dụ ở trên từ đường dẫn này.

0 Bình luận

Đăng nhập để thảo luận

Chuyên mục Hướng dẫn

Tổng hợp các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.

Đăng ký nhận Newsletter

Nhận các nội dung hữu ích mới nhất