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

Tạo hiệu ứng animation cho item RecyclerView khi cuộn trong Android

Giới thiệu về RecyclerView và CardView

Trước khi đi vào ví dụ về animation cho item RecyclerView, chúng ta cần hiểu RecyclerView là gì. RecyclerView là phiên bản nâng cao của ListView, hoạt động dựa trên mẫu thiết kế ViewHolder. Nó cho phép hiển thị danh sách hoặc lưới các item một cách linh hoạt và hiệu quả.

CardView kế thừa từ FrameLayout, được dùng để hiển thị các item theo kiểu thẻ (card). Nó hỗ trợ sẵn các thuộc tính như góc bo tròn (radius) và đổ bóng (shadow).

Ví dụ này minh họa cách tích hợp animation vào RecyclerView kết hợp CardView bằng cách xây dựng một ứng dụng quản lý sinh viên đơn giản hiển thị tên và tuổi.

Các bước thực hiện

Bước 1: Tạo project mới

Mở Android Studio, chọn File → New Project và điền các thông tin cần thiết để tạo project mới.

Bước 2: Thêm thư viện dependency

Mở file build.gradle (Module: app) và thêm các thư viện RecyclerView và CardView:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.example.andy.tutorialspoint"
        minSdkVersion 19
        targetSdkVersion 28
        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(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support:design:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    implementation 'com.android.support:cardview-v7:28.0.0'
    implementation 'com.android.support:recyclerview-v7:28.0.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

Bước 3: Cấu hình layout chính (activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:showIn="@layout/activity_main"
    tools:context=".MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="vertical" />

</RelativeLayout>

Ở đây chúng ta đặt RecyclerView làm view con của RelativeLayout.

Bước 4: Code MainActivity.java

package com.example.andy.tutorialspoint;

import android.annotation.TargetApi;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.LinearLayout;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private RecyclerView recyclerView;
    private StudentAdapter studentAdapter;
    private List<StudentData> studentDataList = new ArrayList<>();

    @TargetApi(Build.VERSION_CODES.O)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = findViewById(R.id.recycler_view);
        studentAdapter = new StudentAdapter(studentDataList, MainActivity.this);
        RecyclerView.LayoutManager manager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(manager);
        recyclerView.setAdapter(studentAdapter);
        prepareStudentData();
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    private void prepareStudentData() {
        studentDataList.add(new StudentData("Sai", 25));
        studentDataList.add(new StudentData("Sai", 25));
        studentDataList.add(new StudentData("Raghu", 20));
        studentDataList.add(new StudentData("Raj", 28));
        studentDataList.add(new StudentData("Amar", 15));
        studentDataList.add(new StudentData("Bapu", 19));
        studentDataList.add(new StudentData("Chandra", 52));
        studentDataList.add(new StudentData("Deraj", 30));
        studentDataList.add(new StudentData("Eshanth", 28));

        // Sắp xếp danh sách theo tên
        Collections.sort(studentDataList, new Comparator<StudentData>() {
            @Override
            public int compare(StudentData o1, StudentData o2) {
                return o1.name.compareTo(o2.name);
            }
        });
    }
}

Trong code trên, chúng ta khởi tạo RecyclerView, gán adapter và LayoutManager. Dữ liệu sinh viên được thêm vào ArrayList và sắp xếp theo tên sử dụng Collections.sort() với Comparator tùy chỉnh.

Bước 5: Tạo StudentAdapter.java với animation

package com.example.andy.tutorialspoint;

import android.content.Context;
import android.graphics.Color;
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.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.List;
import java.util.Random;

class StudentAdapter extends RecyclerView.Adapter<StudentAdapter.MyViewHolder> {
    private List<StudentData> studentDataList;
    private Context context;
    private int lastPosition = -1;

    public StudentAdapter(List<StudentData> studentDataList, Context context) {
        this.studentDataList = studentDataList;
        this.context = context;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View itemView = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.student_list_row, viewGroup, false);
        return new MyViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(MyViewHolder viewHolder, int i) {
        StudentData data = studentDataList.get(i);
        Random rnd = new Random();
        int currentColor = Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
        viewHolder.parent.setBackgroundColor(currentColor);
        viewHolder.name.setText(data.name);
        viewHolder.age.setText(String.valueOf(data.age));
        setAnimation(viewHolder.parent, i);
    }

    private void setAnimation(View viewToAnimate, int position) {
        // Chỉ animate khi item chưa từng hiển thị trên màn hình
        if (position > lastPosition) {
            Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
            viewToAnimate.startAnimation(animation);
            lastPosition = position;
        }
    }

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

    static class MyViewHolder extends RecyclerView.ViewHolder {
        TextView name, age;
        LinearLayout parent;

        public MyViewHolder(View itemView) {
            super(itemView);
            parent = itemView.findViewById(R.id.parent);
            name = itemView.findViewById(R.id.name);
            age = itemView.findViewById(R.id.age);
        }
    }
}

Giải thích các phương thức chính:

  • onCreateViewHolder(): Tạo ViewHolder mới từ layout item.
  • onBindViewHolder(): Gán dữ liệu vào ViewHolder. Tại đây cũng set màu nền ngẫu nhiên và gọi animation.
  • getItemCount(): Trả về số lượng item.
  • MyViewHolder: Inner class giữ reference các view con.

Tạo màu nền ngẫu nhiên:

Random rnd = new Random();
int currentColor = Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
viewHolder.parent.setBackgroundColor(currentColor);

Logic animation trong setAnimation():

private void setAnimation(View viewToAnimate, int position) {
    if (position > lastPosition) {
        Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
        viewToAnimate.startAnimation(animation);
        lastPosition = position;
    }
}

Chỉ animate các item mới xuất hiện (position > lastPosition), sử dụng animation có sẵn slide_in_left của Android.

Bước 6: Layout item (student_list_row.xml)

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:card_view="https://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    card_view:cardCornerRadius="4dp"
    android:id="@+id/card_view"
    android:layout_margin="10dp"
    android:layout_height="200dp">

    <LinearLayout
        android:id="@+id/parent"
        android:layout_gravity="center"
        android:layout_width="match_parent"
        android:orientation="vertical"
        android:gravity="center"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/name"
            android:layout_width="wrap_content"
            android:gravity="center"
            android:textSize="25sp"
            android:textColor="#FFF"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/age"
            android:layout_width="wrap_content"
            android:gravity="center"
            android:textSize="25sp"
            android:textColor="#FFF"
            android:layout_height="wrap_content" />

    </LinearLayout>
</android.support.v7.widget.CardView>

Mỗi item là một CardView chứa LinearLayout dọc với 2 TextView hiển thị tên và tuổi. CardView cung cấp góc bo tròn và đổ bóng tự động.

Bước 7: Model StudentData.java

package com.example.andy.tutorialspoint;

class StudentData {
    String name;
    int age;

    public StudentData(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

Chạy ứng dụng

Kết nối thiết bị Android thật, chọn Run từ toolbar. Màn hình đầu tiên hiển thị danh sách sinh viên:

Tạo hiệu ứng animation cho item RecyclerView khi cuộn trong Android

Khi cuộn xuống, các item mới sẽ xuất hiện với hiệu ứng trượt từ trái sang:

Tạo hiệu ứng animation cho item RecyclerView khi cuộn trong Android