Upgrade to Pro — share decks privately, control downloads, hide ads and more …

droidgirls RecyclerView

Yuki Anzai
December 21, 2016

droidgirls RecyclerView

Yuki Anzai

December 21, 2016
Tweet

More Decks by Yuki Anzai

Other Decks in Technology

Transcript

  1. • blog : Y.A.M ͷࡶهா • y-anz-m.blogspot.com • twitter :

    @yanzm ʢ΍Μ͟Ήʣ • uPhyca Inc. (גࣜձࣾ΢ϑΟΧ) ͋Μ͍͟Ώ͖
  2. ListView vs RecyclerView ListView RecyclerView ۠੾Γઢ ⚪ ࣗ෼Ͱ࣮૷ listSelector ⚪

    º onItemClick ⚪ ࣗ෼Ͱ࣮૷ choiceMode ⚪ º BOESPJETVQQPSUWXJEHFU%JWJEFS*UFN%FDPSBUJPO͕Ͱ௥Ճ͞Ε·ͨ͠
  3. ListView vs RecyclerView ListView RecyclerView Filter ⚪ ࣗ෼Ͱ࣮૷ FadingEdge ⚪

    ࣗ෼Ͱ࣮૷ Header, Footer ⚪ ࣗ෼Ͱ࣮૷ StaggeredGrid º ⚪
  4. ListView vs RecyclerView ListView RecyclerView ௥Ճɾ࡟আͷ Ξχϝʔγϣϯ ࣗ෼Ͱ࣮૷ ⚪ Swipe

    to Dismiss ࣗ෼Ͱ࣮૷ ⚪ Drag & Drop ࣗ෼Ͱ࣮૷ ⚪ ԣεΫϩʔϧ഑ஔ º ⚪
  5. public class ViewHolder extends RecyclerView.ViewHolder {
 
 private static final

    int LAYOUT_ID = android.R.layout.simple_list_item_1;
 
 @NonNull
 public static ViewHolder create(@NonNull LayoutInflater inflater,
 ViewGroup parent) {
 return new ViewHolder(inflater.inflate(LAYOUT_ID, parent, false));
 }
 
 final TextView textView;
 
 private ViewHolder(View itemView) {
 super(itemView);
 textView = (TextView) itemView.findViewById(android.R.id.text1);
 }
 } ViewHolder
  6. public class SimpleAdapter extends RecyclerView.Adapter<ViewHolder> {
 
 @NonNull
 private final

    List<String> data;
 
 public SimpleAdapter(@NonNull List<String> data) {
 this.data = data;
 }
 
 @Override
 public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
 final LayoutInflater inflater = LayoutInflater.from(parent.getContext()) return ViewHolder.create(inflater, parent);
 }
 
 @Override
 public void onBindViewHolder(ViewHolder holder, int position) {
 final String text = data.get(position);
 holder.textView.setText(text);
 }
 
 @Override
 public int getItemCount() {
 return data.size();
 }
 } Adapter
  7. public class MainActivity extends AppCompatActivity {
 
 @Override
 protected void

    onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 
 RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view) recyclerView.setHasFixedSize(true);
 
 List<String> data = new ArrayList<>();
 for (int i = 0; i < 30; i++) {
 data.add("Item : " + i);
 }
 
 final SimpleAdapter adapter = new SimpleAdapter(data);
 recyclerView.setAdapter(adapter);
 }
 } Activity
  8. DividerItemDecoration • v25.0.0 Ͱ DividerItemDecoration ͕௥Ճ͞Εͨ ͷͰͦΕΛ࢖͏ͷ͕؆୯ • https://developer.android.com/reference/ android/support/v7/widget/

    DividerItemDecoration.html • Ұ൪࠷ޙͷΞΠςϜͷԼʹ΋ඳը͞Εͯ͠·͏ recyclerView.addItemDecoration( new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
  9. ΞΠςϜ༻ͷViewͷOffsetΛࢦఆ final int offset = (int) (8 * getResources().getDisplayMetrics().density);
 


    RecyclerView.ItemDecoration itemDecoration = new RecyclerView.ItemDecoration() {
 @Override
 public void getItemOffsets(Rect outRect, View view,
 RecyclerView parent, RecyclerView.State state) {
 outRect.set(offset, offset, offset, offset);
 }
 };
 recyclerView.addItemDecoration(itemDecoration);
  10. ΞΠςϜ༻ͷViewͷOffsetΛࢦఆ RecyclerView.ItemDecoration itemDecoration = new RecyclerView.ItemDecoration() {
 @Override
 public void

    getItemOffsets(Rect outRect, View view,
 RecyclerView parent, RecyclerView.State state) {
 int position = ((RecyclerView.LayoutParams) view.getLayoutParams())
 .getViewLayoutPosition();
 if (position == 0) {
 outRect.set(offset, offset, offset, offset);
 } else {
 outRect.set(offset, 0, offset, offset);
 }
 }
 };
 
 recyclerView.addItemDecoration(itemDecoration);
  11. public class DividerDecoration extends RecyclerView.ItemDecoration {
 
 private final Paint

    paint = new Paint(Paint.ANTI_ALIAS_FLAG);
 private final int dividerHeight;
 
 public DividerDecoration(Resources res) {
 paint.setColor(Color.GRAY);
 dividerHeight = (int) (4 * res.getDisplayMetrics().density);
 }
 
 @Override
 public void getItemOffsets(Rect outRect, View view, RecyclerView parent, 
 RecyclerView.State state) {
 final int position = ((RecyclerView.LayoutParams) view.getLayoutParams())
 .getViewLayoutPosition();
 // Ґஔ͕2൪໨Ҏ߱ͳΒ্෦ʹdividerΛඳը͍ͨ͠ͷͰɺ
 // divider෼্͚ͩΛ͚͋Δ
 
 int top = position == 0 ? 0 : dividerHeight;
 outRect.set(0, top, 0, 0);
 } DividerΛඳը
  12. @Override
 public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {


    super.onDrawOver(c, parent, state);
 // ΞΠςϜͷϏϡʔΑΓ্ʹඳը͞ΕΔ
 
 
 final RecyclerView.LayoutManager manager = parent.getLayoutManager();
 final int left = parent.getPaddingLeft();
 final int right = parent.getWidth() - parent.getPaddingRight();
 final int childCount = parent.getChildCount();
 for (int i = 1; i < childCount; i++) {
 final View child = parent.getChildAt(i);
 final RecyclerView.LayoutParams params =
 (RecyclerView.LayoutParams) child.getLayoutParams();
 if (params.getViewLayoutPosition() == 0) {
 continue;
 }
 
 // ViewCompat.getTranslationY()ΛೖΕͳ͍ͱ
 // ௥Ճɾ࡟আͷΞχϝʔγϣϯ࣌ͷҐஔ͕มʹͳΔ
 final int top = manager.getDecoratedTop(child)
 - params.topMargin + Math.round(ViewCompat.getTranslationY(child));
 final int bottom = top + dividerHeight;
 c.drawRect(left, top, right, bottom, paint);
 }
 }
 }
 DividerΛඳը
  13. public class SimpleAdapter extends RecyclerView.Adapter<ViewHolder> {
 
 …
 
 protected

    void onItemClicked(String text) {
 }
 
 @Override
 public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
 final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
 final ViewHolder holder = ViewHolder.create(inflater, parent);
 holder.itemView.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View v) {
 final int position = holder.getAdapterPosition();
 final String text = data.get(position);
 onItemClicked(text);
 }
 });
 return holder;
 }
 
 …
 } OnItemClick
  14. public class MainActivity extends AppCompatActivity {
 
 @Override
 protected void

    onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 
 …
 
 final SimpleAdapter adapter = new SimpleAdapter(data) {
 @Override
 protected void onItemClicked(String text) {
 super.onItemClicked(text);
 Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show();
 }
 };
 recyclerView.setAdapter(adapter); OnItemClick
  15. notify** • notifyItemChanged(int position) • positionͷҐஔͷΞΠςϜͷมߋ͞Εͨ • notifyItemInserted(int position) •

    posiitonͷҐஔʹΞΠςϜ͕௥Ճ͞Εͨ • notifyItemRemoved(int position) • positionͷҐஔͷΞΠςϜ͕࡟আ͞Εͨ
  16. notify** • notifyItemMoved(int fromPosition, int toPosition) • fromPositionʹ͋ͬͨΞΠςϜ͕toPositionʹҠಈͨ͠ • notifyItemRangeChanged(int

    positionStart, int itemCount) • positionStart͔ΒitemCountݸͷΞΠςϜ͕มߋ͞Εͨ • notifyItemRangeInserted(int positionStart, int itemCount) • positionStartʹitemCountݸͷΞΠςϜ͕௥Ճ͞Εͨ
  17. public abstract class ArrayAdapter<T, VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {


    
 private final Object lock = new Object();
 private final List<T> objects;
 
 public ArrayAdapter() {
 this(new ArrayList<T>());
 }
 
 public ArrayAdapter(List<T> objects) {
 this.objects = objects;
 }
 
 public void add(@NonNull T object) {
 final int position;
 synchronized (lock) {
 position = objects.size();
 objects.add(object);
 }
 notifyItemInserted(position);
 }
 ArrayAdapterతͳRecyclerView༻Adapter
  18. public void addAll(@NonNull Collection<? extends T> collection) {
 final int

    itemCount = collection.size();
 final int positionStart;
 synchronized (lock) {
 positionStart = objects.size();
 objects.addAll(collection);
 }
 notifyItemRangeInserted(positionStart, itemCount);
 }
 
 public void insert(@NonNull T object, int index) {
 synchronized (lock) {
 objects.add(index, object);
 }
 notifyItemInserted(index);
 }
 
 public void remove(@NonNull T object) {
 final int position = objects.indexOf(object);
 synchronized (lock) {
 objects.remove(object);
 }
 notifyItemRemoved(position);
 }
 } ArrayAdapterతͳRecyclerView༻Adapter
  19. Header ͱ Footer Λͭ͘Δ public class SimpleAdapter2 extends RecyclerView.Adapter {


    
 private static final int VIEW_TYPE_HEADER = 0;
 private static final int VIEW_TYPE_FOOTER = 1;
 private static final int VIEW_TYPE_ITEM = 2;
 
 …
 
 @Override
 public int getItemCount() {
 return data.size() + 2; // header + footer
 }
 
 @Override
 public int getItemViewType(int position) {
 if (position == 0) {
 return VIEW_TYPE_HEADER;
 }
 if (position == getItemCount() - 1) {
 return VIEW_TYPE_FOOTER;
 }
 return VIEW_TYPE_ITEM;
 }
 }
  20. Header ͱ Footer Λͭ͘Δ public class SimpleAdapter2 extends RecyclerView.Adapter {


    
 …
 
 @Override
 public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
 final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
 switch (viewType) {
 case VIEW_TYPE_HEADER: {
 return HeaderViewHolder.create(inflater, parent);
 }
 case VIEW_TYPE_FOOTER: {
 return FooterViewHolder.create(inflater, parent);
 }
 case VIEW_TYPE_ITEM: {
 final ViewHolder holder = ViewHolder.create(inflater, parent);
 holder.itemView.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View v) {
 final int position = holder.getAdapterPosition();
 final String text = data.get(position);
 onItemClicked(text);
 }
 });
 return holder;
 }
 }
 
 return null;
 }
  21. Header ͱ Footer Λͭ͘Δ public class SimpleAdapter2 extends RecyclerView.Adapter {


    
 …
 
 @Override
 public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
 if (holder instanceof ViewHolder) {
 final ViewHolder viewHolder = (ViewHolder) holder;
 final String text = data.get(position);
 viewHolder.textView.setText(text);
 }
 }
  22. • γϯϓϧͳList, Grid → • ListView, GridView • RecyclerView •

    ListView, GridView Ͱ͸ແཧͳ഑ஔ → • RecyclerView ·ͱΊ