Giới thiệu
Chiều cao ActionBar/Toolbar thường cần để tính layout, scroll offset, hoặc custom view. Giá trị chuẩn: ?attr/actionBarSize (thường 56dp trên phone, 64dp trên tablet/landscape). Bài viết hướng dẫn lấy giá trị pixel tại runtime và các best practices.
Các cách lấy chiều cao
1. Từ Theme Attribute (Khuyến nghị - Không cần runtime)
Dùng trong XML layout:
<View
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/primary" />
<dimen name="toolbar_height">?attr/actionBarSize</dimen>
2. Từ Toolbar View (Runtime - đã layout)
// Java
Toolbar toolbar = findViewById(R.id.toolbar);
int height = toolbar.getHeight(); // Chỉ > 0 sau onLayout
// Kotlin
val height = binding.toolbar.height
3. Từ Theme/Resources (Runtime - trước khi layout)
// Java
TypedValue tv = new TypedValue();
if (getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)) {
int actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());
}
// Kotlin
val tv = TypedValue()
val actionBarHeight = if (theme.resolveAttribute(R.attr.actionBarSize, tv, true)) {
TypedValue.complexToDimensionPixelSize(tv.data, resources.displayMetrics)
} else 0
4. Từ WindowInsets (Android 11+ / API 30+)
// Lấy system bar insets (status bar + navigation bar + ime)
ViewCompat.setOnApplyWindowInsetsListener(rootView) { view, insets ->
val statusBarHeight = insets.getInsets(WindowInsetsCompat.Type.statusBars()).top
val navigationBarHeight = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom
// Toolbar height thường = actionBarSize, không lấy từ insets
insets
}
Ví dụ hoàn chỉnh
Layout (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:title="My Toolbar"
app:titleTextColor="@android:color/white" />
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="24dp"
android:gravity="center"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<Button
android:id="@+id/btnGetHeight"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Lấy chiều cao Toolbar" />
<TextView
android:id="@+id/tvResult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
MainActivity.kt
package com.example.toolbarheight
import android.os.Bundle
import android.util.TypedValue
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.example.toolbarheight.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.toolbar)
supportActionBar?.setDisplayShowTitleEnabled(true)
binding.btnGetHeight.setOnClickListener { showToolbarHeight() }
}
private fun showToolbarHeight() {
// Cách 1: Từ Toolbar view (cần layout đã xong)
val toolbarHeight = binding.toolbar.height
// Cách 2: Từ theme attribute (luôn đúng, không cần layout)
val tv = TypedValue()
val themeHeight = if (theme.resolveAttribute(R.attr.actionBarSize, tv, true)) {
TypedValue.complexToDimensionPixelSize(tv.data, resources.displayMetrics)
} else 0
// Cách 3: Từ dimens resource (nếu định nghĩa)
val dimenHeight = resources.getDimensionPixelSize(R.dimen.toolbar_height) // Nếu có dimen
binding.tvResult.text = """
Toolbar.getHeight(): $toolbarHeight px
Theme actionBarSize: $themeHeight px
Dimen resource: $dimenHeight px
""".trimIndent()
}
}
ActionBar vs Toolbar
| Đặc điểm | ActionBar (Hệ thống) | Toolbar (Widget) |
|---|---|---|
| Vị trí | Fixed top (window decor) | Bất kỳ đâu trong layout |
| Tùy biến | Hạn chế | Hoàn toàn (View bình thường) |
| Lấy height | Khó (phải query window) | Dễ (toolbar.height) |
| Animation/Collapse | Không | Có (CollapsingToolbarLayout) |
| Khuyến nghị | Không dùng nữa | Dùng Toolbar + NoActionBar theme |
Status Bar & Navigation Bar Height
Thường cần khi làm full-screen, edge-to-edge:
// Status bar height
val statusBarHeight = resources.getDimensionPixelSize(
resources.getIdentifier("status_bar_height", "dimen", "android")
)
// Navigation bar height (API 30+)
val navBarHeight = WindowInsetsCompat.getInsets(rootView, WindowInsetsCompat.Type.navigationBars()).bottom
// Hoặc dùng InsetsListener (API 30+)
ViewCompat.setOnApplyWindowInsetsListener(rootView) { view, insets ->
val statusBar = insets.getInsets(WindowInsetsCompat.Type.statusBars()).top
val navBar = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom
// Cập nhật padding/margin cho view
insets
}
Edge-to-Edge (Android 15+ / API 35)
Từ Android 15, app mặc định edge-to-edge. Toolbar cần handle insets:
// Theme
// Layout - Toolbar với top padding = status bar height
Lưu ý quan trọng
toolbar.getHeight()trả về 0 nếu gọi trongonCreate()(chưa layout). DùngdoOnLayout { }hoặcpost { }.?attr/actionBarSizelà giá trị chuẩn từ theme - luôn đúng, không cần runtime.- Trên tablet/landscape: actionBarSize có thể = 64dp.
- Custom Toolbar height: Override trong theme
.- 72dp
- Khi dùng
CollapsingToolbarLayout, height thay đổi khi scroll - lắng ngheOnOffsetChangedListener.