{"id":1194,"date":"2019-04-16T00:44:16","date_gmt":"2019-04-15T15:44:16","guid":{"rendered":"https:\/\/www.charlezz.com\/?p=1194"},"modified":"2019-06-13T18:57:39","modified_gmt":"2019-06-13T09:57:39","slug":"recyclerview%ec%97%90-selection-%eb%9d%bc%ec%9d%b4%eb%b8%8c%eb%9f%ac%eb%a6%ac%eb%a5%bc-%ec%82%ac%ec%9a%a9%ed%95%98%ea%b8%b0","status":"publish","type":"post","link":"https:\/\/charlezz.com\/?p=1194","title":{"rendered":"RecyclerView\uc5d0 Selection \ub77c\uc774\ube0c\ub7ec\ub9ac\ub97c \uc0ac\uc6a9\ud558\uae30"},"content":{"rendered":"<h1>Selection<\/h1>\n<p><a href=\"https:\/\/www.charlezz.com\/?attachment_id=1198\" rel=\"attachment wp-att-1198\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/www.charlezz.com\/wordpress\/wp-content\/uploads\/2019\/04\/Screenshot_1555342895-576x1024.png\" alt=\"\" width=\"576\" height=\"1024\" class=\"aligncenter size-large wp-image-1198\" srcset=\"https:\/\/charlezz.com\/wordpress\/wp-content\/uploads\/2019\/04\/Screenshot_1555342895-576x1024.png 576w, https:\/\/charlezz.com\/wordpress\/wp-content\/uploads\/2019\/04\/Screenshot_1555342895-169x300.png 169w, https:\/\/charlezz.com\/wordpress\/wp-content\/uploads\/2019\/04\/Screenshot_1555342895-768x1365.png 768w, https:\/\/charlezz.com\/wordpress\/wp-content\/uploads\/2019\/04\/Screenshot_1555342895.png 1080w\" sizes=\"(max-width: 576px) 100vw, 576px\" \/><\/a><\/p>\n<p>RecyclerView\ub97c \uad6c\ud604\ud558\uace0 \ub2e4\uc911 \uc120\ud0dd \uae30\ub2a5\uc744 \ucd94\uac00 \ud558\uae30 \uc704\ud574\uc11c\ub294 Selection \ub77c\uc774\ube0c\ub7ec\ub9ac\ub97c \uc0ac\uc6a9\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc548\ub4dc\ub85c\uc774\ub4dc \ub0b4\uc758 \uc0ac\uc9c4\ub4e4\uc744 Grid\ud615\uc2dd\uc73c\ub85c \uad6c\uc131\ud558\uace0 Selection\uc73c\ub85c \ub2e4\uc911 \uc120\ud0dd\ud558\ub294 \uc608\uc81c\ub97c \ub9cc\ub4e4\uc5b4 \ubcf4\ub3c4\ub85d \ud558\uaca0\uc2b5\ub2c8\ub2e4<\/p>\n<h2>Selection \uad6c\ud604\ud558\uae30<\/h2>\n<p>\uc758\uc874\uc131 \ucd94\uac00\ud558\uae30<\/p>\n<pre class=\"lang:java decode:true\">\/\/androidx \ub97c \uc4f0\uc9c0 \uc54a\ub294\ub2e4\uba74\r\nimplementation \"com.android.support:recyclerview-selection:28.0.0\"<\/pre>\n<p>or<\/p>\n<pre class=\"lang:java decode:true\">\/\/androidx\ub97c \uc4f4\ub2e4\uba74\r\nandroidx.recyclerview:recyclerview-selection:1.0.0<\/pre>\n<h3>Key\ud0c0\uc785 \uacb0\uc815\ud558\uae30<\/h3>\n<p>Selection\ub77c\uc774\ube0c\ub7ec\ub9ac\ub294 3\uac00\uc9c0 \ud0c0\uc785\uc758 Key\ud0c0\uc785\uc744 \uc9c0\uc6d0\ud569\ub2c8\ub2e4.<\/p>\n<ul>\n<li>Parcelable<\/li>\n<li>String<\/li>\n<li>Long<\/li>\n<\/ul>\n<p>\ud558\ub098\uc758 Item\uc744 \uc2dd\ubcc4\ud558\uae30 \uc704\ud55c \uace0\uc720\uac12(ID)\uc73c\ub85c \uc124\uc815\ud558\uba74\ub429\ub2c8\ub2e4.<\/p>\n<p>Key\ud0c0\uc785\uc744 \uacb0\uc815\ud558\uc600\ub2e4\uba74, Adapter\uc5d0\uac8c Id\ub97c \uc774\uc6a9\ud574 Item\uc744 \uc2dd\ubcc4\ud558\uaca0\ub2e4\ub294 \uc124\uc815\uc744 \ud558\ub3c4\ub85d\ud569\ub2c8\ub2e4.<\/p>\n<pre class=\"lang:java mark:4 decode:true \">public class PhotoAdapter {\r\n    protected PhotoAdapter(Context context) {\r\n        ...\r\n        setHasStableIds(true);\r\n        ...\r\n    }\r\n}<\/pre>\n<p>\uadf8\ub7f0 \ub2e4\uc74c \uc544\uc774\ud15c ID\ub97c \uc9c0\uc815\ud558\ub3c4\ub85d \ud569\ub2c8\ub2e4.<\/p>\n<pre class=\"lang:java decode:true\">public class PhotoAdapter extends RecyclerView.Adapter&lt;LookUpViewHolder&gt; {\r\n    ...\r\n    @Override\r\n    public long getItemId(int position) {\r\n        return position;\r\n    }\r\n    ...\r\n}\r\n<\/pre>\n<h3>KeyProvider \uad6c\ud604\ud558\uae30<\/h3>\n<p><span>Key \ud0c0\uc785\uc744 \uc120\ud0dd\uc73c\ubbc0\ub85c, \ud574\ub2f9 Key \ud0c0\uc785\uc5d0 \ub9de\ucd94\uc5b4 KeyProvider\ub97c \uad6c\ud604\ud560 \uc2dc\uac04\uc785\ub2c8\ub2e4. Selection \ub77c\uc774\ube0c\ub7ec\ub9ac\ub294 StableIdKeyProvider\ub97c \uc81c\uacf5\ud558\ubbc0\ub85c \uc774\ub97c \uc774\uc6a9\ud558\uba74 \ub429\ub2c8\ub2e4. SelectionTracker\ub97c \ub9cc\ub4e4\ub54c \ubcf4\ub3c4\ub85d \ud558\uaca0\uc2b5\ub2c8\ub2e4.<\/span><\/p>\n<h3>ItemDetailsLookUp \uad6c\ud604\ud558\uae30<\/h3>\n<p>ItemDetailsLookup&lt;T&gt; \ud074\ub798\uc2a4\ub294 \uc0ac\uc6a9\uc790\uc758 \uc120\ud0dd\uacfc \uad00\ub828\ub41c \ud56d\ubaa9\uc5d0 \ub300\ud55c \uc815\ubcf4\ub97c \uc81c\uacf5\ud569\ub2c8\ub2e4. MotionEvent\ub97c \uae30\ubc18\ud558\uc5ec \uc120\ud0dd\ub41c \ub0b4\uc6a9\uc744 ViewHolder\uc5d0 \ub9e4\ud551\ud569\ub2c8\ub2e4.<\/p>\n<pre class=\"lang:java decode:true  \">public class PhotoDetailsLookUp extends ItemDetailsLookup&lt;Long&gt; {\r\n\r\n    private RecyclerView recyclerView;\r\n    public PhotoDetailsLookUp(RecyclerView recyclerView){\r\n        this.recyclerView = recyclerView;\r\n    }\r\n    @Nullable\r\n    @Override\r\n    public ItemDetails&lt;Long&gt; getItemDetails(@NonNull MotionEvent motionEvent) {\r\n        View view = recyclerView.findChildViewUnder(motionEvent.getX(), motionEvent.getY());\r\n        if (view != null) {\r\n            LookUpViewHolder viewHolder = (LookUpViewHolder) recyclerView.getChildViewHolder(view);\r\n            return viewHolder.getItemDetails();\r\n        }\r\n        return null;\r\n    }\r\n}<\/pre>\n<p>ViewHolder\ub85c \ub3cc\uc544\uac00\uc11c getItemDetails()\uba54\uc18c\ub4dc\ub97c \uc0b4\ud3b4\ubcf4\ub3c4\ub85d \ud569\uc2dc\ub2e4.<\/p>\n<pre class=\"lang:java decode:true\">public class LookUpViewHolder extends RecyclerView.ViewHolder {\r\n\r\n    ImageView image;\r\n    ImageView checkBox;\r\n\r\n    public LookUpViewHolder(View itemView) {\r\n        super(itemView);\r\n        image = itemView.findViewById(R.id.image);\r\n        checkBox = itemView.findViewById(R.id.checkbox);\r\n    }\r\n\r\n    public ItemDetailsLookup.ItemDetails&lt;Long&gt; getItemDetails(){\r\n        return new ItemDetailsLookup.ItemDetails&lt;Long&gt;() {\r\n            @Override\r\n            public int getPosition() {\r\n                return getAdapterPosition();\r\n            }\r\n\r\n            @Nullable\r\n            @Override\r\n            public Long getSelectionKey() {\r\n                return getItemId();\r\n            }\r\n        };\r\n    }<\/pre>\n<p>getItemDetails\ub77c\ub294 \uba54\uc18c\ub4dc\ub97c \ud1b5\ud574 ItemDetails\ub97c \ub9ac\ud134\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4. \ucd94\uc0c1\ud074\ub798\uc2a4\uc778 ItemDetails\uc5d0\ub294 getPosition\uacfc getSelectionKey\ub77c\ub294 \uba54\uc18c\ub4dc\ub97c \uad6c\ud604\ud558\uac8c\ub054 \ub418\uc5b4\uc788\ub294\ub370, \uc704\uc640 \uac19\uc774 adapter\uc758 position\uacfc item id\ub97c \ub9ac\ud134\uc2dc\ucf1c\uc90d\ub2c8\ub2e4.<\/p>\n<h3>SelectionTracker \ub9cc\ub4e4\uae30<\/h3>\n<p>\ub2e4\uc74c\uacfc \uac19\uc774 \ube4c\ub354\ub97c \ud1b5\ud574 SelectionTracker\ub97c \ub9cc\ub4ed\ub2c8\ub2e4.\u00a0<\/p>\n<pre class=\"lang:java decode:true\">private void setupSelectionTracker(){\r\n    selectionTracker = new SelectionTracker.Builder&lt;&gt;(\r\n            \"selection_id\",\r\n            recyclerView,\r\n            new StableIdKeyProvider(recyclerView),\r\n            new PhotoDetailsLookUp(recyclerView),\r\n            StorageStrategy.createLongStorage())\r\n            .withSelectionPredicate(SelectionPredicates.&lt;Long&gt;createSelectAnything())\r\n            .build();\r\n}<\/pre>\n<p><em><strong>Warning : SelectionTracker\ub294 \ubc18\ub4dc\uc2dc RecyclerView\uc5d0 Adapter\uac00 \ucc38\uc870\ub41c \uc774\ud6c4\uc5d0 \ub9cc\ub4e4\uc5b4\uc57c \ud569\ub2c8\ub2e4. \uadf8\ub807\uc9c0 \uc54a\uc73c\uba74 IllegalArgumentException\uc774 \ubc1c\uc0dd\ub429\ub2c8\ub2e4.<\/strong><\/em><\/p>\n<p>Builder\ub97c \ub9cc\ub4dc\ub294\ub370 \ud544\uc694\ud55c \ud30c\ub77c\ubbf8\ud130 \ub0b4\uc6a9\uc785\ub2c8\ub2e4.<\/p>\n<ul>\n<li>selectionId : \uc120\ud0dd\ub0b4\uc6a9 \ub300\ud55c Id\ub97c \uc9c0\uc815\ud569\ub2c8\ub2e4.<\/li>\n<li>recyclerView : \uc120\ud0dd\ub0b4\uc6a9\uc744 \ucd94\uc801\ud560 RecyclerView\ub97c \uc9c0\uc815\ud569\ub2c8\ub2e4.<\/li>\n<li>keyProvider : \uce90\uc2dc\ub97c \uc704\ud55c \uc120\ud0dd\ub418\ub294 \uc544\uc774\ud15c\uc758 Key\uc81c\uacf5\uc790<\/li>\n<li>itemDetailsLookup : RecyclerView \uc544\uc774\ud15c\uc758 \ub300\ud55c \uc815\ubcf4<\/li>\n<li>storage :\u00a0<span>saved state\uc5d0\uc11c \ud0a4\ub97c \uc800\uc7a5\ud558\uae30 \uc704\ud55c \uc804\ub7b5<\/span><\/li>\n<\/ul>\n<p>withSelectionPredicate\ub294 \uc5b4\ub5a0\ud55c \uc120\ud0dd\uc744 \ud560\uc9c0 \uacb0\uc815\ud560 \uc218 \uc788\uac8c \ud569\ub2c8\ub2e4. Selection\ub77c\uc774\ube0c\ub7ec\ub9ac\uc5d0\uc11c \uc81c\uacf5\ud558\ub294 SelectionPredicates.createSelectionAnything()\uc744 \uc4f8 \uc218\ub3c4 \uc788\uace0, \uc790\uc2e0\ub9cc\uc758 SelectionPredicate\ub97c \ub9cc\ub4e4 \uc218\ub3c4 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n<p>SelectionTracker\ub97c \ub9cc\ub4e4\uc5c8\ub2e4\uba74, Adapter\uc5d0 setter\ub97c \ub9cc\ub4e4\uc5b4SelectionTracker\ub97c \ub118\uaca8\uc90d\ub2c8\ub2e4.<\/p>\n<pre class=\"lang:java decode:true \">public void setSelectionTracker(SelectionTracker&lt;Long&gt; selectionTracker) {\r\n    this.selectionTracker = selectionTracker;\r\n}<\/pre>\n<p>Adapter\uc5d0\uc11c \uc774\uc81c selectionTracker\ub97c \ucc38\uc870\ud560 \uc218 \uc788\uac8c \ub418\uc5c8\uc2b5\ub2c8\ub2e4.<\/p>\n<pre class=\"lang:java decode:true \">@Override\r\npublic void onBindViewHolder(@NonNull LookUpViewHolder lookUpViewHolder, int position) {\r\n    Photo photo = photoList.get(position);\r\n    lookUpViewHolder.setPhoto(photo);\r\n    lookUpViewHolder.setSelectionTracker(selectionTracker);\r\n}<\/pre>\n<p>\ubdf0\ud640\ub354\uac00 \ubc14\uc778\ub529 \ub418\ub294 \uc2dc\uc810\uc5d0 selectionTracker\uc758 \uc815\ubcf4\ub97c \uc77d\uc5b4 \uc120\ud0dd\ub0b4\uc6a9\uc5d0 \ub300\ud55c UI\ub97c \uacb0\uc815\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n<p>\uc608\uc81c \ud504\ub85c\uc81d\ud2b8\ub294 <a href=\"https:\/\/github.com\/Charlezz\/SelectionSample\">github<\/a>\uc5d0\uc11c \ud655\uc778\ud558\uc2e4 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n<p><iframe loading=\"lazy\" width=\"480\" height=\"270\" src=\"https:\/\/giphy.com\/embed\/3o7abKhOpu0NwenH3O\" frameborder=\"0\" class=\"giphy-embed\" allowfullscreen=\"allowfullscreen\"><\/iframe><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Selection RecyclerView\ub97c \uad6c\ud604\ud558\uace0 \ub2e4\uc911 \uc120\ud0dd \uae30\ub2a5\uc744 \ucd94\uac00 \ud558\uae30 \uc704\ud574\uc11c\ub294 Selection \ub77c\uc774\ube0c\ub7ec\ub9ac\ub97c \uc0ac\uc6a9\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc548\ub4dc\ub85c\uc774\ub4dc \ub0b4\uc758 \uc0ac\uc9c4\ub4e4\uc744 Grid\ud615\uc2dd\uc73c\ub85c \uad6c\uc131\ud558\uace0 Selection\uc73c\ub85c \ub2e4\uc911 \uc120\ud0dd\ud558\ub294 \uc608\uc81c\ub97c \ub9cc\ub4e4\uc5b4 \ubcf4\ub3c4\ub85d \ud558\uaca0\uc2b5\ub2c8\ub2e4 Selection \uad6c\ud604\ud558\uae30 \uc758\uc874\uc131 \ucd94\uac00\ud558\uae30 \/\/androidx \ub97c \uc4f0\uc9c0 \uc54a\ub294\ub2e4\uba74 implementation &#8220;com.android.support:recyclerview-selection:28.0.0&#8221; or \/\/androidx\ub97c \uc4f4\ub2e4\uba74 androidx.recyclerview:recyclerview-selection:1.0.0 Key\ud0c0\uc785 \uacb0\uc815\ud558\uae30 Selection\ub77c\uc774\ube0c\ub7ec\ub9ac\ub294 3\uac00\uc9c0 \ud0c0\uc785\uc758 Key\ud0c0\uc785\uc744 \uc9c0\uc6d0\ud569\ub2c8\ub2e4. Parcelable String Long [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"inline_featured_image":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0},"categories":[25],"tags":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/charlezz.com\/index.php?rest_route=\/wp\/v2\/posts\/1194"}],"collection":[{"href":"https:\/\/charlezz.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/charlezz.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/charlezz.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/charlezz.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1194"}],"version-history":[{"count":5,"href":"https:\/\/charlezz.com\/index.php?rest_route=\/wp\/v2\/posts\/1194\/revisions"}],"predecessor-version":[{"id":1368,"href":"https:\/\/charlezz.com\/index.php?rest_route=\/wp\/v2\/posts\/1194\/revisions\/1368"}],"wp:attachment":[{"href":"https:\/\/charlezz.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1194"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/charlezz.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1194"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/charlezz.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1194"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}