Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Android

Cách sử dụng ConstraintLayout với RecyclerView trên Android

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.

Cách sử dụng ConstraintLayout với RecyclerView trên Android

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 GONE view trong item nếu có thể - dùng visibility logic trong onBindViewHolder.