چگونه آیتم‌هایی را در RecyclerView ایجاد کنیم که با انیمیشن Expand می‌شود

ترجمه و تالیف : پوریا شریفی
تاریخ انتشار : 28 خرداد 99
خواندن در 2 دقیقه
دسته بندی ها : اندروید

قبلا مقاله‌ای در مورد انیمیشن‌های زیبا در RecyclerView نوشته‌ام، که همه چیز در مورد انیمیشن‌های ورودی آیتم‌ها بود. اکنون در این آموزش می‌خواهیم یاد بگیریم که چگونه آیتم‌های RecyclerView را با انیمیشن Expand کنیم. جالب به نظر میاد نه؟ بیایید نگاهی به آنچه که در موردش صحبت کردیم داشته باشیم.

چگونه آیتم‌هایی را در RecyclerView ایجاد کنیم که با انیمیشن Expand می‌شود

با ضربه زدن بر روی پیکان جلوی هر آیتم، یک layout اضافی در زیر آن قابل مشاهده خواهد شد. می‌توانید اطلاعات اضافی را در آنجا قرار دهید. همچنین می‌توانید انیمیشن یکنواخت از expand و collapse کردن layout و چرخش پیکان کوچک را هربار ببینید.

بیایید شروع کنیم!

اگر نمی‌دانید چگونه باRecyclerView شروع به کار کنید، من از شما می‌خواهم تا به این وبسایت رفته و آن را بررسی کنید تا در مورد آنچه که در ادامه می‌بینید آگاه‌تر باشید.

قدم اول

بیایید یک پروژه‌ی جدید بسازیم و وابستگی‌های زیر را به آن در فایل build.gradle اضافه کنیم.

dependencies{

    implementation 'com.balysv:material-ripple:1.0.2' // for ripple effect
    implementation 'com.android.support:recyclerview-v7:28.0.0' //recyclerView
    implementation 'com.squareup.picasso:picasso:2.71828' //for loading images
    implementation 'de.hdodenhof:circleimageview:3.0.0' //circularImageView 

} 

من معمولا با databinding کار می‌کنم، بنابراین با اضافه کردن تکه کد کوچکی زیر android{} و در فایل build.gradle آن را فعال می‌کنم.

dataBinding{
    enabled true
}

نکته: اگر چیزی در مورد databinding نمی‌دانید اینجا را بررسی کنید.

قدم دوم

اکنون زمان آن رسیده است که یک کلاس مدل درست کنیم. یک کلاس با نام Person ایجاد کنید. کدهای زیر را در آن کپی کنید.

public class Person {

    String name;
    String description;
    boolean isExpanded;
    int image;

    public int getImage() {
        return image;
    }

    public void setImage(int image) {
        this.image = image;
    }

    public boolean isExpanded() {
        return isExpanded;
    }

    public void setExpanded(boolean expanded) {
        isExpanded = expanded;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

قدم سوم

بیایید یک آداپتور درست کنیم تا RecyclerView کار کند. یک کلاس به اسم ExpandableRecyclerViewAdapter.java می‌سازیم، و کدهای زیر را در آن کپی می‌کنیم.

public class ExpendableRecyclerViewAdapter extends RecyclerView.Adapter<ExpendableRecyclerViewAdapter.ViewHolder> {

    Context context;
    List<Person> personList;

    public ExpendableRecyclerViewAdapter(Context context, List<Person> list) {

        this.context = context;
        this.personList = list;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {

        View view = LayoutInflater.from(context).inflate(R.layout.item_expand, null);
        ItemExpandBinding bi = DataBindingUtil.bind(view);
        return new ViewHolder(bi);

    }

    @Override
    public void onBindViewHolder(@NonNull final ViewHolder holder, final int i) {

        holder.bi.name.setText(personList.get(i).getName());

        Picasso.get().load(personList.get(i).getImage()).into(holder.bi.image);

        holder.bi.viewMoreBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

    }

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

    class ViewHolder extends RecyclerView.ViewHolder {

        ItemExpandBinding bi;

        public ViewHolder(@NonNull ItemExpandBinding itemView) {
            super(itemView.getRoot());

            bi = itemView;

        }
    }
}

برای نمایش هر آیتم، یک آیتم RecyclerVIew شبیه به شکل زیر ساخته‌ام.

چگونه آیتم‌هایی را در RecyclerView ایجاد کنیم که با انیمیشن Expand می‌شود

برای ساخت چنین آیتمی کدهای زیر را در فایل xml خود کپی کنید:

<?xml version="1.0" encoding="utf-8"?>
<layout>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"

        >

        <LinearLayout
            android:background="#fff"
            android:id="@+id/parent"
            android:focusable="true"
            android:clickable="true"
            android:minHeight="?attr/actionBarSize"
            android:gravity="center_vertical"
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize">

            <View
                android:layout_width="15dp"
                android:layout_height="wrap_content"/>


            <de.hdodenhof.circleimageview.CircleImageView
                android:id="@+id/image"
                android:class='lozad' data-src='@drawable/photo_male_1'
                android:background="@android:color/transparent"
                android:layout_width="40dp"
                android:layout_height="40dp" />

            <View
                android:layout_width="15dp"
                android:layout_height="wrap_content"/>

            <TextView
                android:id="@+id/name"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="Mutufa Ansari"
                android:textColor="#37474F"
                android:textAppearance="@style/TextAppearance.AppCompat.Medium"/>

            <View
                android:layout_width="15dp"
                android:layout_height="wrap_content"/>

            <ImageButton
                android:id="@+id/viewMoreBtn"
                android:tint="#666666"
                android:class='lozad' data-src='@drawable/ic_arrow'
                android:background="?attr/selectableItemBackgroundBorderless"
                android:layout_width="?attr/actionBarSize"
                android:layout_height="?attr/actionBarSize" />

        </LinearLayout>

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#f2f2f2"/>

        <LinearLayout
            android:layout_below="@id/parent"
            android:visibility="gone"
            android:background="#f7f7f7"
            android:orientation="vertical"
            android:id="@+id/layoutExpand"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">


            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="15dp"
                android:text="@string/lorem"/>


        </LinearLayout>




    </LinearLayout>
</layout>

حال، قبل از رفتن به قسمت انیمیشن، اجازه دهید کار خود را با RecyclerView تمام کنیم.

Activity_main.xml من شبیه به زیر است:

<?xml version="1.0" encoding="utf-8"?>

<layout>
    <LinearLayout
        android:orientation="vertical"
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".ui.MainActivity"
        >

        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">


            <android.support.v7.widget.Toolbar
                android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
                android:id="@+id/toolbar"
                android:background="?attr/colorPrimary"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize">

            </android.support.v7.widget.Toolbar>


        </android.support.design.widget.AppBarLayout>


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

        </android.support.v7.widget.RecyclerView>

    </LinearLayout>
</layout>

در MainActivity.java می‌خواهیم RecyclerView و کارکرد آن را پیاده‌سازی کنیم. برای انجام این کار نیاز به داده‌های ساختگی داریم. من تعدادی آرایه در فایل array.xml از طریق فولدر value ساخته‌ام. شما هم می‌توانید داده‌های ساختگی یا واقعی خود را داشته باشید. کدهای زیر را کپی کنید:

public class MainActivity extends AppCompatActivity {

    ActivityMainBinding bi;
    ExpendableRecyclerViewAdapter adapter;
    List<Person> personList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        bi = DataBindingUtil.setContentView(this, R.layout.activity_main);


        init();


    }

    private void init() {
        setSupportActionBar(bi.toolbar);
        getSupportActionBar().setTitle("Expandable");
        personList = new ArrayList<>();
        personList = getPersonsData();
        personList.addAll(Data.getPersonsData(this));
        adapter = new ExpendableRecyclerViewAdapter(this, personList);
        bi.list.setLayoutManager(new LinearLayoutManager(this));
        bi.list.setHasFixedSize(true);
        bi.list.setAdapter(adapter);


    }

    public List<Person> getPersonsData() {
        List<Person> people = new ArrayList<>();
        String[] persons = getResources().getStringArray(R.array.people);
        TypedArray images = getResources().obtainTypedArray(R.array.images);

        for (int i = 0; i < persons.length; i++) {
            Person person = new Person();
            person.setName(persons[i]);
            person.setImage(images.getResourceId(i, -1));
            people.add(person);
        }

        return people;

    }
}

امیدوارم شما هم نتیجه‌ی زیر را بگیرید.

چگونه آیتم‌هایی را در RecyclerView ایجاد کنیم که با انیمیشن Expand می‌شود

اکنون پیاده‌سازی اولیه به پایان رسیده است. بنابراین وقت آن رسیده است که تعدادی انیمیشن اضافه کنیم. پس بیایید آن را انجام دهیم.

قدم چهارم

من یک پکیج به اسم animations می‌سازم، و در آنجا کلاسی به اسم Animations.java می‌سازم.

بیایید قدم به قدم با هم به جلو بریم. من می‌خواهم با ضربه زدن به پیکان انیمیشن آن اجرا شود. برای این کار، نیاز است تا این قطعه کد زیر را در کلاس Animations.java کپی کنید.

public static boolean toggleArrow(View view, boolean isExpanded) {

        if (isExpanded) {
            view.animate().setDuration(200).rotation(180);
            return true;
        } else {
            view.animate().setDuration(200).rotation(0);
            return false;
        }
    }

بیایید آداپتور را ویرایش کنیم:

 @Override
    public void onBindViewHolder(@NonNull final ViewHolder holder, final int i) {

        holder.bi.name.setText(personList.get(i).getName());

        Picasso.get().load(personList.get(i).getImage()).into(holder.bi.image);

        holder.bi.viewMoreBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                boolean show = toggleLayout(!personList.get(i).isExpanded(), v, holder.bi.layoutExpand);
                personList.get(i).setExpanded(show);
            }
        });

    }

    private boolean toggleLayout(boolean isExpanded, View v, LinearLayout layoutExpand) {
        Animations.toggleArrow(v, isExpanded);
        return isExpanded;

    }

با اجرای برنامه و ضربه زدن بر روی پیکان باید بچرخد.

چگونه آیتم‌هایی را در RecyclerView ایجاد کنیم که با انیمیشن Expand می‌شود

قدم پنجم

بیایید عملکردی را پیاده‌سازی کنیم که با ضربه زدن بر روی پیکان کمک کند تا layout اضافی برای ما باز شود.

برای این کار باید چند خط کد به کلاس Animation.java اضافه کنید.

public static void expand(View view) {
        Animation animation = expandAction(view);
        view.startAnimation(animation);
    }

    private static Animation expandAction(final View view) {

        view.measure(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        final int actualheight = view.getMeasuredHeight();

        view.getLayoutParams().height = 0;
        view.setVisibility(View.VISIBLE);

        Animation animation = new Animation() {
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) {

                view.getLayoutParams().height = interpolatedTime == 1
                        ? ViewGroup.LayoutParams.WRAP_CONTENT
                        : (int) (actualheight * interpolatedTime);
                view.requestLayout();
            }
        };


        animation.setDuration((long) (actualheight / view.getContext().getResources().getDisplayMetrics().density));

        view.startAnimation(animation);

        return animation;


    }

    public static void collapse(final View view) {

        final int actualHeight = view.getMeasuredHeight();

        Animation animation = new Animation() {
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) {

                if (interpolatedTime == 1) {
                    view.setVisibility(View.GONE);
                } else {
                    view.getLayoutParams().height = actualHeight - (int) (actualHeight * interpolatedTime);
                    view.requestLayout();

                }
            }
        };

        animation.setDuration((long) (actualHeight/ view.getContext().getResources().getDisplayMetrics().density));
        view.startAnimation(animation);
    }

دوباره باید آداپتور خود را ویرایش کنید. این بار باید چند خط کد به متد toggleLayout() اضافه کنید.

private boolean toggleLayout(boolean isExpanded, View v, LinearLayout layoutExpand) {
    Animations.toggleArrow(v, isExpanded);
    if (isExpanded) {
        Animations.expand(layoutExpand);
    } else {
        Animations.collapse(layoutExpand);
    }
    return isExpanded;

}

حال بیایید برنامه را اجرا کنیم و ببینیم چه کار انجام داده‌ایم.

برای ارجاع

toggleArrow(): این متد به ما کمک می‌کند تا پیکان را با صدا زدن متد animate() در کلاس view بچرخانیم و مدت زمان آن را مطابق نیاز تنظیم کنیم.

expandAction(): در این متد ارتفاع layout را اندازه‌گیری می‌کنیم، که طول انیمیشن و Expand کردن آن را براساس این اندازه انجام می‌دهیم.

Collaps(): عملکرد این متد نیز همانند قبلی است، اما این بار قابلیت دید layout را از VISIBLE به GONE تغییر می‌دهیم.

منبع

گردآوری و تالیف پوریا شریفی
آفلاین
user-avatar

ابتدا که با برنامه‌نویسی آشنا شدم به سمت php و طراحی وب رفتم، بعد از اون به توسعه‌ی اندروید علاقه‌مند شدم و تقریبا ۲ سال است که مشغول به برنامه‌نویسی اندروید هستم، همچنین عاشق یادگیری چیزهای جدید هستم.

دیدگاه‌ها و پرسش‌ها

برای ارسال نظر لازم است ابتدا وارد سایت شوید
در حال دریافت نظرات از سرور، لطفا منتظر بمانید