کار کردن با RecyclerView در اندروید

منتشرشده توسط حامد قنبری در تاریخ

Android RecyclerView نمونه پیشرفته تری از ListView با عملکرد بهبود یافته و افزون بر آن دارای مزیت بیشتری است. با استفاده از RecyclerView و CardView با هم، می توان  لیست و شبکه های پیشرفته تری ایجاد نمود که کاربر در استفاده از آنها احساس راحتری   بیشتری داشته باشد. در این نوشته قصد داریم  در مورد این عنوان اطلاعات بیشتری را در اختیار دوستان قرار دهیم .  در این آموزش شما خواهید آموخت که چگونه یک RecyclerView ساده را با یک طرح سفارشی ایجاد کنید. همچنين  یاد خواهيد گرفت که چگونه می توان   يک کلاس آداپتور را به آن اضافه کرد، همچنین نحوه استفاده و  اضافه کردن لیست تقسيم کننده divider و oncliklistener  را به سادگی یاد خواهید گرفت . در مثالی که ارائه خواهیم داد شما خواهید توانست  لیستی از انواع الگوهای پیشفرض را به منظور راهنمایی کاربران ارائه کنید بطوری که کاربر با کلیک کردن بر روی هریک از آیتم ها قادر خواهد بود  به محتوای مورد نظر آن آیتم راهنمایی شود.

قبل از ارائه مثال لازم است که برای ایجاد RecyclerView در لایوت xml  از دستور زیر استفاده می کنیم:

 

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

اگر در داخل برنامه اکلیپس یا اندروید استودیو قرار دارید پروژه جدیدی را  ایجاد کنید

اکلیپس :File ⇒ New Android ⇒ Application Project

اندروید استودیو :File ⇒ New  ⇒ New Project

اما اگر هنوز برنامه خود را باز نکرده اید یکی از برنامه های فوق را باز نموده و بعد از تعیین مشخصات(نامگذاری) ، تعیین حداقل sdk  و نوع اکتیویتی (blank  یا Empty) ، نام اکتیویتی ابتدایی و اصلی خود  را همان MainActivity قرار دهید.

در اولین گام فایلbuild.gradle را باز کرده و وابستگی زیر را

compile ‘com.android.support:recyclerview-v7:+’

 را به شکل زیر به آن اضافه کنید و سپس پروژه را sync  کنید :

 

apply plugin: 'com.android.application'

android {
    compileSdkVersion 27
    buildToolsVersion "26.0.0"

    defaultConfig {
        applicationId "ir.psrd.recyclerview.myapplication"
        minSdkVersion 15
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:25.0.0'
    compile 'com.android.support:design:25.0.0'
    compile 'com.android.support:recyclerview-v7:+'
}

 

بعد از کامپایل کردن کتابخانه، در مسیر res ⇒layout لایه متناظر اکتیوتی اصلی یعنی activity_main را پیدا نمود و کدهای مندرج و پیش فرض آن را پاک کرده و کدهای xml  زیر را به آن اضافه کنید:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    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"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:showIn="@layout/activity_main"
    tools:context=".MainActivity">

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

</RelativeLayout>

سپس کلاس جدیدی را به منظور تعریف متغیرها و دسترسی به getter / setter  با نام book تعریف می کنیم.

package ir.psrd.recyclerview.myapplication;

/**
 * Created by  hamed on 8/24/2018.
 */
public class Book {
    private String title, categeroie, year;

    public Book() {
    }

    public Book(String title, String genre, String year) {
        this.title = title;
        this.categeroie = categeroie;
        this.year = year;
    }

    public String getTitle() {
        return title;
    }

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

    public String getYear() {
        return year;
    }

    public void setYear(String year) {
        this.year = year;
    }

    public String getcategeroie() {
        return categeroie;
    }

    public void setcategeroie(String genre) {
        this.categeroie = genre;
    }
}
public void setGenre(String genre) {
this.genre = genre;
}
}

در مرحله بعد فایل XML  جدیدی را در فایل مربوط به لایوت با نام book_list_row.xml ایجاد کنید. این صفحه  اطلاعات مربوط به کتاب ها را بصورت ردیف بندی شده برای کاربران نمایش خواهد داد که شامل اطلاعات مربوط به عنوان ، سال نشر و دسته بندی مربوط به آن کتاب خواهد بود.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?android:attr/selectableItemBackground"
    android:clickable="true"
    android:focusable="true"
    android:orientation="vertical"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
   >

    <TextView
        android:id="@+id/title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:textSize="16dp"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/categeroie"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/title" />

    <TextView
        android:id="@+id/year"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
 />

</RelativeLayout>

حالا یک کلاس به نام BookAdapter.java ایجاد کنید و کد زیر را  به ان اضافه کنید. در این کلاس متد () methodCreateViewHolder  فایل مربوط به  booklist_row.xml را inflates می کند  و متد ()onBindViewHolder  اطلاعات مربوط به کتاب (عنوان، دسته بندی و سال نشر) برای هر ردیف تعیین می کند.

package ir.psrd.recyclerview.myapplication;

/**
 * Created by hamed on 8/24/2018.
 */
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.List;

public class BooksAdapter extends RecyclerView.Adapter<BooksAdapter.MyViewHolder> {

    private List<Book> booksList;

    public class MyViewHolder extends RecyclerView.ViewHolder {
        public TextView title, year, categore;

        public MyViewHolder(View view) {
            super(view);
            title = (TextView) view.findViewById(R.id.title);
            categore = (TextView) view.findViewById(R.id.categeroie);
            year = (TextView) view.findViewById(R.id.year);
        }
    }


    public BooksAdapter(List<Book> booksList) {
        this.booksList = booksList;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.book_list_row, parent, false);

        return new MyViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        Book book = booksList.get(position);
        holder.title.setText(book.getTitle());
        holder.categore.setText(book.getcategeroie());
        holder.year.setText(book.getYear());
    }

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

در گام بعدی لازم است خط تقسیم بین سطرها را با استفاده از DividerItemDecoration به پروژه خود اضافه کنید . از این رو کلاس جدیدی با نام MyDividerItemDecoration ایجاد کرده و آن را به نوع   RecyclerView.ItemDecoration  که دکوراسیون لازم را برای    RecyclerView فراهم می کند گسترش دهید.

package ir.psrd.recyclerview.myapplication;

/**
 * Created by hossin on 8/24/2018.
 */
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.TypedValue;
import android.view.View;


public class MyDividerItemDecoration extends RecyclerView.ItemDecoration {

    private static final int[] ATTRS = new int[]{
            android.R.attr.listDivider
    };

    public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;

    public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;

    private Drawable mDivider;
    private int mOrientation;
    private Context context;
    private int margin;

    public MyDividerItemDecoration(Context context, int orientation, int margin) {
        this.context = context;
        this.margin = margin;
        final TypedArray a = context.obtainStyledAttributes(ATTRS);
        mDivider = a.getDrawable(0);
        a.recycle();
        setOrientation(orientation);
    }

    public void setOrientation(int orientation) {
        if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
            throw new IllegalArgumentException("invalid orientation");
        }
        mOrientation = orientation;
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        if (mOrientation == VERTICAL_LIST) {
            drawVertical(c, parent);
        } else {
            drawHorizontal(c, parent);
        }
    }

    public void drawVertical(Canvas c, RecyclerView parent) {
        final int left = parent.getPaddingLeft();
        final int right = parent.getWidth() - parent.getPaddingRight();

        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            final int top = child.getBottom() + params.bottomMargin;
            final int bottom = top + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left + dpToPx(margin), top, right - dpToPx(margin), bottom);
            mDivider.draw(c);
        }
    }

    public void drawHorizontal(Canvas c, RecyclerView parent) {
        final int top = parent.getPaddingTop();
        final int bottom = parent.getHeight() - parent.getPaddingBottom();

        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            final int left = child.getRight() + params.rightMargin;
            final int right = left + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top + dpToPx(margin), right, bottom - dpToPx(margin));
            mDivider.draw(c);
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        if (mOrientation == VERTICAL_LIST) {
            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
        } else {
            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
        }
    }

    private int dpToPx(int dp) {
        Resources r = context.getResources();
        return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics()));
    }
}

 

نمایش پیمایش افقی RecyclerView

اگر می خواهید RecyclerView را به صورت Horizontal نمایش دهید، می توانید این کار را فقط با تغییر یک خط کد انجام دهید. تنها کاری که باید انجام دهید این است که کد مربوط به  LinearLayoutManager.HORIZONTAL را در داخل پارامتر کلاس LinearLayoutManagerکه در زیر نشان داده شده است قرار دهید. همچنین فراموش نکنید که عرض طرح ردیف خود را تا WRAP_CONTENT حفظ کنید.

RecyclerView.LayoutManager mLayoutManager =
        new LinearLayoutManager(getApplicationContext(), LinearLayoutManager.HORIZONTAL, false);

کلاس جدیدی به نام RecyclerTouchListener.java ایجاد کنید و آن را به نوع RecyclerView.OnItemTouchListener گسترش دهید. در واقع با استفاده از این کلاس می توانید از رابط ClickListener  در پروژه خود استفاده کنید.

package ir.psrd.recyclerview.myapplication;

/**
 * Created by hamed on 8/24/2018.
 */
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;

public class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {

    private GestureDetector gestureDetector;
    private ClickListener clickListener;

    public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final ClickListener clickListener) {
        this.clickListener = clickListener;
        gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                return true;
            }

            @Override
            public void onLongPress(MotionEvent e) {
                View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
                if (child != null && clickListener != null) {
                    clickListener.onLongClick(child, recyclerView.getChildPosition(child));
                }
            }
        });
    }

    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {

        View child = rv.findChildViewUnder(e.getX(), e.getY());
        if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
            clickListener.onClick(child, rv.getChildPosition(child));
        }
        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

    }

    public interface ClickListener {
        void onClick(View view, int position);

        void onLongClick(View view, int position);
    }
}

 

در نهایت کلاس MainActivity.Class  کدهای زیر را قرار دهید.

package ir.psrd.recyclerview.myapplication;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private List<Book> booksList = new ArrayList<>();
    private RecyclerView recyclerView;
    private BooksAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        recyclerView = (RecyclerView) findViewById(R.id.myrecycler_view);

        mAdapter = new BooksAdapter(booksList);

        recyclerView.setHasFixedSize(true);

        // vertical RecyclerView
        // keep movie_list_row.xml width to `match_parent`
        RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());

        // horizontal RecyclerView
        // keep movie_list_row.xml width to `wrap_content`
        // RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext(), LinearLayoutManager.HORIZONTAL, false);

        recyclerView.setLayoutManager(mLayoutManager);

        // adding inbuilt divider line
        recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));

        // adding custom divider line with padding 16dp
        // recyclerView.addItemDecoration(new MyDividerItemDecoration(this, LinearLayoutManager.VERTICAL, 16));
        recyclerView.setItemAnimator(new DefaultItemAnimator());

        recyclerView.setAdapter(mAdapter);

        // row click listener
        recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getApplicationContext(), recyclerView, new RecyclerTouchListener.ClickListener() {
            @Override
            public void onClick(View view, int position) {
                Book book = booksList.get(position);
                Toast.makeText(getApplicationContext(), book.getTitle() + " is selected!", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onLongClick(View view, int position) {

            }
        }));

        prepareMovieData();
    }

    /**
     * Prepares sample data to provide data set to adapter
     */
    private void prepareMovieData() {
        Book book = new Book("کتاب اول", " & آموزشی ", "1394");
        booksList.add(book);

        book = new Book("کناب دوم", "اجتماعی", "1395");
        booksList.add(book);

        book = new Book("کتاب سوم", "رمان", "1396");
        booksList.add(book);

        book = new Book("کتاب جهارم", "روانشناسی", "1397");
        booksList.add(book);

        book = new Book("کتاب پنحم", "مهندسی مکانیک", "1397");
        booksList.add(book);



        // notify adapter about data set changes
        // so that it will render the list with new data
        mAdapter.notifyDataSetChanged();
    }

}

حال پروژه را اجرا کرده و از آن در آموزش هر چه بیشتر خود استفاده کنید. اگر مشکلی در اجرای کدها وجود دارد یا سوال مشخصی از نویسنده سایت دارید سوالات خود را در قسمت دیدگاه ها بیان کنید.

کپی برداری از محتوای سایت psrd، ممنوع بوده و پیگرد قانونی دارد. (تنها استفاده شخصی کاربران ، مجاز است) (کپی برداری توسط سایر وب سایت ها  غیرقانونی بوده و در صورت رویت به ستادسازماندهی اطلاع داده خواهد شد.

 


0 دیدگاه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

-- بارگیری کد امنیتی --