Merhabalar. Android Kütüphane Sistemi Mobil Uygulaması yazı dizisinin yedinci yazısı ile yeniden sizlerleyim. Bu yazıda kitap listesi ekranından bahsedeceğim.Tekrar belirtmekte fayda olacak, uygulamanın kodlarına buradan erişebilirsiniz.
Burada liste çekilirken verinin fazla olması göz önünde bulundurularak scroll yaptıkça verinin gelmesi yani ScrollListener kullanılmıştır. Bu sayede servis tarafı yorulmayıp daha performanslı bir yapı ortaya çıkmıştır. Kitap listesi ekranı ;
-Kitap resmi
-Kitap adı
-Kitap açıklamasının belli bir kısmı
ögelerinden oluşmaktadır. Ekran görüntüsü aşağıda ki gibidir.
fragment_kitap_islem.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/kitapListeRw"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
class KitapIslemFragment():Fragment() {
private lateinit var kitapIslemView:View;
private lateinit var kitapListeRw:RecyclerView;
private lateinit var pd:Dialog;
private lateinit var kitapService:IKitapIslemService;
private var liste:ArrayList<KitapModel> = ArrayList<KitapModel>();
private lateinit var kitapAdapter:KitapListeAdapter;
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
kitapIslemView = inflater.inflate(R.layout.fragment_kitap_islem,container,false);
initComponents();
initKitapListe();
val scrollListener:EndlessRecyclerViewScrollListener;
scrollListener = object:EndlessRecyclerViewScrollListener(4,kitapListeRw.layoutManager as LinearLayoutManager){
override fun onLoadMore(page: Int, totalItemsCount: Int, view: RecyclerView) {
pd.show();
val jsonObj: JSONObject = JSONObject();
jsonObj.put("minKayitNum",((page*4)));
jsonObj.put("maxKayitNum",4);
kitapService.getKitapListe(jsonObj.toString()).enqueue(object:
Callback<ArrayList<KitapModel>> {
override fun onFailure(call: Call<ArrayList<KitapModel>>?, t: Throwable) {
Log.d("Exception",""+t.localizedMessage);
SimpleToast.error(context, resources.getString(R.string.kitapListeHata), "{fa-times-circle}");
pd.dismiss();
}
override fun onResponse(call: Call<ArrayList<KitapModel>>?, response: Response<ArrayList<KitapModel>>) {
if(response.body() != null){
val yeniListe = response.body() as ArrayList<KitapModel>;
liste.addAll(yeniListe);
kitapAdapter.notifyItemInserted(liste.size);
val handler: Handler = Handler(Looper.getMainLooper());
handler.postDelayed(object:Runnable{
override fun run() {
kitapAdapter.notifyDataSetChanged();
}
},1000);
}
pd.dismiss();
}
});
}
}
kitapListeRw.addOnScrollListener(scrollListener);
return kitapIslemView;
}
private fun initComponents(){
kitapListeRw = kitapIslemView.findViewById(R.id.kitapListeRw) as RecyclerView;
kitapService = WebApiUtil.getKitapService(context!!);
pd = Dialog(activity!!);
val pdView: View = layoutInflater.inflate(R.layout.custom_progress_dialog,null);
pd.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT));
pd.setTitle(null);
pd.setContentView(pdView);
pd.setCancelable(false);
kitapListeRw.setHasFixedSize(true);
//kitapListeRw.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
kitapListeRw.layoutManager = LinearLayoutManager(context);
kitapListeRw.addItemDecoration(LinearSpacingDecoration(itemSpacing = 20, edgeSpacing = 30))
activity!!.kitapEkleBtn.visibility = View.VISIBLE;
activity!!.kitapEkleBtn.setOnClickListener {
ProjectUtil.activityYonlendir(activity!!, KitapEklemeActivity());
}
}
private fun initKitapListe(){
pd.show();
val jsonObj: JSONObject = JSONObject();
jsonObj.put("minKayitNum",0);
jsonObj.put("maxKayitNum",4);
kitapService.getKitapListe(jsonObj.toString()).enqueue(object:
Callback<ArrayList<KitapModel>> {
override fun onFailure(call: Call<ArrayList<KitapModel>>?, t: Throwable) {
Log.d("Exception",""+t.localizedMessage);
SimpleToast.error(context, resources.getString(R.string.kitapListeHata), "{fa-times-circle}");
pd.dismiss();
}
override fun onResponse(call: Call<ArrayList<KitapModel>>?, response: Response<ArrayList<KitapModel>>) {
liste = response.body() as ArrayList<KitapModel>;
kitapAdapter = KitapListeAdapter(context!!,liste);
kitapListeRw.adapter = kitapAdapter;
pd.dismiss();
}
});
}
}
Kitaplar çekildikten sonra adapter recyclerview'a setlenmektedir. Adapter ve onun layout u aşağıda ki gibidir.
card_kitap.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/cardLayoutId"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
android:background="@drawable/card_kitap_border"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:id="@+id/imageLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/kitapCardImageId"
android:layout_width="110dp"
android:layout_height="130dp"
app:srcCompat="@drawable/edit_text_border" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/genelBilgilerRootId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/imageLayout">
<RelativeLayout
android:id="@+id/genelBilgiler"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/kitapCardAdTextId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:gravity="center"
android:text="TextView"
android:textColor="@color/siyah"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="@+id/kitapTurTextId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/kitapCardAdTextId"
android:layout_marginTop="5dp"
android:gravity="left"
android:text="TextView"
android:textColor="#4E4E4E"
android:textSize="14sp"/>
<TextView
android:id="@+id/kitapAciklamaTextId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/kitapTurTextId"
android:layout_marginTop="5dp"
android:gravity="left"
android:text="TextView"
android:textColor="#515151"
android:fontFamily="@font/alegreya"
android:textSize="12sp"/>
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
KitapListeAdapter.kt
class KitapListeAdapter(private val mContext: Context, private val kitapListe:ArrayList<KitapModel>):
RecyclerView.Adapter<KitapHolder>(){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): KitapHolder {
val kitapTurCardView: View = LayoutInflater.from(mContext).inflate(R.layout.card_kitap,parent,false);
return KitapHolder(kitapTurCardView);
}
override fun getItemCount(): Int {
return kitapListe.size;
}
override fun onBindViewHolder(holder: KitapHolder, position: Int) {
val kitap:KitapModel = kitapListe.get(position);
Glide.with(mContext).load(kitap.kitapResimPath).into(holder.kitapImage);
if(kitap.kitapAd!!.length>55){
holder.kitapAdText.text = kitap.kitapAd!!.substring(0,54)+"...";
}else{
holder.kitapAdText.text = kitap.kitapAd;
}
holder.kitapTurText.text = "Kitap Türü : "+kitap.kitapTur?.aciklama;
if(kitap.kitapAciklama!!.length>110){
holder.kitapAciklamaText.text = kitap.kitapAciklama?.substring(0,110)+"...";
}else{
holder.kitapAciklamaText.text = kitap.kitapAciklama;
}
holder.cardLayoutId.setOnClickListener {
putKitapDetayIntoSharedPreferences(mContext,kitap);
ProjectUtil.activityYonlendir(mContext,KitapDetayActivity());
}
}
fun addAllItems(yeniListe:ArrayList<KitapModel>):Unit{
this.kitapListe.clear();
this.kitapListe.addAll(yeniListe);
}
private fun putKitapDetayIntoSharedPreferences(mContext: Context, kitap: KitapModel) {
kitap.id?.let {
ProjectUtil.putIntDataToSharedPreferences(mContext,ProjectUtil.SHARED_PREF_FILE,"kitapId",
it
)
};
ProjectUtil.putStringDataToSharedPreferences(mContext,ProjectUtil.SHARED_PREF_FILE,"kitapAd",kitap.kitapAd.toString());
ProjectUtil.putStringDataToSharedPreferences(mContext,ProjectUtil.SHARED_PREF_FILE,"yazarAd",kitap.yazarAd.toString());
ProjectUtil.putStringDataToSharedPreferences(mContext,ProjectUtil.SHARED_PREF_FILE,"kitapAciklama",kitap.kitapAciklama.toString());
ProjectUtil.putStringDataToSharedPreferences(mContext,ProjectUtil.SHARED_PREF_FILE,"kitapTur",kitap.kitapTur!!.aciklama.toString());
ProjectUtil.putStringDataToSharedPreferences(mContext,ProjectUtil.SHARED_PREF_FILE,"kitapYayinevi",kitap.yayinEvi!!.aciklama.toString());
ProjectUtil.putStringDataToSharedPreferences(mContext,ProjectUtil.SHARED_PREF_FILE,"kitapResim",kitap.kitapResimPath.toString());
kitap.alinmatarihi?.let { ProjectUtil.formatDate(it,"dd.MM.yyyy") }?.let {
ProjectUtil.putStringDataToSharedPreferences(mContext,ProjectUtil.SHARED_PREF_FILE,"kitapAlinmaTarih",
it
)
};
ProjectUtil.putDoubleDataToSharedPreferences(mContext,ProjectUtil.SHARED_PREF_FILE,"kitapPuan",kitap.kitapPuan);
}
}
Burada kitap detay ekranına gidilirken putKitapDetayIntoSharedPreferences metodu ile kitaba ait bilgiler shared preferences'a yazılmaktadır.
Kitap resmi Glide kütüphanesi ile çekilirken kitap açıklaması ise aşağıda ki kod kısmı ile ekranda fazla yer kaplamasın diye sınırlandırılmaktadır.
if(kitap.kitapAd!!.length>55){
holder.kitapAdText.text = kitap.kitapAd!!.substring(0,54)+"...";
}else{
holder.kitapAdText.text = kitap.kitapAd;
}
Burada dikkat edilmesi gereken bir diğer husus ise scroll listener yapmayı sağlayan EndlessRecyclerViewScrollListener classıdır. Bu class aşağıda ki gibidir.
EndlessRecyclerViewScrollListener.kt
abstract class EndlessRecyclerViewScrollListener(private var visibleThreshold: Int = 5): RecyclerView.OnScrollListener() {
private var currentPage = 0
private var previousTotalItemCount = 0
private var loading = true
private val startingPageIndex = 0
private var mLayoutManager: RecyclerView.LayoutManager? = null
constructor(visibleThreshold: Int, layoutManager: LinearLayoutManager): this(visibleThreshold) {
this.mLayoutManager = layoutManager
}
constructor(visibleThreshold: Int, layoutManager: GridLayoutManager): this(visibleThreshold) {
this.mLayoutManager = layoutManager
this.visibleThreshold = visibleThreshold * layoutManager.spanCount
}
constructor(visibleThreshold: Int, layoutManager: StaggeredGridLayoutManager): this(visibleThreshold) {
this.mLayoutManager = layoutManager
this.visibleThreshold = visibleThreshold * layoutManager.spanCount
}
fun getLastVisibleItem(lastVisibleItemPositions: IntArray): Int {
var maxSize = 0
for (i in lastVisibleItemPositions.indices) {
if (i == 0) {
maxSize = lastVisibleItemPositions[i]
} else if (lastVisibleItemPositions[i] > maxSize) {
maxSize = lastVisibleItemPositions[i]
}
}
return maxSize
}
override fun onScrolled(view: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(view, dx, dy);
}
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState);
var lastVisibleItemPosition = 0
val totalItemCount = mLayoutManager?.itemCount ?: 0
if (mLayoutManager is StaggeredGridLayoutManager) {
val lastVisibleItemPositions = (mLayoutManager as StaggeredGridLayoutManager).findLastVisibleItemPositions(null)
lastVisibleItemPosition = getLastVisibleItem(lastVisibleItemPositions)
} else if (mLayoutManager is GridLayoutManager) {
lastVisibleItemPosition = (mLayoutManager as GridLayoutManager).findLastVisibleItemPosition()
} else if (mLayoutManager is LinearLayoutManager) {
lastVisibleItemPosition = (mLayoutManager as LinearLayoutManager).findLastVisibleItemPosition()
}
if (totalItemCount < previousTotalItemCount) {
this.currentPage = this.startingPageIndex
this.previousTotalItemCount = totalItemCount
}
if (totalItemCount > previousTotalItemCount) {
previousTotalItemCount = totalItemCount
}
if (lastVisibleItemPosition + visibleThreshold > totalItemCount) {
currentPage++
onLoadMore(currentPage, totalItemCount, recyclerView)
}
}
fun resetState() {
this.currentPage = this.startingPageIndex
this.previousTotalItemCount = 0
this.loading = true
}
abstract fun onLoadMore(page: Int, totalItemsCount: Int, view: RecyclerView)
}
Soru,istek ve önerilerinizi mesutemrecelenk@gmail.com adresine yazabilirsiniz. Bir sonraki yazıda görüşmek üzere hoşça kalın...