ساخت RecyclerView بدون آداپتر


ساخت ریسایکلرویو بدون آداپتر

معرفی کتابخانه ساخت recyclerView ساده تر و سریع تر بدون آداپتر

در مقالات پیشین به نحوه پیاده سازی RecyclerView پرداختیم. کتابخانه ustmannn بر اساس کتابخانه Paging در اندروید ساخته شده است. به آسانی و سرعت می توان یک recyclerView بدون آداپتر ساخت. کتابخانه ای که بر پایه زبان کاتلین نوشته شده است. نیاز به این کتابخانه زمانی احساس می شود که برنامه دیتای زیادی را برای نمایش داشته باشد. در چنین حالتی مدیریت داده هایی که بناست در اختیار adapter قرار بگیرند با چالش هایی رو به رو می شود.

برای دانلود این کتابخانه به لینک مراجعه کنید.

دانلود کتابخانه برای androidx

برای آداپتر استاندارد در بخش gradle این خط را اضافه کنید :

implementation "com.utsman.recycling:recycling:${latest}"

و هم چنین برای آداپتر RecyclerView

implementation "com.utsman.recycling-paged:recycling:${latest}"

دانلود کتابخانه برای اندروید

برای آداپتر استاندار:

implementation "com.utsman.recycling-paged:recycling:${latest}"

برای آداپتر paged :

implementation "com.utsman.recycling-paged-android:recycling:${latest}"

پیاده سازی

برای حالت استاندارد از .setAdapter<> استفاده کنید.

recyclerView.setupAdapter<Item>(R.layout.item_view) { adapter, context, list ->
    ...
}

برای حالت paging از .setupAdapterPaged<> استفاده کنید :

recyclerView.setupAdapterPaged<Item>(R.layout.item_view) { adapter, context, list ->
    ...
}

به جای viewHolder از bind به شکل زیر استفاده می شود :

recyclerView.setupAdapterPaged<Item>(R.layout.item_view) { adapter, context, list ->
    
    // recycling your holder
    bind { itemView, position, item ->
        // bind view
        itemView.img_view.load(item?.url)
        itemView.setOnClickListener {
            toast("Click on $position")
        }
    }

}

پارامترهای لازم در bind

  • itemView : برای layout هر آیتم
  • Item
  • Position : مکان هر آیتم

استفاده از Layout Manager

Layout manager در این کتابخانه بطور پیش فرش روی حالت خطی یعنی LinearLayoutManager تنظیم شده که می توان به این شکل آن را تغییر داد :

 

recyclerView.setupAdapterPaged<Item>(R.layout.item_view) { adapter, context, list ->
    
    // recycling your layout manager
    setLayoutManager(GridLayoutManager(context))

}

ساخت لیست مورد نیاز RecyclerView

با استفاده از متد (submitList(list می توان اطلاعات را به ریسایکلرویو فرستاد :

recyclerView.setupAdapterPaged<Item>(R.layout.item_view) { adapter, context, list ->
    ...
    
    submitList(yourList)
}

لود وضعیت اینترنت (اختیاری)

این کتابخانه قابلیت نمایش network loader را دارد و کافی ست از paged recyclerView استفاده شود. به این ترتیب که ابتدا فایل layout مربوطه را برای آن می سازیم :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:orientation="vertical">

    <ProgressBar
        android:id="@+id/progress_circular"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="30dp"
        tools:ignore="UnusedAttribute"
        android:indeterminateTint="@color/colorPrimary"
        android:indeterminateTintMode="src_atop" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Error"
        android:textColor="@android:color/holo_red_light"
        android:id="@+id/error_text_view"
        android:layout_margin="12dp"
        tools:ignore="HardcodedText" />

</LinearLayout>

ساخت loader

برای ساخت loader از متد (addLoader(layout استفاده می شود. در این متد id موارد موجود در layout به تابع ملحق می شوند. برای مثال :

addLoader(R.layout.item_loader) {
    idLoader = R.id.progress_circular
    idTextError = R.id.error_text_view
}

نمایش وضعیت شبکه

می توان به viewModel یا هر قسمتی که عملیات نمایش دیتا را به عهده دارد وضعیت شبکه را افزود. این وضعیت برای کاربر نمایش داده خواهد شد.

// define network state with mutable livedata
val networkState: MutableLiveData<NetworkState> = MutableLiveData()

// for error state
networkState.postValue(NetworkState.error("error network: ${t.message}"))

// for loading state
networkState.postValue(NetworkState.LOADING)

// for loaded state
networkState.postValue(NetworkState.LOADED)

// and submit in your recycling
submitNetworkState(networkState)

تصحیح محل قرارگیری progressBar برای حالتی نمایش grid

به سادگی از متد fixGridSpan(column_size) می توان استفاده نمود :

recyclerView.setupAdapterPaged<Item>(R.layout.item_view) { adapter, context, list ->

    ...
    
    val layoutManager = GridLayoutManager(context, 2)
    setLayoutManager(layoutManager)
    fixGridSpan(2)

}

بررسی دو مثال

در این مثال در یک حالت فرضی داده هایی از نوع string را به recyclerView تزریق می کنیم تا نحوه عملکرد آن را مشاهده نمایید:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val listData = listOf("satu", "dua", "tiga", "empat")

        main_recycler_view.setupAdapter<String>(R.layout.simple_item_view) { adapter, context, list ->
            bind { itemView, position, item ->
                itemView.name_item.text = item
            }

            submitList(listData)
        }
    }
}

مثالی پیچیده تر از حالتی که با استفاده از API اطلاعات دریافت می شود و وضعیت شبکه نیز نمایش داده می شود:

// View Model
class SampleViewModel : ViewModel() {

    private val instance = RetrofitInstance.create()
    private val networkState: MutableLiveData<NetworkState> = MutableLiveData()

    // get list
    fun getCuratedPhoto(perPage: Int, page: Int): LiveData<List<Pexel>?> {
        val newList: MutableLiveData<List<Pexel>?> = MutableLiveData()

        // network state is loading
        networkState.postValue(NetworkState.LOADING)

        // call api
        instance.getCuratedPhoto(perPage, page)
            .enqueue(object : Callback<Responses> {
                override fun onFailure(call: Call<Responses>, t: Throwable) {

                    // network state error with error message
                    networkState.postValue(NetworkState.error("error network: ${t.message}"))
                }

                override fun onResponse(call: Call<Responses>, response: Response<Responses>) {
                    val listResponse = response.body()?.photos
                    newList.postValue(listResponse)

                    // network state loaded
                    networkState.postValue(NetworkState.LOADED)
                }

            })

        return newList
    }

    // get network state
    fun getNetworkState(): LiveData<NetworkState> = networkState

}

// Activity
class MainActivity : AppCompatActivity() {

    private val viewModel by lazy {
        ViewModelProviders.of(this)[PexelViewModel::class.java]
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // setup recycling
        main_recycler_view.setupAdapter<Pexel>(R.layout.item_view) { adapter, context, list ->

            // bind is viewholder function
            bind { itemView, position, item ->

                itemView.img_view.load(item?.src?.small)
                itemView.setOnClickListener {
                    Toast.makeText(context, "wee ${adapter.itemCount} - ${list.size} - $position", Toast.LENGTH_SHORT).show()
                }
            }

            // add loader state
            addLoader(R.layout.item_loader) {
                idLoader = R.id.progress_circular
                idTextError = R.id.error_text_view
            }

            // using grid layout manager
            val layoutManager = GridLayoutManager(this@MainActivity, 2)
            setLayoutManager(layoutManager)
            
            // for grid layout manager, loader by default is ugly, to fix use fixGridSpan
            fixGridSpan(2)

            // call function setupData with page 1
            setupData(this, 1)

            // use paging listener for endless recycler view and loaded data
            onPagingListener(layoutManager) { page, itemCount ->
            
                // call function setup data with page +1
                setupData(this@setupAdapter, page+1)
            }
        }
    }

    // function for setup data
    private fun setupData(recycling: Recycling<Pexel>, page: Int) {
        viewModel.getCuratedPhoto(20, page).observe(this, Observer {
            
            // submit list from viewmodel into recycling
            recycling.submitList(it)
        })

        viewModel.getNetworkState().observe(this, Observer {
        
            // submit network state from viewmodel into recycling
            recycling.submitNetworkState(it)
        })
    }
}

برای مطالعه کدهای بیشتر در این زمینه می توانید به این دو پروژه در گیت هاب رجوع نمایید :

 

به این پست امتیاز دهید

روی ستاره های کلیک کنید و امتیاز بدید

میانگین امتیاز / 5. تعداد:

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

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

Enter Captcha Here : *

Reload Image