Sử dụng recyclerview với header một cách đơn giản tăng hiệu năng ứng dụng

Trong hướng dẫn này, chúng ta sẽ học làm thế nào để thêm header vào recyclerview.

Nếu bạn đã làm việc với Android ListView, chúng ta sẽ nhận thấy rằng có phương thức xây dựng trong phương thức addHeaderView () để bạn có thể dễ dàng sử dụng để thêm tiêu đề vào ListView.

Có thể có vài cách để đạt được điều này nhưng trong bài viết này chúng ta sẽ sử dụng thuộc tính ViewType.

Ngoài ra bạn có thể xem lại bài viết khác về recyclerview trong link sau.

CREATE NEW ANDROID PROJECT

Trong bài viết này mình sử dụng cấu hình sau:

  • Android Studio 3.0
  • Min SDK 15
  • Target SDK 26

CONFIG BUILD.GRADLE

apply plugin: 'com.android.application'

android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "com.recyclerview.header"
        minSdkVersion 15
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
    implementation 'com.android.support:recyclerview-v7:26.1.0'
    implementation 'com.android.support:cardview-v7:26.1.0'
    compile 'com.jakewharton:butterknife:8.8.1'
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
}

 

Ở đây mình có sử dụng thêm plugin ButterKnife để BindView các bạn xem ở đây nhé.

Step By Step

Xong phần config chúng ta sẽ tiến hành công việc từng bước một cách dễ hiểu nhất.

Step 1: Tạo layout cho Header và Item

Đầu tiên chúng ta tạo 2 file /.xml cho 2 thành phần trong recyclerview:

header_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="16sp"
    android:orientation="vertical">
    <TextView
        android:id="@+id/header_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:textStyle="bold"
        android:textColor="@color/colorBlack"
        android:text="@string/app_name"/>
</LinearLayout>

item_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <android.support.v7.widget.CardView
        android:id="@+id/direction_card_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="2dp"
        card_view:cardElevation="2dp"
        card_view:cardUseCompatPadding="true">
        <TextView
            android:id="@+id/item_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="24dp"
            android:textColor="@color/colorPrimaryDark"
            android:textSize="16sp"
            android:gravity="center"
            android:text="@string/sample" />
    </android.support.v7.widget.CardView>
</LinearLayout>

Step 2: Tạo ViewHolder cho 2 layout ở trên

HeaderViewHolder.java

public class HeaderViewHolder extends RecyclerView.ViewHolder{
    @BindView(R.id.header_id)
    TextView headerTitle;
    public HeaderViewHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(this,itemView);
    }
}

ItemViewHolder.java

public class ItemViewHolder extends RecyclerView.ViewHolder{
    @BindView(R.id.item_content)
    TextView itemContent;
    public ItemViewHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(this,itemView);
    }
}

Step 3: Tạo Data mẫu để hiển thị

Đầu tiên mình tạo một Object tên ItemObject.java chứa contents.

public class ItemObject {
    private String contents;
    public ItemObject(String contents) {
        this.contents = contents;
    }
    public String getContents() {
        return contents;
    }
}

 

Step 4: Tạo CustomRecyclerViewAdapter.java từ các file ở trên

public class CustomRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private static final String TAG = CustomRecyclerViewAdapter.class.getSimpleName();
    private static final int TYPE_HEADER = 0;
    private static final int TYPE_ITEM = 1;
    private List<ItemObject> itemObjects;

    public CustomRecyclerViewAdapter(List<ItemObject> itemObjects) {
        this.itemObjects = itemObjects;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == TYPE_HEADER) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.header_layout, parent, false);
            return new HeaderViewHolder(view);
        } else if (viewType == TYPE_ITEM) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
            return new ItemViewHolder(view);
        }
        throw new RuntimeException("No match for " + viewType + ".");
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        ItemObject mObject = itemObjects.get(position);
        if (holder instanceof HeaderViewHolder) {
            ((HeaderViewHolder) holder).headerTitle.setText(mObject.getContents());
        } else if (holder instanceof ItemViewHolder) {
            ((ItemViewHolder) holder) .itemContent.setText(mObject.getContents());
        }
    }

    @Override
    public int getItemViewType(int position) {
        if (isPositionHeader(position))
            return TYPE_HEADER;
        return TYPE_ITEM;
    }

    private boolean isPositionHeader(int position) {

        return position == 0 || position == 10;
    }

    @Override
    public int getItemCount() {
        return itemObjects.size();
    }
}

Ở adapter này các bạn chỉ cần chú ý đến hàm:

@Override
    public int getItemViewType(int position) {
        if (isPositionHeader(position))
            return TYPE_HEADER;
        return TYPE_ITEM;
    }

    private boolean isPositionHeader(int position) {

        return position == 0 || position == 10;
    }

Ở hàm này mình set header sẽ là vị trí thứ 0 và thứ 10 trong list dữ liệu itemObjects  và trả về ViewType tương ứng. Tiến hành hiển thị dữ liệu theo từng loại viewtype.

Step 5: Sử dụng Adapter vừa tạo 

Mở MainActivity tạo dữ liệu giả và đổ lên Adapter thôi. Tuỳ thuộc vào cấu trúc dữ liệu mà bạn định nghĩa các hàm trong adapter cho hợp logic.

public class MainActivity extends AppCompatActivity {
    @BindView(R.id.rcv_header)
    RecyclerView addHeaderRecyclerView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(MainActivity.this);
        addHeaderRecyclerView.setLayoutManager(linearLayoutManager);
        addHeaderRecyclerView.setHasFixedSize(true);
        CustomRecyclerViewAdapter customAdapter = new CustomRecyclerViewAdapter(getDataSource());
        addHeaderRecyclerView.setAdapter(customAdapter);
    }

    private List<ItemObject> getDataSource() {
        List<ItemObject> data = new ArrayList<>();
        data.add(new ItemObject("First Header"));
        data.add(new ItemObject("This is the item content in the first position"));
        data.add(new ItemObject("This is the item content in the second position"));
        data.add(new ItemObject("This is the item content in the third position"));
        data.add(new ItemObject("This is the item content in the fourth position"));
        data.add(new ItemObject("This is the item content in the fifth position"));
        data.add(new ItemObject("This is the item content in the first position"));
        data.add(new ItemObject("This is the item content in the second position"));
        data.add(new ItemObject("This is the item content in the third position"));
        data.add(new ItemObject("This is the item content in the fourth position"));
        data.add(new ItemObject("Two Header"));
        data.add(new ItemObject("This is the item content in the fourth position"));
        data.add(new ItemObject("This is the item content in the fifth position"));
        data.add(new ItemObject("This is the item content in the first position"));
        data.add(new ItemObject("This is the item content in the second position"));
        data.add(new ItemObject("This is the item content in the third position"));
        data.add(new ItemObject("This is the item content in the fourth position"));
        return data;
    }
}

Cuối cùng chạy app để kiểm tra nào 😀

GitHub Tham Khảo.

Bài viết gốc ở đây.

Nguyễn Linh

Chia sẻ để cùng tiến bộ...