RecyclerView Playground (1)

Android App တွေမှာ list ပြချင်တဲ့ အခါ ကျွန်တော်တို့တွေ ListView (သို့) RecyclerView ကို သုံးလေ့ရှိပါတယ်။ RecyclerView ကို ListView အစား နောက်ပိုင်းမှာ သုံးလာကြတာက သူ့ကို စိတ်ကြိုက်ပြင်လို့ရတဲ့အတွက် အဆင်မြှင့်ရှုပ်ထွေးတဲ့ ဒေတာတွေပါတဲ့ list တွေကို ပြတာမှာ သုံးကြပါတယ်။ ListView မှာ layout တွေကို item တစ်ခု ပြတိုင်း ပြန်ပြန်ကြေငြာတာမျိုးကြောင့် listက တအားများတာဆိုရင် ထစ်နေတာမျိုးတွေ ဖြစ်တတ်တယ်။ အဲ့ဒီအတွက် View ကို cacheလုပ်ပြီ: သုံးရတာမျိုး ရှိပေမဲ့ RecyclerView ကတော့ ဒါကို အစောကတည်းက ViewHolder pattern နဲ့ ထောက်ပံ့ပေးထားတယ်။ List ကို vertical ပြချင်တာပဲဖြစ်ဖြစ် horizontal ပြချင်တာပဲဖြစ်ဖြစ် grid ပြတာပဲဖြစ်ဖြစ် LayoutManager ပြောင်းလိုက်တာနဲ့ အဆင်ပြေပါတယ်။ ဆိုတာကတော့ ListView က မီးဖိုချောင်သုံးဓားဆိုရင် RecyclerView က Swiss Army Knife နဲ့ တူပါတယ်။

RecyclerViewကို သုံးမယ်ဆိုရင် ​ကိုယ့် project ရဲ့ build.gradle မှာ

dependencies {  
  // Other dependencies 

  // RecyclerView
  compile 'com.android.support:recyclerview-v7:24.2.0'
}

ကျွန်တော်တို့ သုံးချင်တဲ့ layout xml မှာ RecyclerView ကို ဒါမျိုး ထည့်သုံးရုံပါပဲ။

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

ပြီးရင် layout ကို သုံးမဲ့ Activity (သို့) Fragment RecyclerView ကို တခြား view တွေ လိုပဲ findViewById နဲ့ ကြေငြာပေးပါ။ RecyclerView အလုပ်လုပ်ဖို့အတွက် LayoutManager ရယ် Adapter ရယ် ထည့်ပေးဖို့ လိုပါတယ်။ LayoutManager မှာ ဆိုရင်

  • LinearLayoutManager (ဒေါင်လိုက် or အလျားလိုက် ဇယား)
  • GridLayoutManager (ဇယားအကွက်ပုံစံ)
  • StaggeredGridLayoutManager (မညီမညာ ဇယားကွက်ပုံစံ)

ဆိုပြီး ၃ မျိုးရှိပါတယ်။ ကိုယ့်ရဲ့ list က ရိုးရိုးပုံစံ အလျားလိုက် သို့ ဒေါင်လိုက် ဆိုရင် LinearLayoutManager ကို RecyclerView အတွက် သတ်မှတ်ပေးရမှာဖြစ်ပြီး ဇယားကွက်ဆိုရင်တော့ GridLayoutManager ထည့်ပေးလိုက်ရုံပါပဲ။ ဒါမှမဟုတ် Grid အကွက်တွေ မညီမညာ အတိုအရှည် မတူတာမျိုးဆိုရင်တော့ StaggeredGridLayoutManager ကို သုံးနိုင်ပါတယ်။ အဲ့အတွက်လည်း RecyclerView ရဲ့ API မှာ setLayoutManager ဆိုတဲ့ method ရှိပြီးသားပါ။

public class MainActivity extends AppCompatActivity {  
  RecyclerView rvListItems;

  @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    rvListItems = (RecyclerView) findViewById(R.id.rvListItems);

    //Vertical Orientation
    LinearLayoutManager verticalLayoutManager =
        new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);

    rvListItems.setLayoutManager(verticalLayoutManager);
  }
}

RecyclerView ကို LayoutManager သတ်မှတ်ပေး ပြီးပြီးဆိုရင်တော့ ကျွန်တော်တို့ ပြချင်တဲ့ list item တွေအတွက် Adapter ရေးပေးဖို့ လိုပါတယ်။ Adapter ရေးမယ် ဆိုရင်တော့ RecyclerView.Adapter<VH extends ViewHolder> ဆိုတဲ့ class ကို extend လုပ်ပေးရပါမယ်။ < > ကတော့ RecyclerView.ViewHolder ကို extend လုပ်ထားတဲ့ မည့်သည့် class ကိုမဆို ထည့်ပေးလို့ရတယ်လို့ ဆိုတာပါ။ အရင်ဆုံး SimpleListAdapter ဆိုပြီး RecyclerView.Adapter ကို extend လုပ်လိုက်ပါတယ်။ extend လုပ်တာနဲ့ပဲ သူ့ class ရဲ့ မသုံးမနေရ abstract methods သုံးခုကို IDE က ရေးဖို့ (override လုပ်တယ်လို့လည်း ခေါ်ပါတယ်) ပြောပါလိမ့်မယ်။ အောက်က ဘာမှ ပြင်မရေးရသေးဘဲ အဲ့ method သုံးခုနဲ့ class လေးပါ။

 private class SimpleListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
      return null;
    }

    @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

    }
    @Override public int getItemCount() {
      return 0;
    }
  }

onCreateViewHolder ဆိုတဲ့ method ကို List item ရဲ့ View Type ပြောင်းသွားလို့ layout လိုတိုင်း ခေါ်ပါတယ်။ @param parent ကတော့ Adapter ရဲ့ position သိပြီးနောက် View ပေါင်းထည့်မည့် ViewGroup ပါ။ @param viewType ကတော့ တကယ်လို့ List Item မှာ view အမျိုးအစား တစ်ခုထက် ပိုခဲ့ရင် အဲ့ အမျိုးအစားလိုက် layout ကို ပြောင်းပေးချင်တဲ့အခါမှာ သုံးလို့ရပါတယ်။ အဲ့အတွက်တော့ getItemViewType(int) ဆိုတဲ့ method ကိုလည်း override လုပ်ပေးရမှာပါ။ အဲ့ဒါကိုလည်း နောက်ကျရင် ရှင်းပြပေးပါ့မယ်။

return type ပြန်ရမှာ ဖြစ်တဲ့အတွက် ViewHolder ပြန်ပေးရမယ်။

onBindViewHolder မှာတော့ ရလာတဲ့ onCreateViewHolder က view တွေကို data set ရဲ့ position အလိုက် item နဲ့ bind ပေးတာပါ။

getItemCount ကတော့ Adapter ရဲ့ စုစုပေါင်း List Item အရေအတွက်ကို ပြန်ပေးရမှာပါ။

Adapter တဲ့ လိုအပ်တဲ့ Item View တစ်ခုချင်းအတွက် row_simple_list.xml ဆိုတဲ့ layout တစ်ခု ဖန်တီးလိုက်ပါတယ်။

<?xml version="1.0" encoding="utf-8"?>  
<TextView xmlns:android="http://schemas.android.com/apk/res/android"  
    android:id="@+id/textView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    />

ပြီး​တော့ SimpleViewHolderဆိုတဲ့ class တစ်ခုကို ဖန်တီးပါမယ်။ class file သပ်သပ်နဲ့ပဲရေး SimpleListAdapter ထဲမှာ inner class နဲ့ ရေးလည်း ရပါတယ်။ ကျွန်တော်ကတော့ ဒီမှာ inner class အနေနဲ့ပဲ ရေးလိုက်ပါမယ်။

 public class SimpleViewHolder extends RecyclerView.ViewHolder {
    TextView textView;

    public SimpleViewHolder(View itemView) {
      super(itemView);
      textView = (TextView) itemView.findViewById(R.id.textView);
    }
  }

ဒါဆိုရင်တော့ Adapter ထဲမှာပြင်ပြီး ရေးလို့ရပါပြီ။ onCreateViewHolder မှာ ViewHolder ထည့်ပြီ: onBindViewHolder မှာ View ထဲကို Data ထည့်ပေးရုံပါပဲ။

public class SimpleListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {  
  private List<String> listItems;

  public SimpleListAdapter(List<String> listItems) {
    this.listItems = listItems;
  }

  @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view =
        LayoutInflater.from(parent.getContext()).inflate(R.layout.row_simple_list, parent, false);

    return new SimpleViewHolder(view);
  }

  @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    String string = listItems.get(position);
    SimpleViewHolder simpleViewHolder = (SimpleViewHolder) holder;
    simpleViewHolder.textView.setText(string);
  }

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

  public class SimpleViewHolder extends RecyclerView.ViewHolder {
    TextView textView;

    public SimpleViewHolder(View itemView) {
      super(itemView);
      textView = (TextView) itemView.findViewById(R.id.textView);
    }
  }
}

getItemCount မှာ List ရဲ့ ရှိသလောက် size ကို return ပြန်ထားပေးသလို onCreateView မှာ ViewHolder အသစ်တစ်ခု construct လုပ်ပြီ: ပြန်ထားပေးရပါတယ်။ onBindView မှာတော့ List ထဲကနေ position အလိုက် ရလာတဲ့ String ကို TextView မှာ bind ပေးပြီးဆိုတော့ ကျွန်တော်တို့ရဲ့ Adapter အဆင်သင့်ဖြစ်ပါပြီ။ MainActivity မှာ ခေါ်သုံးလိုက်ရအောင်။

  private RecyclerView rvListItems;
  private SimpleListAdapter adapter;

  @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    rvListItems = (RecyclerView) findViewById(R.id.rvListItems);

    //Vertical Orientation
    LinearLayoutManager verticalLayoutManager =
        new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);

    rvListItems.setLayoutManager(verticalLayoutManager);

    List<String> strings = Arrays.asList("A", "B", "C", "D", "E", "F");
    adapter = new SimpleListAdapter(strings);

    rvListItems.setAdapter(adapter);
  }y`
}

MainActivity မှာ SimpleListAdapter ကို Constructor ကနေ တစ်ဆင့် initialise လုပ်ပြီ: data ပါ တခါတည်း ထည့်ပေးလိုက်ပါတယ်။ ဒါဆိုရင်တော့ ရိုးရိုးရှင်းရှင်း data ပြရုံပဲပါ။

နောက်လာမဲ့ အဆက်တွေမှာတော့ List Item တစ်ခုချင်း နှိပ်တာတွေ Header, Footer ထည့်တာတွေ ရေးပါဦးမယ်။

You can find the current repo here for download.

Reference