/ recyclerview

RecyclerView Playground (2)

RecyclerView Playground (1) မှာတုန်းက LayoutManagerAdapterနဲ့ ViewHolder တွေ အကြောင်း ပြောပြခဲ့ပါတယ်။ ဒီမှာတော့ item တွေ ထည့်တာ၊ ဖျက်တာ၊ ပြင်တာ စတဲ့အကြောင်းကို ပြောပါဦးမယ်။

Notifying Adapter

RecyclerView မှာ ကျွန်တော်တို့က content ပြရုံတင်မဟုတ်ဘဲ Row တွေ insert, change, delete စတာတွေကို လုပ်ချင်ရင် data controller ဖြစ်တဲ့ adapter ကပဲ ခိုင်းလေ့ရှိပါတယ်။
Collection List ရဲ့ data ပြောင်းသွားတိုင်း Adapter ကို notify လုပ်ပေးရပါတယ်။ အဲ့အခါကျမှ onBindViewHolder က notify လုပ်ခံရတဲ့ index ကို ခေါ်ပြီး data နဲ့ view နဲ့ ပြန်bind လေ့ရှိပါတယ်။

public void setListItems(List<String> listItems) {
    this.listItems = listItems;
    //notify the whole data range has changed
    notifyDataSetChanged();
  }

အပေါ်က method က data set တစ်ခုလုံး ပြောင်းသွားကြောင်း အသိပေးတာ ဖြစ်ပြီး အောက်မှာ data အစုလိုက် ထပ်ထည့်တာ၊ တစ်နေရာ ကွက်ပြောင်းတာ၊ ဖျက်တာ စတဲ့ method တွေပါ။ Notify မလုပ်ရင်တော့ ပြောင်းသွားကြောင်း Adapter က မသိတဲ့ အတွက် ဘာမှ ဖြစ်မှာ မဟုတ်ပါဘူး။

public void addMoreListItems(List<String> newListItems) {
    this.listItems.addAll(newListItems);
    //notify there are newly added items
    notifyItemRangeChanged(listItems.size() - newListItems.size(), newListItems.size());
  }

  public void addItemAtLastPosition(String string) {
    listItems.add(string);
    //notify item is added at the last of row
    notifyItemInserted(listItems.size() - 1);
  }

  public void addItemAtFristPosition(String string) {
    listItems.add(0, string);
    //notify item is added at the first row
    notifyItemInserted(0);
  }

  public void changeItem(int position, String text) {
    listItems.set(position,text);
    notifyItemChanged(position);
  }

  public void deleteItem(int position) {
    listItems.remove(position);
    notifyItemRemoved(position);
  }

Listeners

အရင် ListView မှာကတော့ Item Click အတွက် Event Listener တွေ တစ်ခါတည်းပါပေမဲ့ RecyclerView မှာတော့ ပါမလာပါဘူး။ အဲ့အတွက် Click Event တွေ ဖမ်းချင်တဲ့အခါ Interface
တွေ သုံးလို့ရပါတယ်။ ဒီနမူနာမှာတော့ Item Click Listener ရော Item Long Click Listener ရော ထည့်ပုံပြထားပါတယ်။ ကျန်တဲ့ Layout အတွင်းက Button တွေဘာတွေကိုလည်း ဒီလိုနည်းနဲ့ Click Event တွေ ဖမ်းလည်း ရပါတယ်။

CustomClickListener ဆိုပြီး Interface တစ်ခု ဖန်တီး လိုက်ပါတယ်။

public interface CustomClickListener {
  void onItemClick(int position);

  void onItemLongClick(int position);

  void onDeleteItemClick(int position);
}

ဖျက်ဖို့အတွက် Row တစ်ခုချင်းမှာ delete button ထည့်ပါတယ်။

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    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="wrap_content"
    android:orientation="horizontal"
    android:gravity="center_vertical"
    >
  <TextView
      android:id="@+id/textView"
      android:layout_height="wrap_content"
      android:textSize="16sp"
      tools:text="A"
      android:layout_width="0dp"
      android:layout_weight="1"
      android:padding="16dp"
      />
  <ImageButton
      android:layout_width="48dp"
      android:layout_height="48dp"
      app:srcCompat="@drawable/ic_delete"
      android:id="@+id/imageButton"
      android:background="?android:attr/selectableItemBackground"
      android:layout_marginRight="16dp"
      android:layout_marginEnd="16dp"
      />
</LinearLayout>

ပြီးရင် ViewHolder classမှာ ပုံမှန် OnClickListener နဲ့ OnLongClickListener တွေကို row တစ်ခုချင်းစီမှာ ထည့်ပါတယ်။ event ကို trigger လုပ်တဲ့အခါမှ ကျွန်တော်တို့ရဲ့ Interface ကို ပြန်ပေးလိုက်ပါတယ်။

 private CustomClickListener onClickListener;

 public void setOnClickListener(CustomClickListener onClickListener) {
    this.onClickListener = onClickListener;
 }


 
  public class SimpleViewHolder extends RecyclerView.ViewHolder
      implements View.OnClickListener, View.OnLongClickListener {
    TextView textView;
    ImageButton imageButton;

    public SimpleViewHolder(View itemView) {
      super(itemView);

      textView = (TextView) itemView.findViewById(R.id.textView);
      imageButton = (ImageButton) itemView.findViewById(R.id.imageButton);

      //set normal on click listener
      itemView.setOnClickListener(this);

      //set normal on long click listener
      itemView.setOnLongClickListener(this);

      //set click listener to delete button
      imageButton.setOnClickListener(this);
    }

    @Override public void onClick(View view) {
      int position = getAdapterPosition();

      // getAdapterPosition() will be -1 if recyclerview is recalculating item range
      //if user click in that time it will return -1
      //then we will ignore the click event
      if (position == -1) return; //the rest line will not execute if position ==-1

      if (onClickListener == null) {
        return; // no listener is set
      }

      if (view.getId() == imageButton.getId()) { // click on delete button
        onClickListener.onDeleteItemClick(position);
      } else { //click on item
        onClickListener.onItemClick(position);
      }
    }

    @Override public boolean onLongClick(View view) {

      int position = getAdapterPosition();

      // getAdapterPosition() will be -1 if recyclerview is recalculating item range
      //if user click in that time it will return -1
      //then we will ignore the click event
      if (position == -1) return false; // nothing to do

      if (onClickListener == null) {
        return false; // no listener is set
      }
      onClickListener.onItemLongClick(position);

      return true;
    }
  }

ဒီမှာတော့ Interface method တွေက နှိပ်လိုက်တဲ့ position ပြန်ပေမဲ့ ကိုယ့်စိတ်ကြိုက် ကျန်တာတွေ data တွေ ပြန်လို့ရပါတယ်။ ဒါကြောင့်မို့ RecyclerView ဟာ customizable ကြိုက်သလို လုပ်လို့ရတယ်လို့ ပြောတာပါ။

ပြီးမှ Activity (သို့) Fragment ကနေ ListView မှာလို Listener ထည့်ပေးလိုက်ရုံပဲ။ Example Repo မှာ နမူနာ ထည့်တာ၊ ဖျက်တာတွေ လုပ်ထားပါတယ်။

adapter.setOnClickListener(new CustomClickListener() {
      @Override public void onItemClick(int position) {
         Toast.makeText(this, String.format(Locale.ENGLISH, "Normal Click at position %d", position),
        Toast.LENGTH_SHORT).show();
      }

      @Override public void onItemLongClick(int position) {
Toast.makeText(this, String.format(Locale.ENGLISH, "Long Click at position %d", position),
        Toast.LENGTH_SHORT).show();
      }

      @Override public void onDeleteItemClick(int position) {
  Toast.makeText(this, String.format(Locale.ENGLISH, "Delete Item at position %d", position),
        Toast.LENGTH_SHORT).show();
    adapter.deleteItem(position);
      }
    });

You can find the current repo here for download.

နောက်လာမဲ့ RecyclerView Playground (3) မှာတော့ HeaderFooter တွေ မတူတဲ့ ViewType တွေနဲ့ အလုပ်လုပ်ပုံတွေ ပြောပါဦးမယ်။

Reference