├── .gitignore ├── CHANGELOG.md ├── Dangerfile ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── art ├── dash.png ├── full_bleed.png ├── grid.png ├── horizontal.png ├── inset.png ├── position.png ├── position_inverted.png └── vertical.png ├── bitrise.yml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── multilinedivider ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── sakebook │ │ └── android │ │ └── library │ │ └── multilinedevider │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── kotlin │ │ └── com │ │ │ └── sakebook │ │ │ └── android │ │ │ └── library │ │ │ └── multilinedevider │ │ │ ├── MultiLineDivider.kt │ │ │ ├── OffsetsCalculator.kt │ │ │ └── divider │ │ │ ├── Divider.kt │ │ │ ├── GridDivider.kt │ │ │ ├── HorizontalDivider.kt │ │ │ ├── NoDivider.kt │ │ │ ├── PositionDivider.kt │ │ │ └── VerticalDivider.kt │ └── res │ │ ├── drawable │ │ └── simple_divider.xml │ │ └── values │ │ └── strings.xml │ └── test │ └── kotlin │ └── com │ └── sakebook │ └── android │ └── library │ └── multilinedevider │ ├── ExampleUnitTest.kt │ └── OffsetsCalculatorTest.kt ├── sample ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── sakebook │ │ └── android │ │ └── library │ │ └── multilinedividersample │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── sakebook │ │ │ └── android │ │ │ └── library │ │ │ └── multilinedividersample │ │ │ ├── ContactActivity.java │ │ │ ├── GridActivity.java │ │ │ ├── ListActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── PositionActivity.java │ │ │ ├── TicketActivity.java │ │ │ ├── dash │ │ │ ├── RecyclerAdapter.java │ │ │ └── Ticket.java │ │ │ ├── grid │ │ │ ├── GridFullBleedImageViewHolder.java │ │ │ ├── GridImageViewHolder.java │ │ │ ├── RecyclerAdapter.java │ │ │ └── ViewHolder.java │ │ │ ├── inset │ │ │ ├── Contact.java │ │ │ ├── FirstViewHolder.java │ │ │ ├── OtherViewHolder.java │ │ │ ├── RecyclerAdapter.java │ │ │ └── ViewHolder.java │ │ │ ├── multiline │ │ │ ├── EvenViewHolder.java │ │ │ ├── LayoutType.java │ │ │ ├── Number.java │ │ │ ├── OddViewHolder.java │ │ │ ├── PrimeViewHolder.java │ │ │ ├── RecyclerAdapter.java │ │ │ └── ViewHolder.java │ │ │ └── position │ │ │ ├── PositionInvertedViewHolder.java │ │ │ ├── PositionViewHolder.java │ │ │ ├── RecyclerAdapter.java │ │ │ └── ViewHolder.java │ └── res │ │ ├── drawable-hdpi │ │ ├── ic_account_circle_24dp.png │ │ └── ic_star_24dp.png │ │ ├── drawable-mdpi │ │ ├── ic_account_circle_24dp.png │ │ └── ic_star_24dp.png │ │ ├── drawable-xhdpi │ │ ├── ic_account_circle_24dp.png │ │ └── ic_star_24dp.png │ │ ├── drawable-xxhdpi │ │ ├── ic_account_circle_24dp.png │ │ └── ic_star_24dp.png │ │ ├── drawable-xxxhdpi │ │ ├── ic_account_circle_24dp.png │ │ └── ic_star_24dp.png │ │ ├── drawable │ │ ├── cat1.jpg │ │ ├── cat2.jpg │ │ ├── cat3.jpg │ │ ├── custom_divider.xml │ │ ├── dashed_line_divider.xml │ │ └── simple_divider.xml │ │ ├── layout │ │ ├── activity_contact.xml │ │ ├── activity_grid.xml │ │ ├── activity_list.xml │ │ ├── activity_main.xml │ │ ├── activity_position.xml │ │ ├── activity_ticket.xml │ │ ├── item_contact.xml │ │ ├── item_even_horizontal.xml │ │ ├── item_even_vertical.xml │ │ ├── item_grid_horizontal.xml │ │ ├── item_grid_vertical.xml │ │ ├── item_horizontal.xml │ │ ├── item_odd_horizontal.xml │ │ ├── item_odd_vertical.xml │ │ ├── item_prime_horizontal.xml │ │ ├── item_prime_vertical.xml │ │ ├── item_ticket.xml │ │ └── item_vertical.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── sakebook │ └── android │ └── library │ └── multilinedividersample │ └── ExampleUnitTest.java ├── settings.gradle └── wercker.yml /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | 11 | # Built application files 12 | *.apk 13 | *.ap_ 14 | 15 | # Files for the ART/Dalvik VM 16 | *.dex 17 | 18 | # Java class files 19 | *.class 20 | 21 | # Generated files 22 | bin/ 23 | gen/ 24 | out/ 25 | 26 | # Gradle files 27 | .gradle/ 28 | build/ 29 | 30 | # Local configuration file (sdk path, etc) 31 | local.properties 32 | 33 | # Proguard folder generated by Eclipse 34 | proguard/ 35 | 36 | # Log Files 37 | *.log 38 | 39 | # Android Studio Navigation editor temp files 40 | .navigation/ 41 | 42 | # Android Studio captures folder 43 | captures/ 44 | 45 | # Intellij 46 | *.iml 47 | .idea/ 48 | .idea/workspace.xml 49 | .idea/tasks.xml 50 | .idea/gradle.xml 51 | .idea/dictionaries 52 | .idea/libraries 53 | 54 | # Keystore files 55 | *.jks 56 | 57 | # External native build folder generated in Android Studio 2.2 and later 58 | .externalNativeBuild 59 | 60 | # Google Services (e.g. APIs or Firebase) 61 | google-services.json 62 | 63 | # Freeline 64 | freeline.py 65 | freeline/ 66 | freeline_project_description.json 67 | 68 | # wercker 69 | .wercker/ 70 | 71 | # bitrise 72 | .envstore.yml 73 | .bitrise.secrets.yml 74 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ## 0.2.0 (2017-05-30) 3 | - Add PositionDivider. 4 | - Fix GridDivider last padding. 5 | - Add Unit test. 6 | 7 | ## 0.1.0 (2017-05-21) 8 | - Add GridDivider. 9 | 10 | ## 0.0.2 (2017-05-06) 11 | - Fix group id. 12 | 13 | ## 0.0.1 (2017-05-06) 14 | - This is the first public beta release. -------------------------------------------------------------------------------- /Dangerfile: -------------------------------------------------------------------------------- 1 | # reference http://techlife.cookpad.com/entry/2017/06/28/190000 2 | 3 | #### 4 | # 5 | # github comment settings 6 | # 7 | #### 8 | github.dismiss_out_of_range_messages 9 | 10 | #### 11 | # 12 | # for PR 13 | # 14 | #### 15 | if github.pr_title.include? "[WIP]" || github.pr_labels.include?("WIP") 16 | warn("PR is classed as Work in Progress") 17 | end 18 | 19 | # Warn when there is a big PR 20 | warn("a large PR") if git.lines_of_code > 300 21 | 22 | # Warn when PR has no milestone 23 | warn("A pull request must have a milestone set") if github.pr_json["milestone"].nil? 24 | 25 | # Warn when PR has no assignees 26 | warn("A pull request must have some assignees") if github.pr_json["assignee"].nil? 27 | 28 | #### 29 | # 30 | # Android Lint 31 | # 32 | #### 33 | android_lint.gradle_task = ":multilinedivider:lint" 34 | android_lint.report_file = "multilinedivider/build/reports/lint-results.xml" 35 | # android_lint.filtering = true 36 | # Only GitHub 37 | android_lint.lint(inline_mode: true) 38 | android_lint.lint 39 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | source "https://rubygems.org" 3 | 4 | gem 'danger' 5 | gem 'danger-android_lint' 6 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | addressable (2.5.1) 5 | public_suffix (~> 2.0, >= 2.0.2) 6 | ansi (1.5.0) 7 | ast (2.3.0) 8 | claide (1.0.2) 9 | claide-plugins (0.9.2) 10 | cork 11 | nap 12 | open4 (~> 1.3) 13 | colored2 (3.1.2) 14 | cork (0.3.0) 15 | colored2 (~> 3.1) 16 | danger (5.3.3) 17 | claide (~> 1.0) 18 | claide-plugins (>= 0.9.2) 19 | colored2 (~> 3.1) 20 | cork (~> 0.1) 21 | faraday (~> 0.9) 22 | faraday-http-cache (~> 1.0) 23 | git (~> 1) 24 | kramdown (~> 1.5) 25 | octokit (~> 4.7) 26 | terminal-table (~> 1) 27 | danger-android_lint (0.0.4) 28 | danger-plugin-api (~> 1.0) 29 | oga 30 | danger-plugin-api (1.0.0) 31 | danger (> 2.0) 32 | faraday (0.12.1) 33 | multipart-post (>= 1.2, < 3) 34 | faraday-http-cache (1.3.1) 35 | faraday (~> 0.8) 36 | git (1.11.0) 37 | rchardet (~> 1.8) 38 | kramdown (1.14.0) 39 | multipart-post (2.0.0) 40 | nap (1.1.0) 41 | octokit (4.7.0) 42 | sawyer (~> 0.8.0, >= 0.5.3) 43 | oga (2.10) 44 | ast 45 | ruby-ll (~> 2.1) 46 | open4 (1.3.4) 47 | public_suffix (2.0.5) 48 | rchardet (1.8.0) 49 | ruby-ll (2.1.2) 50 | ansi 51 | ast 52 | sawyer (0.8.1) 53 | addressable (>= 2.3.5, < 2.6) 54 | faraday (~> 0.8, < 1.0) 55 | terminal-table (1.8.0) 56 | unicode-display_width (~> 1.1, >= 1.1.1) 57 | unicode-display_width (1.3.0) 58 | 59 | PLATFORMS 60 | ruby 61 | 62 | DEPENDENCIES 63 | danger 64 | danger-android_lint 65 | 66 | BUNDLED WITH 67 | 1.15.1 68 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2017 Shinya Sakemoto 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MultiLineDivider 2 | ============ 3 | Multi divider in RecyclerView on Android. 4 | 5 | [![Download](https://api.bintray.com/packages/sakebook/maven/MultiLineDivider/images/download.svg) ](https://bintray.com/sakebook/maven/MultiLineDivider/_latestVersion) [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-MultiLineDivider-brightgreen.svg?style=flat)](https://android-arsenal.com/details/1/5735) 6 | 7 | [![wercker status](https://app.wercker.com/status/7b5ad7fbfb97759c7d5ef14778e0539a/s/ "wercker status")](https://app.wercker.com/project/byKey/7b5ad7fbfb97759c7d5ef14778e0539a) 8 | 9 | |Vertical|Horizontal| 10 | |:---:|:---:| 11 | |![image](https://raw.githubusercontent.com/sakebook/MultiLineDivider/master/art/vertical.png)|![image](https://raw.githubusercontent.com/sakebook/MultiLineDivider/master/art/horizontal.png)| 12 | 13 | |Inset|Dash| 14 | |:---:|:---:| 15 | |![image](https://raw.githubusercontent.com/sakebook/MultiLineDivider/master/art/inset.png)|![image](https://raw.githubusercontent.com/sakebook/MultiLineDivider/master/art/dash.png)| 16 | 17 | |Grid|FullBleed| 18 | |:---:|:---:| 19 | |![image](https://raw.githubusercontent.com/sakebook/MultiLineDivider/master/art/grid.png)|![image](https://raw.githubusercontent.com/sakebook/MultiLineDivider/master/art/full_bleed.png)| 20 | 21 | |Position|Inverted| 22 | |:---:|:---:| 23 | |![image](https://raw.githubusercontent.com/sakebook/MultiLineDivider/master/art/position.png)|![image](https://raw.githubusercontent.com/sakebook/MultiLineDivider/master/art/position_inverted.png)| 24 | 25 | --- 26 | 27 | 28 | - Requirement 29 | - SDK Version __16+__ 30 | - (Use from Java)Kotlin Version __1.0.0+__ 31 | 32 | 33 | ## Usage 34 | Add dependencies 35 | 36 | ```gradle 37 | compile 'com.github.sakebook:MultiLineDivider:0.2.0@aar' 38 | 39 | // Use from Java 40 | compile "org.jetbrains.kotlin:kotlin-stdlib:kotlin_version" 41 | ``` 42 | 43 | Add to RecyclerView like in addItemDecoration 44 | 45 | - Java 46 | 47 | ```java 48 | MultiLineDivider multiLineDivider = new MultiLineDivider(this, LinearLayout.VERTICAL); 49 | recyclerView.addItemDecoration(multiLineDivider); 50 | ``` 51 | 52 | - Kotlin 53 | 54 | ```kotlin 55 | val multiLineDivider = MultiLineDivider(this) 56 | recyclerView.addItemDecoration(multiLineDivider) 57 | ``` 58 | 59 | And Implement `VerticalDivider` in ViewHolder 60 | 61 | - Java 62 | 63 | ```java 64 | public class YourViewHolder extends RecyclerView.ViewHolder implements VerticalDivider { 65 | 66 | public YourViewHolder(View itemView) { 67 | super(itemView); 68 | } 69 | 70 | @Override 71 | public int getHeight() { 72 | return this.itemView.getContext().getResources() 73 | .getDimensionPixelSize(R.dimen.small_margin); 74 | } 75 | 76 | @Override 77 | public int getDrawableRes() { 78 | return R.drawable.custom_divider; 79 | } 80 | 81 | @Nullable 82 | @Override 83 | // android.support.v4.util.Pair 84 | public Pair getVerticalInset() { 85 | return null; 86 | } 87 | } 88 | ``` 89 | 90 | - Kotlin 91 | 92 | ```kotlin 93 | class YourViewHolder(view: View): RecyclerView.ViewHolder(view), VerticalDivider { 94 | override val height = view.context.resources.getDimensionPixelSize(R.dimen.small_margin) 95 | override val drawableRes = R.drawable.custom_divider 96 | override val verticalInset: Pair? = null 97 | } 98 | ``` 99 | 100 | 101 | ## Custom 102 | ### If you want to draw Horizontal divider 103 | 104 | ```java 105 | MultiLineDivider multiLineDivider = new MultiLineDivider(this, LinearLayout.HORIZONTAL); 106 | ``` 107 | 108 | and implements `HorizontalDivider` 109 | 110 | 111 | ### If you __don't__ want to draw divider 112 | 113 | Implements `NoDivider` 114 | 115 | ### If you want to inset in divider 116 | 117 | ``` 118 | @Nullable 119 | @Override 120 | // android.support.v4.util.Pair 121 | public Pair getVerticalInset() { 122 | int insetLeft = (int) resources.getDimension(R.dimen.list_padding); 123 | int insetRight = 0; 124 | return Pair.create(insetLeft, insetRight); 125 | } 126 | 127 | ``` 128 | 129 | ### If you want to padding in grid 130 | 131 | - Java 132 | 133 | ```java 134 | public class YourViewHolder extends RecyclerView.ViewHolder implements GridDivider { 135 | 136 | public YourViewHolder(View itemView) { 137 | super(itemView); 138 | } 139 | 140 | @Override 141 | public int getPadding() { 142 | return itemView.getContext().getResources().getDimensionPixelSize(R.dimen.tiny_margin); 143 | } 144 | 145 | @Override 146 | public boolean getFullBleed() { 147 | return false; 148 | } 149 | } 150 | ``` 151 | 152 | - Kotlin 153 | 154 | ```kotlin 155 | class YourViewHolder(view: View): RecyclerView.ViewHolder(view), GridDivider { 156 | override val padding = view.context.resources.getDimensionPixelSize(R.dimen.grid_padding) 157 | override val fullBleed = true 158 | } 159 | ``` 160 | 161 | ### If you want to draw divider in specific position 162 | 163 | - Java 164 | 165 | ```java 166 | public class YourViewHolder extends RecyclerView.ViewHolder implements PositionDivider { 167 | 168 | public YourViewHolder(View itemView) { 169 | super(itemView); 170 | } 171 | 172 | @NotNull 173 | @Override 174 | public List getPositions() { 175 | return Arrays.asList(2, 12, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 42); // include "2" 176 | } 177 | 178 | @Override 179 | public boolean getInverted() { 180 | return false; 181 | } 182 | } 183 | ``` 184 | 185 | - Kotlin 186 | 187 | ```kotlin 188 | class YourViewHolder(view: View): RecyclerView.ViewHolder(view), PositionDivider { 189 | override val positions = listOf(2, 12, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 42) 190 | override val inverted = false 191 | } 192 | ``` 193 | 194 | ### If you __don't__ want to draw divider in specific position 195 | 196 | Implements `PositionDivider` with `inverted` true 197 | 198 | ### If you want to draw custom divider in specific position 199 | 200 | Implements `PositionDivider` and `VerticalDivider` or `HorizontalDivider` 201 | 202 | 203 | ## ProGuard 204 | 205 | If you are using ProGuard you might need to add the following option: 206 | 207 | ``` 208 | -keep class com.sakebook.android.library.multilinedevider.*{ *; } 209 | ``` 210 | 211 | Sample in project [sample/](https://github.com/sakebook/MultiLineDivider/tree/master/sample) 212 | 213 | ## LICENSE 214 | ``` 215 | Copyright (C) 2017 Shinya Sakemoto 216 | 217 | Licensed under the Apache License, Version 2.0 (the "License"); 218 | you may not use this file except in compliance with the License. 219 | You may obtain a copy of the License at 220 | 221 | http://www.apache.org/licenses/LICENSE-2.0 222 | 223 | Unless required by applicable law or agreed to in writing, software 224 | distributed under the License is distributed on an "AS IS" BASIS, 225 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 226 | See the License for the specific language governing permissions and 227 | limitations under the License. 228 | ``` 229 | -------------------------------------------------------------------------------- /art/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/art/dash.png -------------------------------------------------------------------------------- /art/full_bleed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/art/full_bleed.png -------------------------------------------------------------------------------- /art/grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/art/grid.png -------------------------------------------------------------------------------- /art/horizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/art/horizontal.png -------------------------------------------------------------------------------- /art/inset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/art/inset.png -------------------------------------------------------------------------------- /art/position.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/art/position.png -------------------------------------------------------------------------------- /art/position_inverted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/art/position_inverted.png -------------------------------------------------------------------------------- /art/vertical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/art/vertical.png -------------------------------------------------------------------------------- /bitrise.yml: -------------------------------------------------------------------------------- 1 | --- 2 | format_version: '3' 3 | default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git 4 | project_type: android 5 | workflows: 6 | run-test-docker: 7 | steps: 8 | - activate-ssh-key@3.1.1: 9 | run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}' 10 | - git-clone@3.5.1: {} 11 | - script@1.1.4: 12 | title: run test use docker 13 | inputs: 14 | - content: |- 15 | rm -rf local.properties 16 | 17 | docker run --rm \ 18 | -v $BITRISE_SOURCE_DIR:$DOCKER_HOME \ 19 | -w $DOCKER_HOME \ 20 | -e BITRISE_IO=true \ 21 | -e GIT_REPOSITORY_URL=$GIT_REPOSITORY_URL \ 22 | -e BITRISE_PULL_REQUEST=$BITRISE_PULL_REQUEST \ 23 | $DOCKERHUB_IMG_ID bash -c \ 24 | " 25 | # bundle install 26 | # bundle exec danger 27 | ./gradlew :multilinedivider:testDebug -PdisablePreDex 28 | " 29 | before_run: 30 | - docker-build 31 | after_run: 32 | - cache-push 33 | run-test-docker-use-cache: 34 | steps: 35 | - activate-ssh-key@3.1.1: 36 | run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}' 37 | - git-clone@3.5.1: {} 38 | - script@1.1.4: 39 | title: run test use docker 40 | inputs: 41 | - content: |- 42 | rm -rf local.properties 43 | 44 | docker run --rm \ 45 | -v $BITRISE_SOURCE_DIR:$DOCKER_HOME \ 46 | -w $DOCKER_HOME \ 47 | -e GRADLE_USER_HOME=$DOCKER_HOME/.gradle \ 48 | -e BITRISE_IO=true \ 49 | -e GIT_REPOSITORY_URL=$GIT_REPOSITORY_URL \ 50 | -e BITRISE_PULL_REQUEST=$BITRISE_PULL_REQUEST \ 51 | $DOCKERHUB_IMG_ID bash -c \ 52 | " 53 | # bundle install 54 | # bundle exec danger 55 | ./gradlew :multilinedivider:testDebug -PdisablePreDex 56 | " 57 | before_run: 58 | - docker-build-with-cache 59 | after_run: 60 | - cache-push-with-docker 61 | run-test: 62 | steps: 63 | - activate-ssh-key@3.1.1: 64 | run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}' 65 | - git-clone@3.5.1: {} 66 | - cache-pull@1.0.0: {} 67 | - script@1.1.4: 68 | title: run danger 69 | inputs: 70 | - content: |- 71 | # bundle install 72 | # bundle exec danger 73 | - script@1.1.4: 74 | inputs: 75 | - content: |- 76 | ./gradlew :multilinedivider:testDebug -PdisablePreDex 77 | after_run: 78 | - cache-push 79 | local-run-test-docker: 80 | steps: 81 | - script@1.1.4: 82 | title: local run test use docker 83 | inputs: 84 | - content: |- 85 | rm -rf local.properties 86 | 87 | docker run --rm \ 88 | -v $BITRISE_SOURCE_DIR:$DOCKER_HOME \ 89 | -w $DOCKER_HOME \ 90 | -e GRADLE_USER_HOME=$DOCKER_HOME/.gradle \ 91 | -e BITRISE_IO=true \ 92 | -e GIT_REPOSITORY_URL=$GIT_REPOSITORY_URL \ 93 | -e BITRISE_PULL_REQUEST=$BITRISE_PULL_REQUEST \ 94 | -e DANGER_GITHUB_API_TOKEN=$DANGER_GITHUB_API_TOKEN \ 95 | $DOCKERHUB_IMG_ID bash -c \ 96 | " 97 | bundle install 98 | bundle exec danger local 99 | ./gradlew :multilinedivider:testDebug -PdisablePreDex 100 | " 101 | before_run: 102 | - docker-build 103 | envs: 104 | - BITRISE_PULL_REQUEST: 18 105 | - GIT_REPOSITORY_URL: git@github.com:sakebook/MultiLineDivider.git 106 | docker-build-with-cache: 107 | steps: 108 | - cache-pull@1.0.0: {} 109 | - script@1.1.4: 110 | title: docker login or pull use cache 111 | inputs: 112 | - content: |- 113 | if [ -e $BITRISE_CACHE_DIR/$DOCKER_CACHE_IMG ]; then 114 | echo "Exist cache" 115 | docker load < $BITRISE_CACHE_DIR/$DOCKER_CACHE_IMG 116 | else 117 | echo "Cache is not found" 118 | docker login -u $USERNAME -p $PASSWORD 119 | docker pull $DOCKERHUB_IMG_ID 120 | fi 121 | docker-build: 122 | steps: 123 | - cache-pull@1.0.0: {} 124 | - script@1.1.4: 125 | title: docker login & pull 126 | inputs: 127 | - content: |- 128 | docker login -u $USERNAME -p $PASSWORD 129 | docker pull $DOCKERHUB_IMG_ID 130 | cache-push: 131 | steps: 132 | - cache-push@1.1.3: 133 | inputs: 134 | - cache_paths: |- 135 | $BITRISE_SOURCE_DIR/.gradle 136 | $BITRISE_SOURCE_DIR/.m2 137 | $HOME/.gradle 138 | $HOME/.m2 139 | - ignore_check_on_paths: |- 140 | $HOME/.gradle/caches/*.lock 141 | $HOME/.gradle/*.bin 142 | $BITRISE_SOURCE_DIR/.gradle/*.lock 143 | $BITRISE_SOURCE_DIR./.gradle/*.bin 144 | cache-push-with-docker: 145 | steps: 146 | - script@1.1.4: 147 | title: docker image save 148 | inputs: 149 | - content: |- 150 | docker save $DOCKERHUB_IMG_ID > $BITRISE_CACHE_DIR/$DOCKER_CACHE_IMG 151 | - cache-push@1.1.3: 152 | inputs: 153 | - cache_paths: |- 154 | $BITRISE_SOURCE_DIR/.gradle 155 | $BITRISE_SOURCE_DIR/.m2 156 | $BITRISE_CACHE_DIR 157 | $HOME/.gradle 158 | - ignore_check_on_paths: |- 159 | $HOME/.gradle/caches/*.lock 160 | $HOME/.gradle/*.bin 161 | $BITRISE_SOURCE_DIR/.gradle/*.lock 162 | $BITRISE_SOURCE_DIR./.gradle/*.bin 163 | app: 164 | envs: 165 | - GRADLEW_PATH: "./gradlew" 166 | - GRADLE_BUILD_FILE_PATH: build.gradle 167 | - DOCKER_HOME: "/root" 168 | - DOCKER_IMG_NAME: docker-android-alpine 169 | - DOCKER_IMG_TAG: 25.0.3_3 170 | - DOCKERHUB_IMG_ID: sakebook/$DOCKER_IMG_NAME:$DOCKER_IMG_TAG 171 | - DOCKER_CACHE_IMG: $DOCKER_IMG_NAME-$DOCKER_IMG_TAG.tar 172 | # for local bitrise cli 173 | - BITRISE_CACHE_DIR: $BITRISE_SOURCE_DIR 174 | trigger_map: 175 | - push_branch: "*" 176 | workflow: run-test-docker 177 | - pull_request_source_branch: "*" 178 | workflow: run-test 179 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext.kotlin_version = '1.1.2-3' 5 | ext.support_library_version = '25.3.1' 6 | repositories { 7 | jcenter() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:2.3.3' 11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 12 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | plugins { 19 | id "com.jfrog.bintray" version "1.7.3" 20 | } 21 | 22 | allprojects { 23 | repositories { 24 | jcenter() 25 | } 26 | } 27 | 28 | task clean(type: Delete) { 29 | delete rootProject.buildDir 30 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Apr 23 18:41:46 JST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /multilinedivider/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /multilinedivider/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'com.github.dcendents.android-maven' 4 | apply plugin: 'com.jfrog.bintray' 5 | 6 | android { 7 | compileSdkVersion 25 8 | buildToolsVersion "25.0.3" 9 | 10 | defaultConfig { 11 | minSdkVersion 16 12 | targetSdkVersion 25 13 | versionCode 1 14 | versionName "1.0" 15 | 16 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 17 | 18 | } 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 23 | } 24 | debug { 25 | testCoverageEnabled true 26 | } 27 | } 28 | sourceSets { 29 | main.java.srcDirs += 'src/main/kotlin' 30 | test.java.srcDirs += 'src/test/kotlin' 31 | } 32 | lintOptions { 33 | xmlReport true 34 | } 35 | } 36 | 37 | dependencies { 38 | compile fileTree(dir: 'libs', include: ['*.jar']) 39 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 40 | exclude group: 'com.android.support', module: 'support-annotations' 41 | }) 42 | testCompile 'junit:junit:4.12' 43 | testCompile "org.robolectric:robolectric:3.3.2" 44 | testCompile "org.mockito:mockito-inline:2.8.47" 45 | compile "com.android.support:appcompat-v7:$support_library_version" 46 | compile "com.android.support:recyclerview-v7:$support_library_version" 47 | compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 48 | } 49 | repositories { 50 | mavenCentral() 51 | } 52 | 53 | group "com.github.sakebook" 54 | version "0.2.0" 55 | 56 | archivesBaseName = "MultiLineDivider" 57 | 58 | bintray { 59 | user = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER') 60 | key = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY') 61 | // jFrog plugin must be declared for this line to work 62 | configurations = ['archives'] 63 | // Package info for BinTray 64 | pkg { 65 | repo = 'maven' 66 | name = 'MultiLineDivider' 67 | userOrg = user 68 | licenses = ['Apache-2.0'] 69 | vcsUrl = 'https://github.com/sakebook/MultiLineDivider.git' 70 | desc = 'Multi divider in RecyclerView on Android.' 71 | } 72 | } 73 | 74 | task sourcesJar(type: Jar) { 75 | from android.sourceSets.main.java.srcDirs 76 | classifier = 'sources' 77 | } 78 | 79 | task javadoc(type: Javadoc) { 80 | // Workaround https://github.com/novoda/bintray-release/issues/71 81 | excludes = ['**/*.kt'] 82 | source = android.sourceSets.main.java.srcDirs 83 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 84 | } 85 | 86 | task javadocJar(type: Jar, dependsOn: javadoc) { 87 | classifier = 'javadoc' 88 | from javadoc.destinationDir 89 | } 90 | 91 | artifacts { 92 | archives javadocJar 93 | archives sourcesJar 94 | } -------------------------------------------------------------------------------- /multilinedivider/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Applications/adt-bundle-mac-x86_64-20130219/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /multilinedivider/src/androidTest/java/com/sakebook/android/library/multilinedevider/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedevider; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.sakebook.android.library.multilinedevider.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /multilinedivider/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /multilinedivider/src/main/kotlin/com/sakebook/android/library/multilinedevider/MultiLineDivider.kt: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedevider 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.graphics.Canvas 6 | import android.graphics.Rect 7 | import android.graphics.drawable.Drawable 8 | import android.support.v4.content.res.ResourcesCompat 9 | import android.support.v4.util.SimpleArrayMap 10 | import android.support.v4.view.ViewCompat 11 | import android.support.v7.widget.RecyclerView 12 | import android.view.View 13 | import android.widget.LinearLayout 14 | import com.sakebook.android.library.multilinedevider.divider.* 15 | 16 | /** 17 | * Created by sakemotoshinya on 2017/04/24. 18 | */ 19 | class MultiLineDivider(val context: Context, val orientation: Int = VERTICAL): RecyclerView.ItemDecoration() { 20 | 21 | private var drawable: Drawable? = null 22 | private val defaultDivider: Drawable by lazy { createDivider(context, divider = drawable) } 23 | private val dividerMap: SimpleArrayMap = SimpleArrayMap() 24 | private val bounds = Rect() 25 | private val offsetsCalculator = OffsetsCalculator(defaultDivider, orientation) 26 | 27 | constructor(context: Context, orientation: Int = VERTICAL, divider: Drawable) : this(context, orientation) { 28 | drawable = divider 29 | } 30 | 31 | private fun createDivider(context: Context, divider: Drawable?): Drawable { 32 | return divider?.let { 33 | it 34 | }?: context.obtainStyledAttributes(ATTRS).run { 35 | this.getDrawable(0).apply { 36 | this@run.recycle() 37 | } 38 | } 39 | } 40 | 41 | override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State?) { 42 | parent.layoutManager ?: return 43 | when(orientation) { 44 | VERTICAL -> drawVertical(c, parent) 45 | HORIZONTAL -> drawHorizontal(c, parent) 46 | } 47 | } 48 | 49 | override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State?) { 50 | val vh = parent.getChildViewHolder(view) 51 | offsetsCalculator.determineOffsets(outRect, vh, parent) 52 | } 53 | 54 | @SuppressLint("NewApi") 55 | private fun drawVertical(canvas: Canvas, parent: RecyclerView) { 56 | val left: Int 57 | val right: Int 58 | when(parent.clipToPadding) { 59 | true -> { 60 | left = parent.paddingLeft 61 | right = parent.width - parent.paddingRight 62 | canvas.clipRect(left, parent.paddingTop, right, 63 | parent.height - parent.paddingBottom) 64 | } 65 | false -> { 66 | left = 0 67 | right = parent.width 68 | } 69 | } 70 | 71 | val childCount = parent.childCount 72 | loop@ for (i in 0 until childCount) { 73 | val child = parent.getChildAt(i) 74 | parent.getDecoratedBoundsWithMargins(child, bounds) 75 | val bottom = bounds.bottom + Math.round(ViewCompat.getTranslationY(child)) 76 | 77 | val vh = parent.getChildViewHolder(child) 78 | when(vh) { 79 | is NoDivider -> {} 80 | is GridDivider -> {} 81 | is VerticalDivider -> { 82 | if(vh is PositionDivider) { 83 | when(vh.positions.any { it == vh.adapterPosition }) { 84 | true -> if (vh.inverted) continue@loop 85 | false -> if (vh.inverted) else continue@loop 86 | } 87 | } 88 | val drawable = dividerMap[vh]?: // Reuse divider 89 | ResourcesCompat.getDrawable(context.resources, vh.drawableRes, null)?.also { 90 | dividerMap.put(vh, it) 91 | } 92 | val top = bottom - (vh.height + 1) // Line height < Bounds height 93 | drawable?.let { d -> 94 | d.setBounds(left, top, right, bottom) 95 | vh.verticalInset?.let { 96 | d.bounds.left = d.bounds.left.plus(it.first) 97 | d.bounds.right = d.bounds.right.minus(it.second) 98 | } 99 | d.draw(canvas) 100 | } 101 | } 102 | is PositionDivider -> { 103 | when(vh.positions.any { it == vh.adapterPosition }) { 104 | true -> if (vh.inverted) continue@loop 105 | false -> if (vh.inverted) else continue@loop 106 | } 107 | val top = bottom - defaultDivider.intrinsicHeight 108 | defaultDivider.setBounds(left, top, right, bottom) 109 | defaultDivider.draw(canvas) 110 | } 111 | else -> { 112 | val top = bottom - defaultDivider.intrinsicHeight 113 | defaultDivider.setBounds(left, top, right, bottom) 114 | defaultDivider.draw(canvas) 115 | } 116 | } 117 | } 118 | } 119 | 120 | @SuppressLint("NewApi") 121 | private fun drawHorizontal(canvas: Canvas, parent: RecyclerView) { 122 | val top: Int 123 | val bottom: Int 124 | when(parent.clipToPadding) { 125 | true -> { 126 | top = parent.paddingTop 127 | bottom = parent.height - parent.paddingBottom 128 | canvas.clipRect(parent.paddingLeft, top, 129 | parent.width - parent.paddingRight, bottom) 130 | } 131 | false -> { 132 | top = 0 133 | bottom = parent.height 134 | } 135 | } 136 | 137 | val childCount = parent.childCount 138 | loop@ for (i in 0 until childCount) { 139 | val child = parent.getChildAt(i) 140 | parent.layoutManager.getDecoratedBoundsWithMargins(child, bounds) 141 | val right = bounds.right + Math.round(ViewCompat.getTranslationX(child)) 142 | 143 | val vh = parent.getChildViewHolder(child) 144 | when(vh) { 145 | is NoDivider -> {} 146 | is GridDivider -> {} 147 | is HorizontalDivider -> { 148 | if(vh is PositionDivider) { 149 | when(vh.positions.any { it == vh.adapterPosition }) { 150 | true -> if (vh.inverted) continue@loop 151 | false -> if (vh.inverted) else continue@loop 152 | } 153 | } 154 | val drawable = dividerMap[vh]?: // Reuse divider 155 | ResourcesCompat.getDrawable(context.resources, vh.drawableRes, null)?.also { 156 | dividerMap.put(vh, it) 157 | } 158 | val left = right - (vh.width + 1) // Line width < Bounds width 159 | drawable?.let { d -> 160 | d.setBounds(left, top, right, bottom) 161 | vh.horizontalInset?.let { 162 | d.bounds.top = d.bounds.top.plus(it.first) 163 | d.bounds.bottom = d.bounds.bottom.minus(it.second) 164 | } 165 | d.draw(canvas) 166 | } 167 | } 168 | is PositionDivider -> { 169 | when(vh.positions.any { it == vh.adapterPosition }) { 170 | true -> if (vh.inverted) continue@loop 171 | false -> if (vh.inverted) else continue@loop 172 | } 173 | val left = right - defaultDivider.intrinsicWidth 174 | defaultDivider.setBounds(left, top, right, bottom) 175 | defaultDivider.draw(canvas) 176 | } 177 | else -> { 178 | val left = right - defaultDivider.intrinsicWidth 179 | defaultDivider.setBounds(left, top, right, bottom) 180 | defaultDivider.draw(canvas) 181 | } 182 | } 183 | } 184 | } 185 | 186 | companion object { 187 | val HORIZONTAL = LinearLayout.HORIZONTAL 188 | val VERTICAL = LinearLayout.VERTICAL 189 | private val ATTRS = intArrayOf(android.R.attr.listDivider) 190 | } 191 | } -------------------------------------------------------------------------------- /multilinedivider/src/main/kotlin/com/sakebook/android/library/multilinedevider/OffsetsCalculator.kt: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedevider 2 | 3 | import android.graphics.Rect 4 | import android.graphics.drawable.Drawable 5 | import android.support.v7.widget.GridLayoutManager 6 | import android.support.v7.widget.RecyclerView 7 | import android.support.v7.widget.StaggeredGridLayoutManager 8 | import com.sakebook.android.library.multilinedevider.divider.* 9 | 10 | /** 11 | * Created by sakemotoshinya on 2017/05/23. 12 | */ 13 | class OffsetsCalculator(val divider: Drawable, val orientation: Int) { 14 | 15 | fun determineOffsets(outRect: Rect, vh: RecyclerView.ViewHolder, parent: RecyclerView) { 16 | val layoutManager = parent.layoutManager 17 | val spanCount = when(layoutManager) { 18 | is GridLayoutManager -> layoutManager.spanCount 19 | is StaggeredGridLayoutManager -> layoutManager.spanCount 20 | else -> -1 21 | } 22 | when(orientation) { 23 | MultiLineDivider.VERTICAL -> determineVerticalOffsets(outRect, vh, spanCount, layoutManager.itemCount) 24 | MultiLineDivider.HORIZONTAL -> determineHorizontalOffsets(outRect, vh, spanCount, layoutManager.itemCount) 25 | } 26 | } 27 | 28 | internal fun determineVerticalOffsets(outRect: Rect, vh: RecyclerView.ViewHolder, spanCount: Int, itemCount: Int) { 29 | when(vh) { 30 | is NoDivider -> outRect.set(0, 0, 0, 0) 31 | is GridDivider -> gridVerticalOffsets(outRect, vh, spanCount, itemCount) 32 | is VerticalDivider -> dividerVerticalOffsets(outRect, vh) 33 | is PositionDivider -> positionVerticalOffsets(outRect, vh) 34 | else -> outRect.set(0, 0, 0, divider.intrinsicHeight) 35 | } 36 | } 37 | 38 | internal fun determineHorizontalOffsets(outRect: Rect, vh: RecyclerView.ViewHolder, spanCount: Int, itemCount: Int) { 39 | when(vh) { 40 | is NoDivider -> outRect.set(0, 0, 0, 0) 41 | is GridDivider -> gridHorizontalOffsets(outRect, vh, spanCount, itemCount) 42 | is HorizontalDivider -> dividerHorizontalOffsets(outRect, vh) 43 | is PositionDivider -> positionHorizontalOffsets(outRect, vh) 44 | else -> outRect.set(0, 0, divider.intrinsicWidth, 0) 45 | } 46 | } 47 | 48 | private fun gridVerticalOffsets(outRect: Rect, vh: RecyclerView.ViewHolder, spanCount: Int, itemCount: Int) { 49 | vh as GridDivider 50 | val padding = vh.padding / 2 51 | val lastGridCount = if (itemCount % spanCount == 0) spanCount else itemCount % spanCount 52 | val cornerPadding = if (vh.fullBleed) 0 else vh.padding 53 | val position = vh.adapterPosition 54 | when(position) { 55 | in 0 until spanCount -> { 56 | // first grid 57 | when(position % spanCount) { 58 | 0 -> outRect.set(cornerPadding, cornerPadding, padding, padding) // left top 59 | spanCount - 1 -> outRect.set(padding, cornerPadding, cornerPadding, padding) // right top, top bottom 60 | else -> outRect.set(padding, cornerPadding, padding, padding) // other 61 | } 62 | } 63 | in (itemCount - lastGridCount until itemCount) -> { 64 | // last grid 65 | when(position % spanCount) { 66 | 0 -> outRect.set(cornerPadding, padding, padding, cornerPadding) // left bottom 67 | spanCount - 1 -> outRect.set(padding, padding, cornerPadding, cornerPadding) // right bottom, bottom right 68 | else -> outRect.set(padding, padding, padding, cornerPadding) // other 69 | } 70 | } 71 | else -> { 72 | when(position % spanCount) { 73 | 0 -> outRect.set(cornerPadding, padding, padding, padding) // left 74 | spanCount - 1 -> outRect.set(padding, padding, cornerPadding, padding) // right 75 | else -> outRect.set(padding, padding, padding, padding) // other 76 | } 77 | } 78 | } 79 | } 80 | 81 | private fun gridHorizontalOffsets(outRect: Rect, vh: RecyclerView.ViewHolder, spanCount: Int, itemCount: Int) { 82 | vh as GridDivider 83 | val padding = vh.padding / 2 84 | val lastGridCount = if (itemCount % spanCount == 0) spanCount else itemCount % spanCount 85 | val cornerPadding = if (vh.fullBleed) 0 else vh.padding 86 | val position = vh.adapterPosition 87 | when(position) { 88 | in 0 until spanCount -> { 89 | // first grid 90 | when(position % spanCount) { 91 | 0 -> outRect.set(cornerPadding, cornerPadding, padding, padding) // top left 92 | spanCount - 1 -> outRect.set(cornerPadding, padding, padding, cornerPadding) // right top, top bottom 93 | else -> outRect.set(cornerPadding, padding, padding, padding) // other 94 | } 95 | } 96 | in (itemCount - lastGridCount until itemCount) -> { 97 | // last grid 98 | when(position % spanCount) { 99 | 0 -> outRect.set(padding, cornerPadding, cornerPadding, padding) // bottom left 100 | spanCount - 1 -> outRect.set(padding, padding, cornerPadding, cornerPadding) // right bottom, bottom right 101 | else -> outRect.set(padding, padding, cornerPadding, padding) // other 102 | } 103 | } 104 | else -> { 105 | when(position % spanCount) { 106 | 0 -> outRect.set(padding, cornerPadding, padding, padding) // top 107 | spanCount - 1 -> outRect.set(padding, padding, padding, cornerPadding) // bottom 108 | else -> outRect.set(padding, padding, padding, padding) // other 109 | } 110 | } 111 | } 112 | } 113 | 114 | private fun dividerVerticalOffsets(outRect: Rect, vh: RecyclerView.ViewHolder) { 115 | vh as VerticalDivider 116 | val position = vh.adapterPosition 117 | when(vh is PositionDivider){ 118 | true -> { 119 | vh as PositionDivider 120 | when(vh.positions.any { it == position }) { 121 | true -> outRect.set(0, 0, 0, if (vh.inverted) vh.height else 0) 122 | false -> outRect.set(0, 0, 0, if (vh.inverted) 0 else vh.height) 123 | } 124 | } 125 | false -> outRect.set(0, 0, 0, vh.height) 126 | } 127 | } 128 | 129 | private fun dividerHorizontalOffsets(outRect: Rect, vh: RecyclerView.ViewHolder) { 130 | vh as HorizontalDivider 131 | val position = vh.adapterPosition 132 | when(vh is PositionDivider){ 133 | true -> { 134 | vh as PositionDivider 135 | when(vh.positions.any { it == position }) { 136 | true -> outRect.set(0, 0, if (vh.inverted) vh.width else 0, 0) 137 | false -> outRect.set(0, 0, if (vh.inverted) 0 else vh.width, 0) 138 | } 139 | } 140 | false -> outRect.set(0, 0, vh.width, 0) 141 | } 142 | } 143 | 144 | private fun positionVerticalOffsets(outRect: Rect, vh: RecyclerView.ViewHolder) { 145 | vh as PositionDivider 146 | val position = vh.adapterPosition 147 | when(vh.positions.any { it == position }) { 148 | true -> outRect.set(0, 0, 0, if (vh.inverted) divider.intrinsicHeight else 0) 149 | false -> outRect.set(0, 0, 0, if (vh.inverted) 0 else divider.intrinsicHeight) 150 | } 151 | } 152 | 153 | private fun positionHorizontalOffsets(outRect: Rect, vh: RecyclerView.ViewHolder) { 154 | vh as PositionDivider 155 | val position = vh.adapterPosition 156 | when(vh.positions.any { it == position }) { 157 | true -> outRect.set(0, 0, if (vh.inverted) divider.intrinsicWidth else 0, 0) 158 | false -> outRect.set(0, 0, if (vh.inverted) 0 else divider.intrinsicWidth, 0) 159 | } 160 | } 161 | } -------------------------------------------------------------------------------- /multilinedivider/src/main/kotlin/com/sakebook/android/library/multilinedevider/divider/Divider.kt: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedevider.divider 2 | 3 | /** 4 | * Created by sakemotoshinya on 2017/04/24. 5 | */ 6 | interface Divider { 7 | } -------------------------------------------------------------------------------- /multilinedivider/src/main/kotlin/com/sakebook/android/library/multilinedevider/divider/GridDivider.kt: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedevider.divider 2 | 3 | /** 4 | * Created by sakemotoshinya on 2017/05/16. 5 | */ 6 | interface GridDivider: Divider { 7 | val padding: Int 8 | val fullBleed: Boolean 9 | } -------------------------------------------------------------------------------- /multilinedivider/src/main/kotlin/com/sakebook/android/library/multilinedevider/divider/HorizontalDivider.kt: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedevider.divider 2 | 3 | import android.support.v4.util.Pair 4 | 5 | /** 6 | * Created by sakemotoshinya on 2017/04/24. 7 | */ 8 | interface HorizontalDivider: Divider { 9 | val width: Int 10 | val drawableRes: Int 11 | val horizontalInset: Pair? 12 | } -------------------------------------------------------------------------------- /multilinedivider/src/main/kotlin/com/sakebook/android/library/multilinedevider/divider/NoDivider.kt: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedevider.divider 2 | 3 | /** 4 | * Created by sakemotoshinya on 2017/04/24. 5 | */ 6 | interface NoDivider: Divider { 7 | } -------------------------------------------------------------------------------- /multilinedivider/src/main/kotlin/com/sakebook/android/library/multilinedevider/divider/PositionDivider.kt: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedevider.divider 2 | 3 | /** 4 | * Created by sakemotoshinya on 2017/05/21. 5 | */ 6 | interface PositionDivider: Divider { 7 | val positions: List 8 | val inverted: Boolean 9 | } -------------------------------------------------------------------------------- /multilinedivider/src/main/kotlin/com/sakebook/android/library/multilinedevider/divider/VerticalDivider.kt: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedevider.divider 2 | 3 | import android.support.v4.util.Pair 4 | 5 | /** 6 | * Created by sakemotoshinya on 2017/04/24. 7 | */ 8 | interface VerticalDivider: Divider { 9 | val height: Int 10 | val drawableRes: Int 11 | val verticalInset: Pair? 12 | } -------------------------------------------------------------------------------- /multilinedivider/src/main/res/drawable/simple_divider.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /multilinedivider/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | MultiLineDevider 3 | 4 | -------------------------------------------------------------------------------- /multilinedivider/src/test/kotlin/com/sakebook/android/library/multilinedevider/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedevider 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | 10 | * @see [Testing documentation](http://d.android.com/tools/testing) 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | @Throws(Exception::class) 15 | fun addition_isCorrect() { 16 | assertEquals(4, (2 + 2).toLong()) 17 | } 18 | } -------------------------------------------------------------------------------- /multilinedivider/src/test/kotlin/com/sakebook/android/library/multilinedevider/OffsetsCalculatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedevider 2 | 3 | import android.graphics.Rect 4 | import android.graphics.drawable.Drawable 5 | import android.support.v4.util.Pair 6 | import android.support.v7.widget.RecyclerView 7 | import android.view.View 8 | import com.sakebook.android.library.multilinedevider.divider.* 9 | import org.junit.Assert 10 | import org.junit.Before 11 | import org.junit.Test 12 | import org.junit.runner.RunWith 13 | import org.mockito.Mockito 14 | import org.robolectric.RobolectricTestRunner 15 | import org.robolectric.RuntimeEnvironment 16 | import org.robolectric.annotation.Config 17 | 18 | /** 19 | * Created by sakemotoshinya on 2017/05/24. 20 | */ 21 | @RunWith(RobolectricTestRunner::class) 22 | @Config(constants = BuildConfig::class, sdk = intArrayOf(21)) 23 | class OffsetsCalculatorTest { 24 | 25 | val PADDING = 8 26 | val PADDINGx2 = PADDING * 2 27 | val PADDINGx3 = PADDING * 3 28 | val PADDINGx4 = PADDING * 4 29 | val PADDINGx5 = PADDING * 5 30 | val PADDINGx6 = PADDING * 6 31 | 32 | val mockDrawable = Mockito.mock(Drawable::class.java).also { 33 | Mockito.`when`(it.intrinsicHeight).thenReturn(PADDING) 34 | Mockito.`when`(it.intrinsicWidth).thenReturn(PADDING) 35 | } 36 | val context = RuntimeEnvironment.application 37 | 38 | @Before 39 | @Throws(Exception::class) 40 | fun setup() { 41 | } 42 | 43 | // GridDivider 44 | 45 | @Test 46 | @Throws(Exception::class) 47 | fun testVerticalGridFirst() { 48 | val offsetCalculator = OffsetsCalculator(mockDrawable, MultiLineDivider.VERTICAL) 49 | val view = View(context) 50 | val vh = GridViewHolder(view, PADDINGx6, false) 51 | val mockViewHolder = Mockito.spy(vh) 52 | Mockito.`when`(mockViewHolder.adapterPosition).thenReturn(0, 1, 2, 3, 4, 5) 53 | val expectTopLeft = Rect(PADDINGx6, PADDINGx6, PADDINGx3, PADDINGx3) 54 | val expectTopCenter = Rect(PADDINGx3, PADDINGx6, PADDINGx3, PADDINGx3) 55 | val expectTopRight = Rect(PADDINGx3, PADDINGx6, PADDINGx6, PADDINGx3) 56 | val expectLeft = Rect(PADDINGx6, PADDINGx3, PADDINGx3, PADDINGx3) 57 | val expectCenter = Rect(PADDINGx3, PADDINGx3, PADDINGx3, PADDINGx3) 58 | val expectRight = Rect(PADDINGx3, PADDINGx3, PADDINGx6, PADDINGx3) 59 | val actual = Rect() 60 | 61 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 62 | Assert.assertEquals(expectTopLeft, actual) 63 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 64 | Assert.assertEquals(expectTopCenter, actual) 65 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 66 | Assert.assertEquals(expectTopRight, actual) 67 | 68 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 69 | Assert.assertEquals(expectLeft, actual) 70 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 71 | Assert.assertEquals(expectCenter, actual) 72 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 73 | Assert.assertEquals(expectRight, actual) 74 | } 75 | 76 | @Test 77 | @Throws(Exception::class) 78 | fun testVerticalGridLast() { 79 | val offsetCalculator = OffsetsCalculator(mockDrawable, MultiLineDivider.VERTICAL) 80 | val view = View(context) 81 | val vh = GridViewHolder(view, PADDINGx6, false) 82 | val mockViewHolder = Mockito.spy(vh) 83 | Mockito.`when`(mockViewHolder.adapterPosition).thenReturn(114, 115, 116, 117, 118, 119) 84 | val expectLeft = Rect(PADDINGx6, PADDINGx3, PADDINGx3, PADDINGx3) 85 | val expectCenter = Rect(PADDINGx3, PADDINGx3, PADDINGx3, PADDINGx3) 86 | val expectRight = Rect(PADDINGx3, PADDINGx3, PADDINGx6, PADDINGx3) 87 | val expectBottomLeft = Rect(PADDINGx6, PADDINGx3, PADDINGx3, PADDINGx6) 88 | val expectBottomCenter = Rect(PADDINGx3, PADDINGx3, PADDINGx3, PADDINGx6) 89 | val expectBottomRight = Rect(PADDINGx3, PADDINGx3, PADDINGx6, PADDINGx6) 90 | val actual = Rect() 91 | 92 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 93 | Assert.assertEquals(expectLeft, actual) 94 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 95 | Assert.assertEquals(expectCenter, actual) 96 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 97 | Assert.assertEquals(expectRight, actual) 98 | 99 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 100 | Assert.assertEquals(expectBottomLeft, actual) 101 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 102 | Assert.assertEquals(expectBottomCenter, actual) 103 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 104 | Assert.assertEquals(expectBottomRight, actual) 105 | } 106 | 107 | @Test 108 | @Throws(Exception::class) 109 | fun testHorizontalGridFirst() { 110 | val offsetCalculator = OffsetsCalculator(mockDrawable, MultiLineDivider.HORIZONTAL) 111 | val view = View(context) 112 | val vh = GridViewHolder(view, PADDINGx6, false) 113 | val mockViewHolder = Mockito.spy(vh) 114 | Mockito.`when`(mockViewHolder.adapterPosition).thenReturn(0, 1, 2, 3, 4, 5) 115 | val expectLeftTop = Rect(PADDINGx6, PADDINGx6, PADDINGx3, PADDINGx3) 116 | val expectLeftCenter = Rect(PADDINGx6, PADDINGx3, PADDINGx3, PADDINGx3) 117 | val expectLeftBottom = Rect(PADDINGx6, PADDINGx3, PADDINGx3, PADDINGx6) 118 | val expectTop = Rect(PADDINGx3, PADDINGx6, PADDINGx3, PADDINGx3) 119 | val expectCenter = Rect(PADDINGx3, PADDINGx3, PADDINGx3, PADDINGx3) 120 | val expectBottom = Rect(PADDINGx3, PADDINGx3, PADDINGx3, PADDINGx6) 121 | val actual = Rect() 122 | 123 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 124 | Assert.assertEquals(expectLeftTop, actual) 125 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 126 | Assert.assertEquals(expectLeftCenter, actual) 127 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 128 | Assert.assertEquals(expectLeftBottom, actual) 129 | 130 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 131 | Assert.assertEquals(expectTop, actual) 132 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 133 | Assert.assertEquals(expectCenter, actual) 134 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 135 | Assert.assertEquals(expectBottom, actual) 136 | } 137 | 138 | @Test 139 | @Throws(Exception::class) 140 | fun testHorizontalGridLast() { 141 | val offsetCalculator = OffsetsCalculator(mockDrawable, MultiLineDivider.HORIZONTAL) 142 | val view = View(context) 143 | val vh = GridViewHolder(view, PADDINGx6, false) 144 | val mockViewHolder = Mockito.spy(vh) 145 | Mockito.`when`(mockViewHolder.adapterPosition).thenReturn(114, 115, 116, 117, 118, 119) 146 | val expectTop = Rect(PADDINGx3, PADDINGx6, PADDINGx3, PADDINGx3) 147 | val expectCenter = Rect(PADDINGx3, PADDINGx3, PADDINGx3, PADDINGx3) 148 | val expectBottom = Rect(PADDINGx3, PADDINGx3, PADDINGx3, PADDINGx6) 149 | val expectRightTop = Rect(PADDINGx3, PADDINGx6, PADDINGx6, PADDINGx3) 150 | val expectRightCenter = Rect(PADDINGx3, PADDINGx3, PADDINGx6, PADDINGx3) 151 | val expectRightBottom = Rect(PADDINGx3, PADDINGx3, PADDINGx6, PADDINGx6) 152 | val actual = Rect() 153 | 154 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 155 | Assert.assertEquals(expectTop, actual) 156 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 157 | Assert.assertEquals(expectCenter, actual) 158 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 159 | Assert.assertEquals(expectBottom, actual) 160 | 161 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 162 | Assert.assertEquals(expectRightTop, actual) 163 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 164 | Assert.assertEquals(expectRightCenter, actual) 165 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 166 | Assert.assertEquals(expectRightBottom, actual) 167 | } 168 | 169 | @Test 170 | @Throws(Exception::class) 171 | fun testVerticalFullBleedGridFirst() { 172 | val offsetCalculator = OffsetsCalculator(mockDrawable, MultiLineDivider.VERTICAL) 173 | val view = View(context) 174 | val vh = GridViewHolder(view, PADDINGx6, true) 175 | val mockViewHolder = Mockito.spy(vh) 176 | Mockito.`when`(mockViewHolder.adapterPosition).thenReturn(0, 1, 2, 3, 4, 5) 177 | val expectTopLeft = Rect(0, 0, PADDINGx3, PADDINGx3) 178 | val expectTopCenter = Rect(PADDINGx3, 0, PADDINGx3, PADDINGx3) 179 | val expectTopRight = Rect(PADDINGx3, 0, 0, PADDINGx3) 180 | val expectLeft = Rect(0, PADDINGx3, PADDINGx3, PADDINGx3) 181 | val expectCenter = Rect(PADDINGx3, PADDINGx3, PADDINGx3, PADDINGx3) 182 | val expectRight = Rect(PADDINGx3, PADDINGx3, 0, PADDINGx3) 183 | val actual = Rect() 184 | 185 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 186 | Assert.assertEquals(expectTopLeft, actual) 187 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 188 | Assert.assertEquals(expectTopCenter, actual) 189 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 190 | Assert.assertEquals(expectTopRight, actual) 191 | 192 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 193 | Assert.assertEquals(expectLeft, actual) 194 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 195 | Assert.assertEquals(expectCenter, actual) 196 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 197 | Assert.assertEquals(expectRight, actual) 198 | } 199 | 200 | @Test 201 | @Throws(Exception::class) 202 | fun testVerticalFullBleedGridLast() { 203 | val offsetCalculator = OffsetsCalculator(mockDrawable, MultiLineDivider.VERTICAL) 204 | val view = View(context) 205 | val vh = GridViewHolder(view, PADDINGx6, true) 206 | val mockViewHolder = Mockito.spy(vh) 207 | Mockito.`when`(mockViewHolder.adapterPosition).thenReturn(114, 115, 116, 117, 118, 119) 208 | val expectLeft = Rect(0, PADDINGx3, PADDINGx3, PADDINGx3) 209 | val expectCenter = Rect(PADDINGx3, PADDINGx3, PADDINGx3, PADDINGx3) 210 | val expectRight = Rect(PADDINGx3, PADDINGx3, 0, PADDINGx3) 211 | val expectBottomLeft = Rect(0, PADDINGx3, PADDINGx3, 0) 212 | val expectBottomCenter = Rect(PADDINGx3, PADDINGx3, PADDINGx3, 0) 213 | val expectBottomRight = Rect(PADDINGx3, PADDINGx3, 0, 0) 214 | val actual = Rect() 215 | 216 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 217 | Assert.assertEquals(expectLeft, actual) 218 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 219 | Assert.assertEquals(expectCenter, actual) 220 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 221 | Assert.assertEquals(expectRight, actual) 222 | 223 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 224 | Assert.assertEquals(expectBottomLeft, actual) 225 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 226 | Assert.assertEquals(expectBottomCenter, actual) 227 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, 3, 120) 228 | Assert.assertEquals(expectBottomRight, actual) 229 | } 230 | 231 | @Test 232 | @Throws(Exception::class) 233 | fun testHorizontalFullBleedGridFirst() { 234 | val offsetCalculator = OffsetsCalculator(mockDrawable, MultiLineDivider.HORIZONTAL) 235 | val view = View(context) 236 | val vh = GridViewHolder(view, PADDINGx6, true) 237 | val mockViewHolder = Mockito.spy(vh) 238 | Mockito.`when`(mockViewHolder.adapterPosition).thenReturn(0, 1, 2, 3, 4, 5) 239 | val expectLeftTop = Rect(0, 0, PADDINGx3, PADDINGx3) 240 | val expectLeftCenter = Rect(0, PADDINGx3, PADDINGx3, PADDINGx3) 241 | val expectLeftBottom = Rect(0, PADDINGx3, PADDINGx3, 0) 242 | val expectTop = Rect(PADDINGx3, 0, PADDINGx3, PADDINGx3) 243 | val expectCenter = Rect(PADDINGx3, PADDINGx3, PADDINGx3, PADDINGx3) 244 | val expectBottom = Rect(PADDINGx3, PADDINGx3, PADDINGx3, 0) 245 | val actual = Rect() 246 | 247 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 248 | Assert.assertEquals(expectLeftTop, actual) 249 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 250 | Assert.assertEquals(expectLeftCenter, actual) 251 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 252 | Assert.assertEquals(expectLeftBottom, actual) 253 | 254 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 255 | Assert.assertEquals(expectTop, actual) 256 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 257 | Assert.assertEquals(expectCenter, actual) 258 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 259 | Assert.assertEquals(expectBottom, actual) 260 | } 261 | 262 | @Test 263 | @Throws(Exception::class) 264 | fun testHorizontalFullBleedGridLast() { 265 | val offsetCalculator = OffsetsCalculator(mockDrawable, MultiLineDivider.HORIZONTAL) 266 | val view = View(context) 267 | val vh = GridViewHolder(view, PADDINGx6, true) 268 | val mockViewHolder = Mockito.spy(vh) 269 | Mockito.`when`(mockViewHolder.adapterPosition).thenReturn(114, 115, 116, 117, 118, 119) 270 | val expectTop = Rect(PADDINGx3, 0, PADDINGx3, PADDINGx3) 271 | val expectCenter = Rect(PADDINGx3, PADDINGx3, PADDINGx3, PADDINGx3) 272 | val expectBottom = Rect(PADDINGx3, PADDINGx3, PADDINGx3, 0) 273 | val expectRightTop = Rect(PADDINGx3, 0, 0, PADDINGx3) 274 | val expectRightCenter = Rect(PADDINGx3, PADDINGx3, 0, PADDINGx3) 275 | val expectRightBottom = Rect(PADDINGx3, PADDINGx3, 0, 0) 276 | val actual = Rect() 277 | 278 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 279 | Assert.assertEquals(expectTop, actual) 280 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 281 | Assert.assertEquals(expectCenter, actual) 282 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 283 | Assert.assertEquals(expectBottom, actual) 284 | 285 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 286 | Assert.assertEquals(expectRightTop, actual) 287 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 288 | Assert.assertEquals(expectRightCenter, actual) 289 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, 3, 120) 290 | Assert.assertEquals(expectRightBottom, actual) 291 | } 292 | 293 | // PositionDivider 294 | 295 | @Test 296 | @Throws(Exception::class) 297 | fun testVerticalPosition() { 298 | val offsetCalculator = OffsetsCalculator(mockDrawable, MultiLineDivider.VERTICAL) 299 | val view = View(context) 300 | val vh = PositionViewHolder(view, listOf(2, 3, 5), false) 301 | val mockViewHolder = Mockito.spy(vh) 302 | Mockito.`when`(mockViewHolder.adapterPosition).thenReturn(0, 1 ,2 ,3, 4, 5) 303 | val expectDivider = Rect(0, 0, 0, PADDING) 304 | val expectNoDivider = Rect(0, 0, 0, 0) 305 | val actual = Rect() 306 | 307 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 308 | Assert.assertEquals(expectDivider, actual) 309 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 310 | Assert.assertEquals(expectDivider, actual) 311 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 312 | Assert.assertEquals(expectNoDivider, actual) 313 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 314 | Assert.assertEquals(expectNoDivider, actual) 315 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 316 | Assert.assertEquals(expectDivider, actual) 317 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 318 | Assert.assertEquals(expectNoDivider, actual) 319 | } 320 | 321 | @Test 322 | @Throws(Exception::class) 323 | fun testHorizontalPosition() { 324 | val offsetCalculator = OffsetsCalculator(mockDrawable, MultiLineDivider.HORIZONTAL) 325 | val view = View(context) 326 | val vh = PositionViewHolder(view, listOf(2, 3, 5), false) 327 | val mockViewHolder = Mockito.spy(vh) 328 | Mockito.`when`(mockViewHolder.adapterPosition).thenReturn(0, 1 ,2 ,3, 4, 5) 329 | val expectDivider = Rect(0, 0, PADDING, 0) 330 | val expectNoDivider = Rect(0, 0, 0, 0) 331 | val actual = Rect() 332 | 333 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 334 | Assert.assertEquals(expectDivider, actual) 335 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 336 | Assert.assertEquals(expectDivider, actual) 337 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 338 | Assert.assertEquals(expectNoDivider, actual) 339 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 340 | Assert.assertEquals(expectNoDivider, actual) 341 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 342 | Assert.assertEquals(expectDivider, actual) 343 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 344 | Assert.assertEquals(expectNoDivider, actual) 345 | } 346 | 347 | @Test 348 | @Throws(Exception::class) 349 | fun testVerticalPositionInverted() { 350 | val offsetCalculator = OffsetsCalculator(mockDrawable, MultiLineDivider.VERTICAL) 351 | val view = View(context) 352 | val vh = PositionViewHolder(view, listOf(2, 3, 5), true) 353 | val mockViewHolder = Mockito.spy(vh) 354 | Mockito.`when`(mockViewHolder.adapterPosition).thenReturn(0, 1 ,2 ,3, 4, 5) 355 | val expectDivider = Rect(0, 0, 0, PADDING) 356 | val expectNoDivider = Rect(0, 0, 0, 0) 357 | val actual = Rect() 358 | 359 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 360 | Assert.assertEquals(expectNoDivider, actual) 361 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 362 | Assert.assertEquals(expectNoDivider, actual) 363 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 364 | Assert.assertEquals(expectDivider, actual) 365 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 366 | Assert.assertEquals(expectDivider, actual) 367 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 368 | Assert.assertEquals(expectNoDivider, actual) 369 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 370 | Assert.assertEquals(expectDivider, actual) 371 | } 372 | 373 | @Test 374 | @Throws(Exception::class) 375 | fun testHorizontalPositionInverted() { 376 | val offsetCalculator = OffsetsCalculator(mockDrawable, MultiLineDivider.HORIZONTAL) 377 | val view = View(context) 378 | val vh = PositionViewHolder(view, listOf(2, 3, 5), true) 379 | val mockViewHolder = Mockito.spy(vh) 380 | Mockito.`when`(mockViewHolder.adapterPosition).thenReturn(0, 1 ,2 ,3, 4, 5) 381 | val expectDivider = Rect(0, 0, PADDING, 0) 382 | val expectNoDivider = Rect(0, 0, 0, 0) 383 | val actual = Rect() 384 | 385 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 386 | Assert.assertEquals(expectNoDivider, actual) 387 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 388 | Assert.assertEquals(expectNoDivider, actual) 389 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 390 | Assert.assertEquals(expectDivider, actual) 391 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 392 | Assert.assertEquals(expectDivider, actual) 393 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 394 | Assert.assertEquals(expectNoDivider, actual) 395 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 396 | Assert.assertEquals(expectDivider, actual) 397 | } 398 | 399 | // NoDivider 400 | 401 | @Test 402 | @Throws(Exception::class) 403 | fun testVerticalNoDivider() { 404 | val offsetCalculator = OffsetsCalculator(mockDrawable, MultiLineDivider.VERTICAL) 405 | val view = View(context) 406 | val vh = NoDividerViewHolder(view) 407 | val mockViewHolder = Mockito.spy(vh) 408 | Mockito.`when`(mockViewHolder.adapterPosition).thenReturn(0, 1 ,2) 409 | val expectNoDivider = Rect(0, 0, 0, 0) 410 | val actual = Rect() 411 | 412 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 413 | Assert.assertEquals(expectNoDivider, actual) 414 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 415 | Assert.assertEquals(expectNoDivider, actual) 416 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 417 | Assert.assertEquals(expectNoDivider, actual) 418 | } 419 | 420 | @Test 421 | @Throws(Exception::class) 422 | fun testHorizontalNoDivider() { 423 | val offsetCalculator = OffsetsCalculator(mockDrawable, MultiLineDivider.HORIZONTAL) 424 | val view = View(context) 425 | val vh = NoDividerViewHolder(view) 426 | val mockViewHolder = Mockito.spy(vh) 427 | Mockito.`when`(mockViewHolder.adapterPosition).thenReturn(0, 1 ,2) 428 | val expectNoDivider = Rect(0, 0, 0, 0) 429 | val actual = Rect() 430 | 431 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 432 | Assert.assertEquals(expectNoDivider, actual) 433 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 434 | Assert.assertEquals(expectNoDivider, actual) 435 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 436 | Assert.assertEquals(expectNoDivider, actual) 437 | } 438 | 439 | // VerticalDivider 440 | 441 | @Test 442 | @Throws(Exception::class) 443 | fun testVertical() { 444 | val offsetCalculator = OffsetsCalculator(mockDrawable, MultiLineDivider.VERTICAL) 445 | val view = View(context) 446 | val vh = VerticalViewHolder(view, PADDINGx3, R.drawable.simple_divider, null) 447 | val mockViewHolder = Mockito.spy(vh) 448 | Mockito.`when`(mockViewHolder.adapterPosition).thenReturn(0, 1 ,2) 449 | val expectDivider = Rect(0, 0, 0, PADDINGx3) 450 | val actual = Rect() 451 | 452 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 453 | Assert.assertEquals(expectDivider, actual) 454 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 455 | Assert.assertEquals(expectDivider, actual) 456 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 457 | Assert.assertEquals(expectDivider, actual) 458 | } 459 | 460 | // HorizontalDivider 461 | 462 | @Test 463 | @Throws(Exception::class) 464 | fun testHorizontal() { 465 | val offsetCalculator = OffsetsCalculator(mockDrawable, MultiLineDivider.HORIZONTAL) 466 | val view = View(context) 467 | val vh = HorizontalViewHolder(view, PADDINGx3, R.drawable.simple_divider, null) 468 | val mockViewHolder = Mockito.spy(vh) 469 | Mockito.`when`(mockViewHolder.adapterPosition).thenReturn(0, 1 ,2) 470 | val expectDivider = Rect(0, 0, PADDINGx3, 0) 471 | val actual = Rect() 472 | 473 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 474 | Assert.assertEquals(expectDivider, actual) 475 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 476 | Assert.assertEquals(expectDivider, actual) 477 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 478 | Assert.assertEquals(expectDivider, actual) 479 | } 480 | 481 | // VerticalDivider with PositionDivider 482 | 483 | @Test 484 | @Throws(Exception::class) 485 | fun testVerticalWithPosition() { 486 | val offsetCalculator = OffsetsCalculator(mockDrawable, MultiLineDivider.VERTICAL) 487 | val view = View(context) 488 | val vh = VerticalWithPositionDividerViewHolder(view, PADDINGx3, R.drawable.simple_divider, null, listOf(2, 3, 5), false) 489 | val mockViewHolder = Mockito.spy(vh) 490 | Mockito.`when`(mockViewHolder.adapterPosition).thenReturn(0, 1 ,2, 3 ,4, 5) 491 | val expectDivider = Rect(0, 0, 0, PADDINGx3) 492 | val expectNoDivider = Rect(0, 0, 0, 0) 493 | val actual = Rect() 494 | 495 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 496 | Assert.assertEquals(expectDivider, actual) 497 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 498 | Assert.assertEquals(expectDivider, actual) 499 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 500 | Assert.assertEquals(expectNoDivider, actual) 501 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 502 | Assert.assertEquals(expectNoDivider, actual) 503 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 504 | Assert.assertEquals(expectDivider, actual) 505 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 506 | Assert.assertEquals(expectNoDivider, actual) 507 | } 508 | 509 | @Test 510 | @Throws(Exception::class) 511 | fun testVerticalWithPositionInverted() { 512 | val offsetCalculator = OffsetsCalculator(mockDrawable, MultiLineDivider.VERTICAL) 513 | val view = View(context) 514 | val vh = VerticalWithPositionDividerViewHolder(view, PADDINGx3, R.drawable.simple_divider, null, listOf(2, 3, 5), true) 515 | val mockViewHolder = Mockito.spy(vh) 516 | Mockito.`when`(mockViewHolder.adapterPosition).thenReturn(0, 1 ,2, 3 ,4, 5) 517 | val expectDivider = Rect(0, 0, 0, PADDINGx3) 518 | val expectNoDivider = Rect(0, 0, 0, 0) 519 | val actual = Rect() 520 | 521 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 522 | Assert.assertEquals(expectNoDivider, actual) 523 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 524 | Assert.assertEquals(expectNoDivider, actual) 525 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 526 | Assert.assertEquals(expectDivider, actual) 527 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 528 | Assert.assertEquals(expectDivider, actual) 529 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 530 | Assert.assertEquals(expectNoDivider, actual) 531 | offsetCalculator.determineVerticalOffsets(actual, mockViewHolder, -1, 120) 532 | Assert.assertEquals(expectDivider, actual) 533 | } 534 | 535 | // HorizontalDivider with PositionDivider 536 | 537 | @Test 538 | @Throws(Exception::class) 539 | fun testHorizontalWithPosition() { 540 | val offsetCalculator = OffsetsCalculator(mockDrawable, MultiLineDivider.HORIZONTAL) 541 | val view = View(context) 542 | val vh = HorizontalWithPositionDividerViewHolder(view, PADDINGx3, R.drawable.simple_divider, null, listOf(2, 3, 5), false) 543 | val mockViewHolder = Mockito.spy(vh) 544 | Mockito.`when`(mockViewHolder.adapterPosition).thenReturn(0, 1 ,2 ,3, 4, 5) 545 | val expectDivider = Rect(0, 0, PADDINGx3, 0) 546 | val expectNoDivider = Rect(0, 0, 0, 0) 547 | val actual = Rect() 548 | 549 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 550 | Assert.assertEquals(expectDivider, actual) 551 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 552 | Assert.assertEquals(expectDivider, actual) 553 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 554 | Assert.assertEquals(expectNoDivider, actual) 555 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 556 | Assert.assertEquals(expectNoDivider, actual) 557 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 558 | Assert.assertEquals(expectDivider, actual) 559 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 560 | Assert.assertEquals(expectNoDivider, actual) 561 | } 562 | 563 | @Test 564 | @Throws(Exception::class) 565 | fun testHorizontalWithPositionInverted() { 566 | val offsetCalculator = OffsetsCalculator(mockDrawable, MultiLineDivider.HORIZONTAL) 567 | val view = View(context) 568 | val vh = HorizontalWithPositionDividerViewHolder(view, PADDINGx3, R.drawable.simple_divider, null, listOf(2, 3, 5), true) 569 | val mockViewHolder = Mockito.spy(vh) 570 | Mockito.`when`(mockViewHolder.adapterPosition).thenReturn(0, 1 ,2 ,3, 4, 5) 571 | val expectDivider = Rect(0, 0, PADDINGx3, 0) 572 | val expectNoDivider = Rect(0, 0, 0, 0) 573 | val actual = Rect() 574 | 575 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 576 | Assert.assertEquals(expectNoDivider, actual) 577 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 578 | Assert.assertEquals(expectNoDivider, actual) 579 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 580 | Assert.assertEquals(expectDivider, actual) 581 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 582 | Assert.assertEquals(expectDivider, actual) 583 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 584 | Assert.assertEquals(expectNoDivider, actual) 585 | offsetCalculator.determineHorizontalOffsets(actual, mockViewHolder, -1, 120) 586 | Assert.assertEquals(expectDivider, actual) 587 | } 588 | 589 | class GridViewHolder(view: View, override val padding: Int, override val fullBleed: Boolean) : RecyclerView.ViewHolder(view), GridDivider 590 | class PositionViewHolder(view: View, override val positions: List, override val inverted: Boolean) : RecyclerView.ViewHolder(view), PositionDivider 591 | class VerticalViewHolder(view: View, override val height: Int, override val drawableRes: Int, override val verticalInset: Pair?) : RecyclerView.ViewHolder(view), VerticalDivider 592 | class HorizontalViewHolder(view: View, override val width: Int, override val drawableRes: Int, override val horizontalInset: Pair?) : RecyclerView.ViewHolder(view), HorizontalDivider 593 | class NoDividerViewHolder(view: View): RecyclerView.ViewHolder(view), NoDivider 594 | class VerticalWithPositionDividerViewHolder(view: View, override val height: Int, override val drawableRes: Int, override val verticalInset: Pair?, override val positions: List, override val inverted: Boolean) : RecyclerView.ViewHolder(view), VerticalDivider, PositionDivider 595 | class HorizontalWithPositionDividerViewHolder(view: View, override val width: Int, override val drawableRes: Int, override val horizontalInset: Pair?, override val positions: List, override val inverted: Boolean) : RecyclerView.ViewHolder(view), HorizontalDivider, PositionDivider 596 | } -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.3" 6 | defaultConfig { 7 | applicationId "com.sakebook.android.library.multilinedividersample" 8 | minSdkVersion 16 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile project(path: ':multilinedivider') 28 | compile "com.android.support:appcompat-v7:$support_library_version" 29 | testCompile 'junit:junit:4.12' 30 | } 31 | -------------------------------------------------------------------------------- /sample/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Applications/adt-bundle-mac-x86_64-20130219/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /sample/src/androidTest/java/com/sakebook/android/library/multilinedividersample/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.sakebook.android.library.multilinedividersample", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/ContactActivity.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.os.Bundle; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.widget.LinearLayout; 10 | 11 | import com.sakebook.android.library.multilinedevider.MultiLineDivider; 12 | import com.sakebook.android.library.multilinedividersample.inset.Contact; 13 | import com.sakebook.android.library.multilinedividersample.inset.RecyclerAdapter; 14 | 15 | import java.util.ArrayList; 16 | 17 | public class ContactActivity extends AppCompatActivity { 18 | 19 | public static Intent createIntent(Context context) { 20 | Intent intent = new Intent(context, ContactActivity.class); 21 | return intent; 22 | } 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | setContentView(R.layout.activity_contact); 28 | initList(); 29 | } 30 | 31 | private void initList() { 32 | RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); 33 | RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this, LinearLayout.VERTICAL, false); 34 | recyclerView.setLayoutManager(layoutManager); 35 | MultiLineDivider multiLineDivider = new MultiLineDivider(this, LinearLayout.VERTICAL); 36 | recyclerView.addItemDecoration(multiLineDivider); 37 | RecyclerAdapter recyclerAdapter = new RecyclerAdapter(this, createFavoriteData(), createData()); 38 | recyclerView.setAdapter(recyclerAdapter); 39 | } 40 | 41 | private ArrayList createFavoriteData() { 42 | ArrayList arrayList = new ArrayList<>(); 43 | String[] names = getResources().getStringArray(R.array.favorite_contact_names); 44 | for (String name: names) { 45 | arrayList.add(new Contact(name, true)); 46 | } 47 | return arrayList; 48 | } 49 | 50 | private ArrayList createData() { 51 | ArrayList arrayList = new ArrayList<>(); 52 | String[] names = getResources().getStringArray(R.array.contact_names); 53 | for (String name: names) { 54 | arrayList.add(new Contact(name, false)); 55 | } 56 | return arrayList; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/GridActivity.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.graphics.Color; 6 | import android.os.Bundle; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.support.v7.widget.GridLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.widget.LinearLayout; 11 | 12 | import com.sakebook.android.library.multilinedevider.MultiLineDivider; 13 | import com.sakebook.android.library.multilinedividersample.grid.RecyclerAdapter; 14 | 15 | import java.util.ArrayList; 16 | 17 | /** 18 | * Created by sakemotoshinya on 2017/05/15. 19 | */ 20 | 21 | public class GridActivity extends AppCompatActivity { 22 | 23 | private final static String ORIENTATION = "orientation"; 24 | private final static String FULL_BLEED = "full_bleed"; 25 | 26 | public static Intent createIntent(Context context, boolean isFullBleed, int orientation) { 27 | Intent intent = new Intent(context, GridActivity.class); 28 | intent.putExtra(ORIENTATION, orientation); 29 | intent.putExtra(FULL_BLEED, isFullBleed); 30 | return intent; 31 | } 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | setContentView(R.layout.activity_grid); 37 | initList(); 38 | } 39 | 40 | private void initList() { 41 | int orientation = (getIntent() != null) ? getIntent().getIntExtra(ORIENTATION, LinearLayout.VERTICAL) : LinearLayout.VERTICAL; 42 | boolean isFullBleed = (getIntent() != null) && getIntent().getBooleanExtra(FULL_BLEED, false); 43 | RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); 44 | int spanCount = 2; 45 | if (orientation == LinearLayout.HORIZONTAL) { 46 | spanCount = 3; 47 | } 48 | if (isFullBleed) { 49 | recyclerView.setBackgroundColor(Color.BLACK); 50 | } 51 | RecyclerView.LayoutManager layoutManager = new GridLayoutManager(this, spanCount, orientation, false); 52 | recyclerView.setLayoutManager(layoutManager); 53 | MultiLineDivider multiLineDivider = new MultiLineDivider(this, orientation); 54 | recyclerView.addItemDecoration(multiLineDivider); 55 | RecyclerAdapter recyclerAdapter = new RecyclerAdapter(this, createData(), isFullBleed, orientation); 56 | recyclerView.setAdapter(recyclerAdapter); 57 | } 58 | 59 | private ArrayList createData() { 60 | String pie = "1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"; 61 | String[] pieList = pie.split(""); 62 | ArrayList arrayList = new ArrayList<>(); 63 | for (String s: pieList) { 64 | if ("".equals(s)) { 65 | continue; 66 | } 67 | arrayList.add(Integer.parseInt(s)); 68 | } 69 | return arrayList; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/ListActivity.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.os.Bundle; 7 | import android.support.v7.widget.DividerItemDecoration; 8 | import android.support.v7.widget.LinearLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.widget.LinearLayout; 11 | 12 | import com.sakebook.android.library.multilinedevider.MultiLineDivider; 13 | import com.sakebook.android.library.multilinedividersample.multiline.RecyclerAdapter; 14 | 15 | import java.util.ArrayList; 16 | 17 | public class ListActivity extends AppCompatActivity { 18 | 19 | private final static String ORIENTATION = "orientation"; 20 | 21 | public static Intent createIntent(Context context, int orientation) { 22 | Intent intent = new Intent(context, ListActivity.class); 23 | intent.putExtra(ORIENTATION, orientation); 24 | return intent; 25 | } 26 | 27 | @Override 28 | protected void onCreate(Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_list); 31 | initList(); 32 | } 33 | 34 | private void initList() { 35 | int orientation = (getIntent() != null) ? getIntent().getIntExtra(ORIENTATION, LinearLayout.VERTICAL) : LinearLayout.VERTICAL; 36 | RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); 37 | 38 | RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this, orientation, false); 39 | recyclerView.setLayoutManager(layoutManager); 40 | MultiLineDivider multiLineDivider = new MultiLineDivider(this, orientation); 41 | recyclerView.addItemDecoration(multiLineDivider); 42 | RecyclerAdapter recyclerAdapter = new RecyclerAdapter(this, createData(), orientation); 43 | recyclerView.setAdapter(recyclerAdapter); 44 | } 45 | 46 | private ArrayList createData() { 47 | ArrayList arrayList = new ArrayList<>(); 48 | for (int i = 0; i < 100; i++) { 49 | arrayList.add("title: " + i); 50 | } 51 | return arrayList; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample; 2 | 3 | import android.content.Intent; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.widget.Button; 8 | import android.widget.LinearLayout; 9 | 10 | import com.sakebook.android.library.multilinedividersample.multiline.LayoutType; 11 | 12 | public class MainActivity extends AppCompatActivity { 13 | 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | setContentView(R.layout.activity_main); 18 | initLayout(); 19 | } 20 | 21 | private void initLayout() { 22 | Button verticalLinearButton = (Button) findViewById(R.id.button_linear_vertical); 23 | verticalLinearButton.setOnClickListener(new View.OnClickListener() { 24 | @Override 25 | public void onClick(View v) { 26 | Intent intent = ListActivity.createIntent(MainActivity.this, LinearLayout.VERTICAL); 27 | startActivity(intent); 28 | } 29 | }); 30 | Button horizontalLinearButton = (Button) findViewById(R.id.button_linear_horizontal); 31 | horizontalLinearButton.setOnClickListener(new View.OnClickListener() { 32 | @Override 33 | public void onClick(View v) { 34 | Intent intent = ListActivity.createIntent(MainActivity.this, LinearLayout.HORIZONTAL); 35 | startActivity(intent); 36 | } 37 | }); 38 | Button verticalGridButton = (Button) findViewById(R.id.button_grid_vertical); 39 | verticalGridButton.setOnClickListener(new View.OnClickListener() { 40 | @Override 41 | public void onClick(View v) { 42 | Intent intent = GridActivity.createIntent(MainActivity.this, true, LinearLayout.VERTICAL); 43 | startActivity(intent); 44 | } 45 | }); 46 | Button horizontalGridButton = (Button) findViewById(R.id.button_grid_horizontal); 47 | horizontalGridButton.setOnClickListener(new View.OnClickListener() { 48 | @Override 49 | public void onClick(View v) { 50 | Intent intent = GridActivity.createIntent(MainActivity.this, false, LinearLayout.HORIZONTAL); 51 | startActivity(intent); 52 | } 53 | }); 54 | Button verticalPositionButton = (Button) findViewById(R.id.button_position_vertical); 55 | verticalPositionButton.setOnClickListener(new View.OnClickListener() { 56 | @Override 57 | public void onClick(View v) { 58 | Intent intent = PositionActivity.createIntent(MainActivity.this, false, LinearLayout.VERTICAL); 59 | startActivity(intent); 60 | } 61 | }); 62 | Button horizontalPositionButton = (Button) findViewById(R.id.button_position_horizontal); 63 | horizontalPositionButton.setOnClickListener(new View.OnClickListener() { 64 | @Override 65 | public void onClick(View v) { 66 | Intent intent = PositionActivity.createIntent(MainActivity.this, true, LinearLayout.HORIZONTAL); 67 | startActivity(intent); 68 | } 69 | }); 70 | Button contactButton = (Button) findViewById(R.id.button_contact); 71 | contactButton.setOnClickListener(new View.OnClickListener() { 72 | @Override 73 | public void onClick(View v) { 74 | Intent intent = ContactActivity.createIntent(MainActivity.this); 75 | startActivity(intent); 76 | } 77 | }); 78 | Button ticketButton = (Button) findViewById(R.id.button_ticket); 79 | ticketButton.setOnClickListener(new View.OnClickListener() { 80 | @Override 81 | public void onClick(View v) { 82 | Intent intent = TicketActivity.createIntent(MainActivity.this); 83 | startActivity(intent); 84 | } 85 | }); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/PositionActivity.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.os.Bundle; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.widget.LinearLayout; 10 | 11 | import com.sakebook.android.library.multilinedevider.MultiLineDivider; 12 | import com.sakebook.android.library.multilinedividersample.position.RecyclerAdapter; 13 | 14 | import java.util.ArrayList; 15 | 16 | public class PositionActivity extends AppCompatActivity { 17 | 18 | private final static String ORIENTATION = "orientation"; 19 | private final static String INVERTED = "inverted"; 20 | 21 | public static Intent createIntent(Context context, boolean inverted, int orientation) { 22 | Intent intent = new Intent(context, PositionActivity.class); 23 | intent.putExtra(ORIENTATION, orientation); 24 | intent.putExtra(INVERTED, inverted); 25 | return intent; 26 | } 27 | 28 | @Override 29 | protected void onCreate(Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.activity_position); 32 | initList(); 33 | } 34 | 35 | private void initList() { 36 | int orientation = (getIntent() != null) ? getIntent().getIntExtra(ORIENTATION, LinearLayout.VERTICAL) : LinearLayout.VERTICAL; 37 | boolean inverted = (getIntent() != null) && getIntent().getBooleanExtra(INVERTED, false); 38 | RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); 39 | 40 | RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this, orientation, false); 41 | recyclerView.setLayoutManager(layoutManager); 42 | MultiLineDivider multiLineDivider = new MultiLineDivider(this, orientation); 43 | recyclerView.addItemDecoration(multiLineDivider); 44 | RecyclerAdapter recyclerAdapter = new RecyclerAdapter(this, createData(), inverted, orientation); 45 | recyclerView.setAdapter(recyclerAdapter); 46 | } 47 | 48 | private ArrayList createData() { 49 | ArrayList arrayList = new ArrayList<>(); 50 | for (int i = 0; i < 50; i++) { 51 | arrayList.add(i); 52 | } 53 | return arrayList; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/TicketActivity.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.os.Bundle; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.widget.LinearLayout; 10 | 11 | import com.sakebook.android.library.multilinedevider.MultiLineDivider; 12 | import com.sakebook.android.library.multilinedividersample.dash.RecyclerAdapter; 13 | import com.sakebook.android.library.multilinedividersample.dash.Ticket; 14 | import com.sakebook.android.library.multilinedividersample.inset.Contact; 15 | 16 | import java.util.ArrayList; 17 | 18 | public class TicketActivity extends AppCompatActivity { 19 | 20 | public static Intent createIntent(Context context) { 21 | Intent intent = new Intent(context, TicketActivity.class); 22 | return intent; 23 | } 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.activity_ticket); 29 | initList(); 30 | } 31 | 32 | private void initList() { 33 | RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); 34 | RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this, LinearLayout.VERTICAL, false); 35 | recyclerView.setLayoutManager(layoutManager); 36 | MultiLineDivider multiLineDivider = new MultiLineDivider(this, LinearLayout.VERTICAL); 37 | recyclerView.addItemDecoration(multiLineDivider); 38 | RecyclerAdapter recyclerAdapter = new RecyclerAdapter(this, createTicket()); 39 | recyclerView.setAdapter(recyclerAdapter); 40 | } 41 | 42 | private ArrayList createTicket() { 43 | ArrayList arrayList = new ArrayList<>(); 44 | String[] titles = getResources().getStringArray(R.array.ticket_titles); 45 | String[] descriptions = getResources().getStringArray(R.array.ticket_descriptions); 46 | int length = titles.length; 47 | for (int i = 0; i < length; i++) { 48 | arrayList.add(new Ticket(titles[i], descriptions[i], 0)); 49 | } 50 | return arrayList; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/dash/RecyclerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.dash; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | import android.support.v4.util.Pair; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.TextView; 11 | 12 | import com.sakebook.android.library.multilinedevider.divider.VerticalDivider; 13 | import com.sakebook.android.library.multilinedividersample.R; 14 | 15 | import org.jetbrains.annotations.Nullable; 16 | 17 | import java.util.ArrayList; 18 | 19 | /** 20 | * Created by sakemotoshinya on 2017/05/02. 21 | */ 22 | 23 | public class RecyclerAdapter extends RecyclerView.Adapter { 24 | 25 | private LayoutInflater inflater; 26 | private ArrayList items; 27 | 28 | public RecyclerAdapter(Context context, ArrayList items) { 29 | this.inflater = LayoutInflater.from(context); 30 | this.items = items; 31 | } 32 | 33 | @Override 34 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 35 | return new TicketViewHolder(inflater.inflate(R.layout.item_ticket, parent, false)); 36 | } 37 | 38 | @Override 39 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 40 | ((TicketViewHolder)holder).setData(items.get(position)); 41 | } 42 | 43 | @Override 44 | public int getItemCount() { 45 | return items.size(); 46 | } 47 | 48 | 49 | class TicketViewHolder extends RecyclerView.ViewHolder implements VerticalDivider{ 50 | 51 | private TextView textTitle; 52 | private TextView textDescription; 53 | private Resources resources; 54 | 55 | public TicketViewHolder(View itemView) { 56 | super(itemView); 57 | textTitle = (TextView) itemView.findViewById(R.id.text_title); 58 | textDescription = (TextView) itemView.findViewById(R.id.text_description); 59 | resources = itemView.getContext().getResources(); 60 | } 61 | 62 | void setData(Ticket ticket) { 63 | textTitle.setText(ticket.getTitle()); 64 | textDescription.setText(ticket.getDescription()); 65 | } 66 | 67 | @Override 68 | public int getHeight() { 69 | return (int) resources.getDimension(R.dimen.dash_height); 70 | } 71 | 72 | @Override 73 | public int getDrawableRes() { 74 | return R.drawable.dashed_line_divider; 75 | } 76 | 77 | @Nullable 78 | @Override 79 | public Pair getVerticalInset() { 80 | int inset = (int) resources.getDimension(R.dimen.list_item); 81 | return Pair.create(inset, inset); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/dash/Ticket.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.dash; 2 | 3 | /** 4 | * Created by sakemotoshinya on 2017/05/02. 5 | */ 6 | 7 | public class Ticket { 8 | private String title; 9 | private String description; 10 | private int price; 11 | 12 | public Ticket(String title, String description, int price) { 13 | this.title = title; 14 | this.description = description; 15 | this.price = price; 16 | } 17 | 18 | public String getTitle() { 19 | return title; 20 | } 21 | 22 | public String getDescription() { 23 | return description; 24 | } 25 | 26 | public int getPrice() { 27 | return price; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/grid/GridFullBleedImageViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.grid; 2 | 3 | import android.view.View; 4 | import android.widget.ImageView; 5 | 6 | import com.sakebook.android.library.multilinedevider.divider.GridDivider; 7 | import com.sakebook.android.library.multilinedividersample.R; 8 | import com.sakebook.android.library.multilinedividersample.multiline.Number; 9 | 10 | /** 11 | * Created by sakemotoshinya on 2017/05/21. 12 | */ 13 | 14 | public class GridFullBleedImageViewHolder extends ViewHolder implements GridDivider { 15 | 16 | private ImageView imageView; 17 | public GridFullBleedImageViewHolder(View itemView) { 18 | super(itemView); 19 | imageView = (ImageView) itemView.findViewById(R.id.image); 20 | } 21 | 22 | @Override 23 | void setData(Number number) { 24 | switch (number) { 25 | case EVEN: 26 | imageView.setImageResource(R.drawable.cat2); 27 | break; 28 | case ODD: 29 | imageView.setImageResource(R.drawable.cat3); 30 | break; 31 | case PRIME: 32 | imageView.setImageResource(R.drawable.cat1); 33 | break; 34 | } 35 | } 36 | 37 | @Override 38 | public int getPadding() { 39 | return itemView.getContext().getResources().getDimensionPixelSize(R.dimen.grid_padding); 40 | } 41 | 42 | @Override 43 | public boolean getFullBleed() { 44 | return true; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/grid/GridImageViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.grid; 2 | 3 | import android.view.View; 4 | import android.widget.ImageView; 5 | 6 | import com.sakebook.android.library.multilinedevider.divider.GridDivider; 7 | import com.sakebook.android.library.multilinedividersample.R; 8 | import com.sakebook.android.library.multilinedividersample.multiline.Number; 9 | 10 | /** 11 | * Created by sakemotoshinya on 2017/05/21. 12 | */ 13 | 14 | public class GridImageViewHolder extends ViewHolder implements GridDivider { 15 | 16 | private ImageView imageView; 17 | public GridImageViewHolder(View itemView) { 18 | super(itemView); 19 | imageView = (ImageView) itemView.findViewById(R.id.image); 20 | } 21 | 22 | @Override 23 | void setData(Number number) { 24 | switch (number) { 25 | case EVEN: 26 | imageView.setImageResource(R.drawable.cat2); 27 | break; 28 | case ODD: 29 | imageView.setImageResource(R.drawable.cat3); 30 | break; 31 | case PRIME: 32 | imageView.setImageResource(R.drawable.cat1); 33 | break; 34 | } 35 | } 36 | 37 | @Override 38 | public int getPadding() { 39 | return itemView.getContext().getResources().getDimensionPixelSize(R.dimen.tiny_margin); 40 | } 41 | 42 | @Override 43 | public boolean getFullBleed() { 44 | return false; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/grid/RecyclerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.grid; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.ViewGroup; 7 | import android.widget.LinearLayout; 8 | 9 | import com.sakebook.android.library.multilinedividersample.R; 10 | import com.sakebook.android.library.multilinedividersample.multiline.Number; 11 | 12 | import java.util.ArrayList; 13 | 14 | /** 15 | * Created by sakemotoshinya on 2017/05/15. 16 | */ 17 | 18 | public class RecyclerAdapter extends RecyclerView.Adapter { 19 | 20 | private LayoutInflater inflater; 21 | private ArrayList items; 22 | private boolean isFullBleed; 23 | private int orientation; 24 | 25 | public RecyclerAdapter(Context context, ArrayList arrayList, boolean isFullBleed, int orientation) { 26 | this.inflater = LayoutInflater.from(context); 27 | this.items = arrayList; 28 | this.isFullBleed = isFullBleed; 29 | this.orientation = orientation; 30 | } 31 | 32 | @Override 33 | public int getItemViewType(int position) { 34 | Number number = Number.id(items.get(position)); 35 | switch (number) { 36 | case EVEN: 37 | break; 38 | case ODD: 39 | break; 40 | case PRIME: 41 | break; 42 | } 43 | return number.type(); 44 | } 45 | 46 | @Override 47 | public int getItemCount() { 48 | return items.size(); 49 | } 50 | 51 | @Override 52 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 53 | ViewHolder holder; 54 | int layoutId = (orientation == LinearLayout.VERTICAL) ? R.layout.item_grid_vertical: R.layout.item_grid_horizontal; 55 | if (isFullBleed) { 56 | holder = new GridFullBleedImageViewHolder(inflater.inflate(layoutId, parent, false)); 57 | } else { 58 | holder = new GridImageViewHolder(inflater.inflate(layoutId, parent, false)); 59 | } 60 | return holder; 61 | } 62 | 63 | @Override 64 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 65 | Number number = Number.id(items.get(position)); 66 | ((ViewHolder)holder).setData(number); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/grid/ViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.grid; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.View; 5 | 6 | /** 7 | * Created by sakemotoshinya on 2017/05/16. 8 | */ 9 | 10 | public abstract class ViewHolder extends RecyclerView.ViewHolder { 11 | public ViewHolder(View itemView) { 12 | super(itemView); 13 | } 14 | 15 | abstract void setData(T t); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/inset/Contact.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.inset; 2 | 3 | /** 4 | * Created by sakemotoshinya on 2017/04/30. 5 | */ 6 | 7 | public class Contact { 8 | private String name; 9 | private boolean favorite; 10 | 11 | public Contact(String name, boolean favorite) { 12 | this.name = name; 13 | this.favorite = favorite; 14 | } 15 | 16 | public String getName() { 17 | return name; 18 | } 19 | 20 | public boolean isFavorite() { 21 | return favorite; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/inset/FirstViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.inset; 2 | 3 | import android.view.View; 4 | import android.widget.ImageView; 5 | import android.widget.TextView; 6 | 7 | import com.sakebook.android.library.multilinedevider.divider.NoDivider; 8 | import com.sakebook.android.library.multilinedividersample.R; 9 | 10 | /** 11 | * Created by sakemotoshinya on 2017/04/30. 12 | */ 13 | 14 | public class FirstViewHolder extends ViewHolder implements NoDivider{ 15 | 16 | private ImageView imageView; 17 | private TextView textView; 18 | 19 | public FirstViewHolder(View itemView) { 20 | super(itemView); 21 | imageView = (ImageView) itemView.findViewById(R.id.image); 22 | textView = (TextView) itemView.findViewById(R.id.text); 23 | } 24 | 25 | @Override 26 | void setData(Contact contact) { 27 | if (contact.isFavorite()) { 28 | imageView.setImageResource(R.drawable.ic_star_24dp); 29 | } else { 30 | imageView.setImageResource(R.drawable.ic_account_circle_24dp); 31 | } 32 | textView.setText(contact.getName()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/inset/OtherViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.inset; 2 | 3 | import android.content.res.Resources; 4 | import android.support.v4.util.Pair; 5 | import android.view.View; 6 | import android.widget.ImageView; 7 | import android.widget.TextView; 8 | 9 | import com.sakebook.android.library.multilinedevider.divider.PositionDivider; 10 | import com.sakebook.android.library.multilinedevider.divider.VerticalDivider; 11 | import com.sakebook.android.library.multilinedividersample.R; 12 | 13 | import org.jetbrains.annotations.NotNull; 14 | import org.jetbrains.annotations.Nullable; 15 | 16 | import java.util.Arrays; 17 | import java.util.List; 18 | 19 | /** 20 | * Created by sakemotoshinya on 2017/04/30. 21 | */ 22 | 23 | public class OtherViewHolder extends ViewHolder implements VerticalDivider, PositionDivider{ 24 | 25 | private ImageView imageView; 26 | private TextView textView; 27 | private Resources resources; 28 | 29 | public OtherViewHolder(View itemView) { 30 | super(itemView); 31 | imageView = (ImageView) itemView.findViewById(R.id.image); 32 | textView = (TextView) itemView.findViewById(R.id.text); 33 | resources = itemView.getContext().getResources(); 34 | } 35 | 36 | @Override 37 | void setData(Contact contact) { 38 | textView.setText(contact.getName()); 39 | } 40 | 41 | @Override 42 | public int getHeight() { 43 | return (int) resources.getDimension(R.dimen.tiny_margin); 44 | } 45 | 46 | @Override 47 | public int getDrawableRes() { 48 | return R.drawable.simple_divider; 49 | } 50 | 51 | @Nullable 52 | @Override 53 | public Pair getVerticalInset() { 54 | int inset = (int) resources.getDimension(R.dimen.list_padding); 55 | return Pair.create(inset, 0); 56 | } 57 | 58 | @NotNull 59 | @Override 60 | public List getPositions() { 61 | return Arrays.asList(3, 8); 62 | } 63 | 64 | @Override 65 | public boolean getInverted() { 66 | return false; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/inset/RecyclerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.inset; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.ViewGroup; 7 | 8 | 9 | import com.sakebook.android.library.multilinedividersample.R; 10 | 11 | import java.util.ArrayList; 12 | 13 | import static com.sakebook.android.library.multilinedividersample.inset.RecyclerAdapter.ITEM_TYPE.First; 14 | import static com.sakebook.android.library.multilinedividersample.inset.RecyclerAdapter.ITEM_TYPE.Other; 15 | 16 | /** 17 | * Created by sakemotoshinya on 2017/04/30. 18 | */ 19 | 20 | public class RecyclerAdapter extends RecyclerView.Adapter { 21 | 22 | private LayoutInflater inflater; 23 | private ArrayList favoriteItems; 24 | private ArrayList items; 25 | 26 | enum ITEM_TYPE { 27 | First(0), 28 | Other(2), 29 | ; 30 | 31 | ITEM_TYPE(int i) {} 32 | } 33 | 34 | public RecyclerAdapter(Context context, ArrayList favoriteItems, ArrayList items) { 35 | this.inflater = LayoutInflater.from(context); 36 | this.favoriteItems = favoriteItems; 37 | this.items = items; 38 | } 39 | 40 | @Override 41 | public int getItemViewType(int position) { 42 | Contact contact = getContact(position); 43 | return getType(contact).ordinal(); 44 | } 45 | 46 | @Override 47 | public int getItemCount() { 48 | return favoriteItems.size() + items.size(); 49 | } 50 | 51 | @Override 52 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 53 | ViewHolder holder = null; 54 | switch (viewType) { 55 | case 0: 56 | holder = new FirstViewHolder(inflater.inflate(R.layout.item_contact, parent, false)); 57 | break; 58 | default: 59 | holder = new OtherViewHolder(inflater.inflate(R.layout.item_contact, parent, false)); 60 | break; 61 | } 62 | return holder; 63 | } 64 | 65 | @Override 66 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 67 | ViewHolder viewHolder = (ViewHolder) holder; 68 | viewHolder.setData(getContact(position)); 69 | } 70 | 71 | private Contact getContact(int position) { 72 | Contact contact; 73 | if (favoriteItems.size() > position) { 74 | contact = favoriteItems.get(position); 75 | } else { 76 | contact = items.get(position - favoriteItems.size()); 77 | } 78 | return contact; 79 | } 80 | 81 | private ITEM_TYPE getType(Contact contact) { 82 | ArrayList targetList; 83 | if (contact.isFavorite()) { 84 | targetList = favoriteItems; 85 | } else { 86 | targetList = items; 87 | } 88 | 89 | int index = targetList.indexOf(contact); 90 | if (index == 0) { 91 | // first 92 | return First; 93 | } else { 94 | return Other; 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/inset/ViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.inset; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.View; 5 | 6 | /** 7 | * Created by sakemotoshinya on 2017/04/30. 8 | */ 9 | 10 | public abstract class ViewHolder extends RecyclerView.ViewHolder { 11 | public ViewHolder(View itemView) { 12 | super(itemView); 13 | } 14 | 15 | abstract void setData(T t); 16 | } 17 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/multiline/EvenViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.multiline; 2 | 3 | import android.view.View; 4 | import android.widget.TextView; 5 | 6 | import com.sakebook.android.library.multilinedevider.divider.NoDivider; 7 | import com.sakebook.android.library.multilinedividersample.R; 8 | 9 | /** 10 | * Created by sakemotoshinya on 2017/04/26. 11 | */ 12 | 13 | public class EvenViewHolder extends ViewHolder implements NoDivider { 14 | 15 | private TextView textView; 16 | public EvenViewHolder(View itemView) { 17 | super(itemView); 18 | textView = (TextView) itemView.findViewById(R.id.text); 19 | } 20 | 21 | @Override 22 | void setData(String str) { 23 | textView.setText("Even: " + str); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/multiline/LayoutType.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.multiline; 2 | 3 | /** 4 | * Created by sakemotoshinya on 2017/05/12. 5 | */ 6 | 7 | public enum LayoutType { 8 | LINEAR, 9 | GRID, 10 | STAGGERED, 11 | ; 12 | } 13 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/multiline/Number.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.multiline; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | /** 7 | * Created by sakemotoshinya on 2017/04/26. 8 | */ 9 | 10 | public enum Number { 11 | EVEN(10), 12 | ODD(1), 13 | PRIME(3), 14 | ; 15 | 16 | private static List primeNumbers = Arrays.asList(2, 3, 5, 7, 11, 17 | 13, 17, 19, 23, 29, 18 | 31, 37, 41, 43, 47, 19 | 53, 59, 61, 67, 71, 20 | 73, 79, 83, 89, 97); 21 | 22 | private int id; 23 | Number(int i) { 24 | this.id = i; 25 | } 26 | 27 | public static Number id(int i) { 28 | if (primeNumbers.contains(i)) { 29 | return PRIME; 30 | } else if (i % 2 == 0) { 31 | return EVEN; 32 | } else { 33 | return ODD; 34 | } 35 | } 36 | 37 | public int type() { 38 | return this.id; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/multiline/OddViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.multiline; 2 | 3 | import android.support.v4.util.Pair; 4 | import android.view.View; 5 | import android.widget.TextView; 6 | 7 | import com.sakebook.android.library.multilinedevider.divider.HorizontalDivider; 8 | import com.sakebook.android.library.multilinedevider.divider.VerticalDivider; 9 | import com.sakebook.android.library.multilinedividersample.R; 10 | 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | /** 14 | * Created by sakemotoshinya on 2017/04/25. 15 | */ 16 | 17 | public class OddViewHolder extends ViewHolder implements VerticalDivider, HorizontalDivider{ 18 | 19 | private TextView textView; 20 | public OddViewHolder(View itemView) { 21 | super(itemView); 22 | textView = (TextView) itemView.findViewById(R.id.text); 23 | } 24 | 25 | @Override 26 | void setData(String str) { 27 | textView.setText("Odd: " + str); 28 | } 29 | 30 | @Override 31 | public int getHeight() { 32 | return this.itemView.getContext().getResources().getDimensionPixelSize(R.dimen.small_margin); 33 | } 34 | 35 | @Override 36 | public int getDrawableRes() { 37 | return R.drawable.custom_divider; 38 | } 39 | 40 | @Override 41 | public int getWidth() { 42 | return this.itemView.getContext().getResources().getDimensionPixelSize(R.dimen.small_margin); 43 | } 44 | 45 | @Nullable 46 | @Override 47 | public Pair getHorizontalInset() { 48 | return null; 49 | } 50 | 51 | @Nullable 52 | @Override 53 | public Pair getVerticalInset() { 54 | return null; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/multiline/PrimeViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.multiline; 2 | 3 | import android.view.View; 4 | import android.widget.TextView; 5 | 6 | import com.sakebook.android.library.multilinedividersample.R; 7 | 8 | /** 9 | * Created by sakemotoshinya on 2017/04/26. 10 | */ 11 | 12 | public class PrimeViewHolder extends ViewHolder { 13 | 14 | private TextView textView; 15 | public PrimeViewHolder(View itemView) { 16 | super(itemView); 17 | textView = (TextView) itemView.findViewById(R.id.text); 18 | } 19 | 20 | @Override 21 | void setData(String str) { 22 | textView.setText("Prime: " + str); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/multiline/RecyclerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.multiline; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.ViewGroup; 7 | import android.widget.LinearLayout; 8 | 9 | import com.sakebook.android.library.multilinedividersample.R; 10 | 11 | import java.util.ArrayList; 12 | 13 | /** 14 | * Created by sakemotoshinya on 2017/04/25. 15 | */ 16 | 17 | public class RecyclerAdapter extends RecyclerView.Adapter { 18 | 19 | private LayoutInflater inflater; 20 | private ArrayList items; 21 | private int orientation; 22 | 23 | public RecyclerAdapter(Context context, ArrayList arrayList, int orientation) { 24 | this.inflater = LayoutInflater.from(context); 25 | this.items = arrayList; 26 | this.orientation = orientation; 27 | } 28 | 29 | @Override 30 | public int getItemViewType(int position) { 31 | Number number = Number.id(position); 32 | switch (number) { 33 | case EVEN: 34 | break; 35 | case ODD: 36 | break; 37 | case PRIME: 38 | break; 39 | } 40 | return number.type(); 41 | } 42 | 43 | @Override 44 | public int getItemCount() { 45 | return items.size(); 46 | } 47 | 48 | @Override 49 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 50 | ViewHolder holder = null; 51 | int layoutId; 52 | Number number = Number.id(viewType); 53 | switch (number) { 54 | case EVEN: 55 | layoutId = (orientation == LinearLayout.VERTICAL) ? R.layout.item_even_vertical: R.layout.item_even_horizontal; 56 | holder = new EvenViewHolder(inflater.inflate(layoutId, parent, false)); 57 | break; 58 | case ODD: 59 | layoutId = (orientation == LinearLayout.VERTICAL) ? R.layout.item_odd_vertical: R.layout.item_odd_horizontal; 60 | holder = new OddViewHolder(inflater.inflate(layoutId, parent, false)); 61 | break; 62 | case PRIME: 63 | layoutId = (orientation == LinearLayout.VERTICAL) ? R.layout.item_prime_vertical: R.layout.item_prime_horizontal; 64 | holder = new PrimeViewHolder(inflater.inflate(layoutId, parent, false)); 65 | break; 66 | } 67 | return holder; 68 | } 69 | 70 | @Override 71 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 72 | ViewHolder viewHolder = (ViewHolder) holder; 73 | viewHolder.setData(items.get(position)); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/multiline/ViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.multiline; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.View; 5 | 6 | /** 7 | * Created by sakemotoshinya on 2017/04/25. 8 | */ 9 | 10 | public abstract class ViewHolder extends RecyclerView.ViewHolder { 11 | public ViewHolder(View itemView) { 12 | super(itemView); 13 | } 14 | 15 | abstract void setData(T t); 16 | } 17 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/position/PositionInvertedViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.position; 2 | 3 | import android.view.View; 4 | import android.widget.TextView; 5 | 6 | import com.sakebook.android.library.multilinedevider.divider.PositionDivider; 7 | import com.sakebook.android.library.multilinedividersample.R; 8 | 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.Arrays; 12 | import java.util.List; 13 | 14 | /** 15 | * Created by sakemotoshinya on 2017/05/21. 16 | */ 17 | 18 | public class PositionInvertedViewHolder extends ViewHolder implements PositionDivider { 19 | 20 | private TextView textView; 21 | public PositionInvertedViewHolder(View itemView) { 22 | super(itemView); 23 | textView = (TextView) itemView.findViewById(R.id.text); 24 | } 25 | 26 | @Override 27 | void setData(Integer integer) { 28 | textView.setText("Position: " + integer); 29 | } 30 | 31 | @NotNull 32 | @Override 33 | public List getPositions() { 34 | return Arrays.asList(2, 12, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 42); // include "2" 35 | } 36 | 37 | @Override 38 | public boolean getInverted() { 39 | return true; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/position/PositionViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.position; 2 | 3 | import android.view.View; 4 | import android.widget.TextView; 5 | 6 | import com.sakebook.android.library.multilinedevider.divider.PositionDivider; 7 | import com.sakebook.android.library.multilinedividersample.R; 8 | 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.Arrays; 12 | import java.util.List; 13 | 14 | /** 15 | * Created by sakemotoshinya on 2017/05/21. 16 | */ 17 | 18 | public class PositionViewHolder extends ViewHolder implements PositionDivider { 19 | 20 | private TextView textView; 21 | public PositionViewHolder(View itemView) { 22 | super(itemView); 23 | textView = (TextView) itemView.findViewById(R.id.text); 24 | } 25 | 26 | @Override 27 | void setData(Integer integer) { 28 | textView.setText("Position: " + integer); 29 | } 30 | 31 | @NotNull 32 | @Override 33 | public List getPositions() { 34 | return Arrays.asList(2, 12, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 42); // include "2" 35 | } 36 | 37 | @Override 38 | public boolean getInverted() { 39 | return false; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/position/RecyclerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.position; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.ViewGroup; 7 | import android.widget.LinearLayout; 8 | 9 | import com.sakebook.android.library.multilinedividersample.R; 10 | 11 | import java.util.ArrayList; 12 | 13 | /** 14 | * Created by sakemotoshinya on 2017/05/21. 15 | */ 16 | 17 | public class RecyclerAdapter extends RecyclerView.Adapter { 18 | 19 | private LayoutInflater inflater; 20 | private ArrayList items; 21 | private boolean inverted; 22 | private int orientation; 23 | 24 | public RecyclerAdapter(Context context, ArrayList arrayList, boolean inverted, int orientation) { 25 | this.inflater = LayoutInflater.from(context); 26 | this.items = arrayList; 27 | this.inverted = inverted; 28 | this.orientation = orientation; 29 | } 30 | 31 | @Override 32 | public int getItemCount() { 33 | return items.size(); 34 | } 35 | 36 | @Override 37 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 38 | ViewHolder holder; 39 | int layoutId = (orientation == LinearLayout.VERTICAL) ? R.layout.item_vertical: R.layout.item_horizontal; 40 | if (inverted) { 41 | holder = new PositionInvertedViewHolder(inflater.inflate(layoutId, parent, false)); 42 | } else { 43 | holder = new PositionViewHolder(inflater.inflate(layoutId, parent, false)); 44 | } 45 | return holder; 46 | } 47 | 48 | @Override 49 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 50 | ((ViewHolder)holder).setData(position); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /sample/src/main/java/com/sakebook/android/library/multilinedividersample/position/ViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.sakebook.android.library.multilinedividersample.position; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.View; 5 | 6 | /** 7 | * Created by sakemotoshinya on 2017/05/21. 8 | */ 9 | 10 | public abstract class ViewHolder extends RecyclerView.ViewHolder{ 11 | public ViewHolder(View itemView) { 12 | super(itemView); 13 | } 14 | abstract void setData(T t); 15 | } 16 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable-hdpi/ic_account_circle_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/sample/src/main/res/drawable-hdpi/ic_account_circle_24dp.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-hdpi/ic_star_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/sample/src/main/res/drawable-hdpi/ic_star_24dp.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-mdpi/ic_account_circle_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/sample/src/main/res/drawable-mdpi/ic_account_circle_24dp.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-mdpi/ic_star_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/sample/src/main/res/drawable-mdpi/ic_star_24dp.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xhdpi/ic_account_circle_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/sample/src/main/res/drawable-xhdpi/ic_account_circle_24dp.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xhdpi/ic_star_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/sample/src/main/res/drawable-xhdpi/ic_star_24dp.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/ic_account_circle_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/sample/src/main/res/drawable-xxhdpi/ic_account_circle_24dp.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/ic_star_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/sample/src/main/res/drawable-xxhdpi/ic_star_24dp.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxxhdpi/ic_account_circle_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/sample/src/main/res/drawable-xxxhdpi/ic_account_circle_24dp.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxxhdpi/ic_star_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/sample/src/main/res/drawable-xxxhdpi/ic_star_24dp.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable/cat1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/sample/src/main/res/drawable/cat1.jpg -------------------------------------------------------------------------------- /sample/src/main/res/drawable/cat2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/sample/src/main/res/drawable/cat2.jpg -------------------------------------------------------------------------------- /sample/src/main/res/drawable/cat3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakebook/MultiLineDivider/de2c9ba45620076c1a9d930d6d533699bf06d348/sample/src/main/res/drawable/cat3.jpg -------------------------------------------------------------------------------- /sample/src/main/res/drawable/custom_divider.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable/dashed_line_divider.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable/simple_divider.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_contact.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_grid.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 |