Giới thiệu
Kết hợp ConstraintLayout làm item layout cho RecyclerView cho phép thiết kế giao diện phức tạp, responsive, flat hierarchy (ít nested view) - hiệu suất tốt hơn.
Các bước thực hiện
Bước 1: Dependency (build.gradle)
dependencies {
implementation "androidx.recyclerview:recyclerview:1.3.0"
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
implementation "com.google.android.material:material:1.9.0"
}
Bước 2: Giao diện chính (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:layout_scrollFlags="scroll|enterAlways"
app:title="ConstraintLayout + RecyclerView" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Bước 3: Item Layout - ConstraintLayout (res/layout/item_constraint.xml)
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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="wrap_content"
android:padding="16dp"
android:background="?android:attr/selectableItemBackground">
<ImageView
android:id="@+id/ivAvatar"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:src="@mipmap/ic_launcher"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<TextView
android:id="@+id/tvTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:text="Title"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintStart_toEndOf="@id/ivAvatar"
app:layout_constraintTop_toTopOf="@id/ivAvatar"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="@+id/tvSubtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:text="Subtitle description"
android:textSize="14sp"
android:textColor="?android:attr/textColorSecondary"
app:layout_constraintStart_toEndOf="@id/ivAvatar"
app:layout_constraintTop_toBottomOf="@id/tvTitle"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="@id/ivAvatar" />
</androidx.constraintlayout.widget.ConstraintLayout>
Bước 4: Adapter (src/ConstraintAdapter.java)
package com.example.myapplication;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
public class ConstraintAdapter extends RecyclerView.Adapter<ConstraintAdapter.ViewHolder> {
private List<String> titles;
private List<String> subtitles;
private OnItemClickListener listener;
public interface OnItemClickListener {
void onItemClick(int position);
}
public ConstraintAdapter(List<String> titles, List<String> subtitles, OnItemClickListener listener) {
this.titles = titles;
this.subtitles = subtitles;
this.listener = listener;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_constraint, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.tvTitle.setText(titles.get(position));
holder.tvSubtitle.setText(subtitles.get(position));
holder.itemView.setOnClickListener(v -> {
if (listener != null) listener.onItemClick(position);
});
}
@Override
public int getItemCount() {
return titles.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
ImageView ivAvatar;
TextView tvTitle, tvSubtitle;
ViewHolder(View view) {
super(view);
ivAvatar = view.findViewById(R.id.ivAvatar);
tvTitle = view.findViewById(R.id.tvTitle);
tvSubtitle = view.findViewById(R.id.tvSubtitle);
}
}
}
Bước 5: MainActivity.java
package com.example.myapplication;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements ConstraintAdapter.OnItemClickListener {
RecyclerView recyclerView;
ConstraintAdapter adapter;
List<String> titles = new ArrayList<>();
List<String> subtitles = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
// Dữ liệu mẫu
for (int i = 1; i <= 20; i++) {
titles.add("Item " + i);
subtitles.add("Mô tả chi tiết cho item số " + i);
}
adapter = new ConstraintAdapter(titles, subtitles, this);
recyclerView.setAdapter(adapter);
}
@Override
public void onItemClick(int position) {
// Xử lý click
}
}
Ưu điểm ConstraintLayout trong RecyclerView Item
- Flat hierarchy: 1 cấp ConstraintLayout thay vì nested LinearLayout/RelativeLayout.
- Responsive: Dùng constraint, guideline, barrier, chain để thích ứng màn hình.
- Performance: Giảm measure/layout pass, cuộn mượt hơn.
- Visual Editor: Hỗ trợ drag-drop trong Layout Editor.
Chạy ứng dụng
Nhấn Run. Danh sách hiển thị với layout 2 cột (avatar + text), responsive, Toolbar ẩn/hiện khi cuộn.

Mẹo ConstraintLayout cho RecyclerView
- Dùng
android:layout_height="wrap_content"cho item root. - ConstraintTop_toTopOf + ConstraintBottom_toBottomOf cho view căn giữa dọc (avatar).
- Dùng
0dp(match_constraint) cho width text để tự co giãn. - Tránh
GONEview trong item nếu có thể - dùng visibility logic trong onBindViewHolder.