Slide 1

Slide 1 text

RecyclerView droid girls meetup #2 Yuki Anzai (@yanzm)

Slide 2

Slide 2 text

• blog : Y.A.M ͷࡶهா • y-anz-m.blogspot.com • twitter : @yanzm ʢ΍Μ͟Ήʣ • uPhyca Inc. (גࣜձࣾ΢ϑΟΧ) ͋Μ͍͟Ώ͖

Slide 3

Slide 3 text

RecyclerView A flexible view for providing a limited window into a large data set.

Slide 4

Slide 4 text

RecyclerView RecyclerView ͸ αϙʔτϥΠϒϥϦ IUUQTEFWFMPQFSBOESPJEDPNUPQJDMJCSBSJFTTVQQPSU MJCSBSZGFBUVSFTIUNMWSFDZDMFSWJFX

Slide 5

Slide 5 text

RecyclerView େن໛ͳσʔληοτʹɺ ݶఆ͞Εͨ΢Οϯυ΢Λ ఏڙ͢ΔͨΊͷॊೈͳϏϡʔ

Slide 6

Slide 6 text

RecyclerView େن໛ͳσʔληοτͷҰ෦Λ ϏϡʔΛ࠶ར༻͠ͳ͕Β දࣔ͢ΔͨΊͷίϯϙʔωϯτ

Slide 7

Slide 7 text

RecyclerView ListViewͱ͔GridView Έ͍ͨͳ΍ͭ

Slide 8

Slide 8 text

RecyclerViewͷߏ੒ • RecyclerView • σʔλΛදࣔ͢ΔͨΊͷεΫϩʔϧՄೳͳ View

Slide 9

Slide 9 text

• RecyclerView • σʔλΛදࣔ͢ΔͨΊͷεΫϩʔϧՄೳͳ View • RecyclerView.LayoutManager • ΞΠςϜ༻ͷϏϡʔͷαΠζΛܭࢉ͠ɺ഑ ஔ͢Δ RecyclerViewͷߏ੒

Slide 10

Slide 10 text

• RecyclerView.Adapter • RecyclerViewʹදࣔ͢ΔσʔληοτΛ ؅ཧ͠ɺΞΠςϜ༻ͷViewʹσʔλΛඥ ͚ͮΔ RecyclerViewͷߏ੒

Slide 11

Slide 11 text

• RecyclerView.Adapter • RecyclerViewʹදࣔ͢ΔσʔληοτΛ ؅ཧ͠ɺΞΠςϜ༻ͷViewʹσʔλΛඥ ͚ͮΔ • RecyclerView.ViewHolder • ΞΠςϜ༻ͷϏϡʔͱϝλσʔλΛอ࣋͢ Δ RecyclerViewͷߏ੒

Slide 12

Slide 12 text

RecyclerViewͷߏ੒ RecyclerView LayoutManager Adapter ࢠϏϡʔ഑ஔ ࢠϏϡʔ ʢViewHolderʣ ʹσʔλඥ෇ Recycler ViewHolderΛ࠶ར༻ ࠶ར༻͢Δ ViewHolder

Slide 13

Slide 13 text

ListViewͷߏ੒ RecyclerView LayoutManager Adapter ࢠϏϡʔ഑ஔ ࢠϏϡʔ ʢViewHolderʣ ʹσʔλඥ෇ Recycler ViewHolderΛ࠶ར༻ ࠶ར༻͢Δ ViewHolder ListView ListAdapter

Slide 14

Slide 14 text

ListViewͷߏ੒ ListView = RecyclerView + LayoutManager + Recycler + ͦͷଞ΋Ζ΋Ζͷػೳ ListAdapter = Adapter + ViewHolder

Slide 15

Slide 15 text

ListViewͷߏ੒ ListView = RecyclerView + LayoutManager + Recycler + ͦͷଞ΋Ζ΋Ζͷػೳ ListAdapter = Adapter + ViewHolder

Slide 16

Slide 16 text

ListView vs RecyclerView ListView RecyclerView ۠੾Γઢ ⚪ ࣗ෼Ͱ࣮૷ listSelector ⚪ º onItemClick ⚪ ࣗ෼Ͱ࣮૷ choiceMode ⚪ º BOESPJETVQQPSUWXJEHFU%JWJEFS*UFN%FDPSBUJPO͕Ͱ௥Ճ͞Ε·ͨ͠

Slide 17

Slide 17 text

ListView vs RecyclerView ListView RecyclerView Filter ⚪ ࣗ෼Ͱ࣮૷ FadingEdge ⚪ ࣗ෼Ͱ࣮૷ Header, Footer ⚪ ࣗ෼Ͱ࣮૷ StaggeredGrid º ⚪

Slide 18

Slide 18 text

ListView vs RecyclerView ListView RecyclerView ௥Ճɾ࡟আͷ Ξχϝʔγϣϯ ࣗ෼Ͱ࣮૷ ⚪ Swipe to Dismiss ࣗ෼Ͱ࣮૷ ⚪ Drag & Drop ࣗ෼Ͱ࣮૷ ⚪ ԣεΫϩʔϧ഑ஔ º ⚪

Slide 19

Slide 19 text

RecyclerViewͷ Ұ൪γϯϓϧͳ ࢖͍ํ

Slide 20

Slide 20 text

gradle ͷઃఆ dependencies {
 …
 
 compile 'com.android.support:recyclerview-v7:25.1.0'
 }

Slide 21

Slide 21 text

࠷௿ݶඞཁͳ΋ͷ • RecyclerView • RecyclerView.LayoutManager • RecyclerView.Adapter • RecyclerView.ViewHolder

Slide 22

Slide 22 text

࠷௿ݶඞཁͳ΋ͷ • RecyclerView • RecyclerView.LayoutManager • RecyclerView.Adapter • RecyclerView.ViewHolder

Slide 23

Slide 23 text

RecyclerView + LayoutManager

Slide 24

Slide 24 text

Slide 25

Slide 25 text

RecyclerView + LayoutManager

Slide 26

Slide 26 text

࠷௿ݶඞཁͳ΋ͷ • RecyclerView • RecyclerView.LayoutManager • RecyclerView.Adapter • RecyclerView.ViewHolder

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

public class SimpleAdapter extends RecyclerView.Adapter {
 
 @NonNull
 private final List data;
 
 public SimpleAdapter(@NonNull List 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

Slide 29

Slide 29 text

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 data = new ArrayList<>();
 for (int i = 0; i < 30; i++) {
 data.add("Item : " + i);
 }
 
 final SimpleAdapter adapter = new SimpleAdapter(data);
 recyclerView.setAdapter(adapter);
 }
 } Activity

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

LinearLayoutManager GridLayoutManager StaggeredGridLayoutManager

Slide 32

Slide 32 text

LinearLayoutManager • ઃఆ߲໨ • orientation • reverseLayout • stackFromEnd

Slide 33

Slide 33 text

orientation • σϑΥϧτ͸LinearLayoutManager.VERTICAL 
 new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false); layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); PS PS

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

app:reverseLayout="true" app:stackFromEnd="true"

Slide 36

Slide 36 text

GridLayoutManager • ઃఆ߲໨ • spanCount • orientation • reverseLayout • stackFromEnd

Slide 37

Slide 37 text

spanCount • ྻ਺ɺσϑΥϧτ͸1 
 new GridLayoutManager(this, 2); layoutManager.setSpanCount(2); PS PS

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

StaggeredGridLayoutManager • ઃఆ߲໨ • spanCount • orientation • reverseLayout

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

ItemDecorationͰ DividerΛ͚ͭΔ

Slide 42

Slide 42 text

DividerItemDecoration • v25.0.0 Ͱ DividerItemDecoration ͕௥Ճ͞Εͨ ͷͰͦΕΛ࢖͏ͷ͕؆୯ • https://developer.android.com/reference/ android/support/v7/widget/ DividerItemDecoration.html • Ұ൪࠷ޙͷΞΠςϜͷԼʹ΋ඳը͞Εͯ͠·͏ recyclerView.addItemDecoration( new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));

Slide 43

Slide 43 text

ItemDecoration • ૷০Λߦ͏ͨΊͷΫϥε • ΞΠςϜ༻ͷViewͷoffsetΛࢦఆ • onDraw()ͰRecyclerViewͷԼʹඳը • onDrawOver()ͰRecyclerVieͷ্ʹඳը

Slide 44

Slide 44 text

ΞΠςϜ༻ͷ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);

Slide 45

Slide 45 text

No content

Slide 46

Slide 46 text

ΞΠςϜ༻ͷ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);

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

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Λඳը

Slide 49

Slide 49 text

@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Λඳը

Slide 50

Slide 50 text

No content

Slide 51

Slide 51 text

onItemClick

Slide 52

Slide 52 text

OnItemClick • ํ๏͕͍͔ͭ͋͘Δ • ViewHolderͷitemViewʹ View.setOnClickListener • ItemDecorationͰλοϓ͞ΕͨΞΠςϜͷ ҐஔʹselectorΛඳը

Slide 53

Slide 53 text

OnItemClick • ํ๏͕͍͔ͭ͋͘Δ • ViewHolderͷitemViewʹ View.setOnClickListener • ItemDecorationͰλοϓ͞ΕͨΞΠςϜͷ ҐஔʹselectorΛඳը v17 leanback library ͸ͬͪ͜

Slide 54

Slide 54 text

public class SimpleAdapter extends RecyclerView.Adapter {
 
 …
 
 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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

σʔλͷ௥Ճɾ࡟আɾมߋ

Slide 57

Slide 57 text

notify** • ArrayAdapterʹ૬౰͢Δ΋ͷ͸༻ҙ͞Ε͍ͯͳ͍ • σʔλͷ௥Ճɾ࡟আɾมߋ࣌ʹ͸notifyItem**()ΛݺͿ • notifyDataSetChanged()͸ͦΕҎ֎ͷͱ͖͚ͩʹ͢Δ

Slide 58

Slide 58 text

notify** • notifyItemChanged(int position) • positionͷҐஔͷΞΠςϜͷมߋ͞Εͨ • notifyItemInserted(int position) • posiitonͷҐஔʹΞΠςϜ͕௥Ճ͞Εͨ • notifyItemRemoved(int position) • positionͷҐஔͷΞΠςϜ͕࡟আ͞Εͨ

Slide 59

Slide 59 text

notify** • notifyItemMoved(int fromPosition, int toPosition) • fromPositionʹ͋ͬͨΞΠςϜ͕toPositionʹҠಈͨ͠ • notifyItemRangeChanged(int positionStart, int itemCount) • positionStart͔ΒitemCountݸͷΞΠςϜ͕มߋ͞Εͨ • notifyItemRangeInserted(int positionStart, int itemCount) • positionStartʹitemCountݸͷΞΠςϜ͕௥Ճ͞Εͨ

Slide 60

Slide 60 text

notify** • notifyItemRangeRemoved(int positionStart, int itemCount) • positionStart͔ΒitemCountݸͷΞΠςϜ͕࡟আ͞Εͨ • notifyDataSetChanged() • σʔληοτ͕มߋ͞Εͨ

Slide 61

Slide 61 text

public abstract class ArrayAdapter extends RecyclerView.Adapter {
 
 private final Object lock = new Object();
 private final List objects;
 
 public ArrayAdapter() {
 this(new ArrayList());
 }
 
 public ArrayAdapter(List 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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

ItemViewType

Slide 64

Slide 64 text

getItemViewType() • ϨΠΞ΢τͷछྨʢViewHolder ͷछྨʣʹԠͯ͡ผͷ஋ Λฦ͢Α͏ʹ͢Δ • σʔλͷछྨͰ͸ͳ͍ • ಉ͡ itemViewType Ͱ ViewHolder ͕࠶ར༻͞ΕΔ

Slide 65

Slide 65 text

Header ͱ Footer Λͭ͘Δ • ϨΠΞ΢τͷछྨʢViewHolder ͷछྨʣʹԠͯ͡ผͷ஋ Λฦ͢Α͏ʹ͢Δ • σʔλͷछྨͰ͸ͳ͍ • ಉ͡ itemViewType Ͱ ViewHolder ͕࠶ར༻͞ΕΔ

Slide 66

Slide 66 text

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;
 }
 }

Slide 67

Slide 67 text

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;
 }

Slide 68

Slide 68 text

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);
 }
 }

Slide 69

Slide 69 text

·ͱΊ

Slide 70

Slide 70 text

• γϯϓϧͳList, Grid → • ListView, GridView • RecyclerView • ListView, GridView Ͱ͸ແཧͳ഑ஔ → • RecyclerView ·ͱΊ