├── .gitignore ├── .idea ├── dictionaries │ └── justin.xml ├── gradle.xml ├── misc.xml ├── runConfigurations.xml └── vcs.xml ├── JscTestKeyStore.jks ├── LICENSE ├── README.md ├── adapterLibrary ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── jsc │ │ └── kit │ │ └── adapter │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── jsc │ │ │ └── kit │ │ │ └── adapter │ │ │ ├── BaseHeaderFooterAdapter.java │ │ │ ├── BaseItemAdapter.java │ │ │ ├── OnCreateViewHolderListener.java │ │ │ ├── OnItemChildClickListener.java │ │ │ ├── OnItemChildLongClickListener.java │ │ │ ├── OnItemClickListener.java │ │ │ ├── OnItemLongClickListener.java │ │ │ ├── SimpleAdapter.java │ │ │ ├── SimpleAdapter2.java │ │ │ ├── SimpleAdapter3.java │ │ │ ├── SimpleAdapter4.java │ │ │ ├── SimpleAnimationListener.java │ │ │ ├── SimpleAnimatorListener.java │ │ │ ├── SimpleCreateViewHolderListener.java │ │ │ ├── SimpleItemChildClickListener.java │ │ │ ├── SimpleItemChildClickListener2.java │ │ │ ├── SimpleItemChildClickListener3.java │ │ │ ├── SimpleItemChildClickListener4.java │ │ │ ├── SimpleItemChildLongClickListener.java │ │ │ ├── SimpleItemChildLongClickListener2.java │ │ │ ├── SimpleItemChildLongClickListener3.java │ │ │ ├── SimpleItemChildLongClickListener4.java │ │ │ ├── SimpleItemClickListener.java │ │ │ ├── SimpleItemClickListener2.java │ │ │ ├── SimpleItemClickListener3.java │ │ │ ├── SimpleItemClickListener4.java │ │ │ ├── SimpleItemLongClickListener.java │ │ │ ├── SimpleItemLongClickListener2.java │ │ │ ├── SimpleItemLongClickListener3.java │ │ │ ├── SimpleItemLongClickListener4.java │ │ │ ├── bean │ │ │ ├── ISelectable.java │ │ │ └── SelectableBean.java │ │ │ ├── decoration │ │ │ ├── LineItemDecoration.java │ │ │ └── SpaceItemDecoration.java │ │ │ └── refresh │ │ │ ├── ILoadMore.java │ │ │ ├── IRefresh.java │ │ │ ├── PullToRefreshRecyclerView.java │ │ │ └── SwipeRefreshRecyclerView.java │ └── res │ │ ├── drawable │ │ └── recycler_header_arrow.xml │ │ ├── layout │ │ ├── recycler_default_empty_list_layout.xml │ │ ├── recycler_default_footer_view.xml │ │ ├── recycler_default_header_view.xml │ │ ├── recycler_default_load_more_layout.xml │ │ ├── recycler_default_swipe_refresh_recycler_view_layout.xml │ │ └── recycler_pull_to_refresh_recycler_view.xml │ │ ├── values-zh │ │ └── recycler_strings.xml │ │ └── values │ │ ├── recycler_attrs.xml │ │ ├── recycler_ids.xml │ │ └── recycler_strings.xml │ └── test │ └── java │ └── jsc │ └── kit │ └── adapter │ └── ExampleUnitTest.java ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── jsc │ │ └── exam │ │ └── com │ │ └── adapter │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── jsc │ │ │ └── exam │ │ │ └── com │ │ │ └── adapter │ │ │ ├── BaseActivity.java │ │ │ ├── BaseAppCompatActivity.java │ │ │ ├── BaseEmptyFragmentActivity.java │ │ │ ├── EmptyFragmentActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── bean │ │ │ ├── ClassItem.java │ │ │ └── CustomBean.java │ │ │ ├── fragments │ │ │ ├── AboutFragment.java │ │ │ ├── BaseFragment.java │ │ │ ├── BaseItemAdapterFragment.java │ │ │ ├── CheckableFragment.java │ │ │ ├── OptionalFragment.java │ │ │ ├── PullToRefreshFragment.java │ │ │ ├── SimpleAdapterFragment.java │ │ │ └── SwipeRefreshFragment.java │ │ │ ├── retrofit │ │ │ ├── ApiService.java │ │ │ ├── CustomHttpClient.java │ │ │ ├── CustomRetrofit.java │ │ │ └── LoadingDialogObserver.java │ │ │ ├── utils │ │ │ ├── CompatResourceUtils.java │ │ │ ├── ConnectivityHelper.java │ │ │ └── WindowUtils.java │ │ │ └── widgets │ │ │ ├── FiveTwoImageView.java │ │ │ └── SquareImageView.java │ └── res │ │ ├── drawable-v21 │ │ └── ripple_round_corner_white_r4.xml │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable-xxhdpi │ │ ├── btn_background.png │ │ ├── ic_chevron_left_white_24dp.png │ │ ├── ico_checkable_nor.png │ │ ├── ico_checkable_press.png │ │ ├── kit_ic_assignment_blue_24dp.png │ │ ├── kit_ic_chevron_right_gray_24dp.png │ │ └── picture.jpg │ │ ├── drawable │ │ ├── button_selector.xml │ │ ├── head.jpg │ │ ├── ic_launcher_background.xml │ │ ├── ico_checkable_selector.xml │ │ ├── red_dot_shape.xml │ │ ├── ripple_round_corner_white_r4.xml │ │ └── simple_adapter_qr_code.png │ │ ├── layout │ │ ├── checkable_list_item_layout.xml │ │ ├── fragment_about.xml │ │ ├── fragment_pull_to_refresh.xml │ │ ├── fragment_recycler_view.xml │ │ ├── fragment_simple_adapter.xml │ │ ├── fragment_swipe_refresh.xml │ │ ├── list_footer_layout.xml │ │ ├── list_header_layout.xml │ │ └── main_list_item_layout.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.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-zh │ │ └── strings.xml │ │ └── values │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── jsc │ └── exam │ └── com │ └── adapter │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── output ├── SimpleAdapterDemo.apk ├── output.json └── shots │ ├── pull_to_refresh_recycler_view.png │ └── simple_adapter.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches/build_file_checksums.ser 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | .DS_Store 9 | /build 10 | /captures 11 | .externalNativeBuild 12 | -------------------------------------------------------------------------------- /.idea/dictionaries/justin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 36 | 37 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 97 | 112 | 113 | 114 | 115 | 116 | 117 | 119 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /JscTestKeyStore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinRoom/SimpleAdapterDemo/739e75fc2bcaccdd5d323e717a1021cf4d907b63/JscTestKeyStore.jks -------------------------------------------------------------------------------- /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 2018 JustinRoom 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. 202 | -------------------------------------------------------------------------------- /adapterLibrary/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /adapterLibrary/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.novoda.bintray-release' 3 | 4 | android { 5 | compileSdkVersion sdk_veriosn 6 | 7 | defaultConfig { 8 | minSdkVersion min_sdk_veriosn 9 | targetSdkVersion sdk_veriosn 10 | versionCode version_code 11 | versionName version_name 12 | 13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 14 | 15 | } 16 | 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | 24 | } 25 | 26 | publish { 27 | userOrg = "$user_org" 28 | repoName = 'maven' 29 | groupId = 'jsc.kit.adapter' 30 | artifactId = 'adapter-component' 31 | publishVersion = "$version_name" 32 | desc = 'Usefull and simple recycler view adapter library' 33 | website = 'https://github.com/JustinRoom/SimpleAdapterDemo' 34 | } 35 | 36 | dependencies { 37 | implementation fileTree(include: ['*.jar'], dir: 'libs') 38 | compileOnly 'com.android.support:appcompat-v7:28.0.0' 39 | testImplementation 'junit:junit:4.12' 40 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 41 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 42 | compileOnly 'com.android.support:recyclerview-v7:28.0.0' 43 | } 44 | -------------------------------------------------------------------------------- /adapterLibrary/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /adapterLibrary/src/androidTest/java/jsc/kit/adapter/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 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 | * Instrumented 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() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("jsc.kit.wheel.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/OnCreateViewHolderListener.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | /** 6 | *
Email:1006368252@qq.com 7 | *
QQ:1006368252 8 | * create time: 2019/3/2 17:44 Saturday 9 | * 10 | * @author jsc 11 | */ 12 | public interface OnCreateViewHolderListener { 13 | void onCreateHeaderViewHolder(@NonNull BaseHeaderFooterAdapter.BaseViewHolder holder); 14 | void onCreateDataViewHolder(@NonNull BaseHeaderFooterAdapter.BaseViewHolder holder); 15 | void onCreateFooterViewHolder(@NonNull BaseHeaderFooterAdapter.BaseViewHolder holder); 16 | void onCreateEmptyViewHolder(@NonNull BaseHeaderFooterAdapter.BaseViewHolder holder); 17 | } 18 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/OnItemChildClickListener.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.view.View; 5 | 6 | /** 7 | *
Email:1006368252@qq.com 8 | *
QQ:1006368252 9 | * create time: 2018/12/23 01:38 Sunday 10 | * 11 | * @author jsc 12 | */ 13 | public interface OnItemChildClickListener { 14 | void onHeaderItemChildClick(@NonNull View headerChild, int position, H headerBean); 15 | void onDataItemChildClick(@NonNull View dataItemChild, int position, D dataBean); 16 | void onFooterItemChildClick(@NonNull View footerChild, int position, F footerBean); 17 | void onEmptyItemChildClick(@NonNull View emptyChild, int position, E emptyBean); 18 | } 19 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/OnItemChildLongClickListener.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.view.View; 5 | 6 | /** 7 | *
Email:1006368252@qq.com 8 | *
QQ:1006368252 9 | * create time: 2018/12/23 01:38 Sunday 10 | * 11 | * @author jsc 12 | */ 13 | public interface OnItemChildLongClickListener { 14 | boolean onHeaderItemChildLongClick(@NonNull View headerChild, int position, H headerBean); 15 | boolean onDataItemChildLongClick(@NonNull View dataItemChild, int position, D dataBean); 16 | boolean onFooterItemChildLongClick(@NonNull View footerChild, int position, F footerBean); 17 | boolean onEmptyItemChildLongClick(@NonNull View emptyChild, int position, E emptyBean); 18 | } 19 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/OnItemClickListener.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.view.View; 5 | 6 | /** 7 | *
Email:1006368252@qq.com 8 | *
QQ:1006368252 9 | * create time: 2018/12/23 01:38 Sunday 10 | * 11 | * @author jsc 12 | */ 13 | public interface OnItemClickListener { 14 | void onHeaderItemClick(@NonNull View headerItemView, int position, H headerBean); 15 | void onDataItemClick(@NonNull View dataItemView, int position, D dataBean); 16 | void onFooterItemClick(@NonNull View footerItemView, int position, F footerBean); 17 | void onEmptyItemClick(@NonNull View emptyItemView, int position, E emptyBean); 18 | } 19 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/OnItemLongClickListener.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.view.View; 5 | 6 | /** 7 | *
Email:1006368252@qq.com 8 | *
QQ:1006368252 9 | * create time: 2018/12/23 01:38 Sunday 10 | * 11 | * @author jsc 12 | */ 13 | public interface OnItemLongClickListener { 14 | boolean onHeaderItemLongClick(@NonNull View headerItemView, int position, H headerBean); 15 | boolean onDataItemLongClick(@NonNull View dataItemView, int position, D dataBean); 16 | boolean onFooterItemLongClick(@NonNull View footerItemView, int position, F footerBean); 17 | boolean onEmptyItemLongClick(@NonNull View emptyItemView, int position, E emptyBean); 18 | } 19 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleAdapter.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | import android.graphics.Color; 4 | import android.support.annotation.LayoutRes; 5 | import android.support.annotation.NonNull; 6 | import android.view.Gravity; 7 | import android.view.LayoutInflater; 8 | import android.view.ViewGroup; 9 | import android.widget.TextView; 10 | 11 | /** 12 | *
Email:1006368252@qq.com 13 | *
QQ:1006368252 14 | * create time: 2018/12/22 23:34 Saturday 15 | * 16 | * @author jsc 17 | */ 18 | public class SimpleAdapter extends BaseHeaderFooterAdapter { 19 | 20 | public SimpleAdapter() { 21 | } 22 | 23 | public SimpleAdapter(@LayoutRes int dataLayoutId) { 24 | super(dataLayoutId); 25 | } 26 | 27 | @NonNull 28 | @Override 29 | public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) { 30 | BaseViewHolder holder = null; 31 | switch (viewType) { 32 | case TYPE_HEADER: 33 | if (getHeaderLayoutId() == -1) 34 | throw new IllegalArgumentException(getClass().getSimpleName() + " : please set header layout first."); 35 | holder = new BaseViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(getHeaderLayoutId(), viewGroup, false)); 36 | if (getOnCreateViewHolderListener() != null) { 37 | getOnCreateViewHolderListener().onCreateHeaderViewHolder(holder); 38 | } 39 | break; 40 | case TYPE_DATA: 41 | if (getDataLayoutId() == -1) 42 | throw new IllegalArgumentException(getClass().getSimpleName() + " : please set footer layout first."); 43 | holder = new BaseViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(getDataLayoutId(), viewGroup, false)); 44 | if (getOnCreateViewHolderListener() != null) { 45 | getOnCreateViewHolderListener().onCreateDataViewHolder(holder); 46 | } 47 | break; 48 | case TYPE_FOOTER: 49 | if (getFooterLayoutId() == -1) 50 | throw new IllegalArgumentException(getClass().getSimpleName() + " : please set footer layout first."); 51 | holder = new BaseViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(getFooterLayoutId(), viewGroup, false)); 52 | if (getOnCreateViewHolderListener() != null) { 53 | getOnCreateViewHolderListener().onCreateFooterViewHolder(holder); 54 | } 55 | break; 56 | case TYPE_EMPTY: 57 | holder = new BaseViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(getEmptyLayoutId() == -1 ? R.layout.recycler_default_empty_list_layout : getEmptyLayoutId(), viewGroup, false)); 58 | if (getOnCreateViewHolderListener() != null) { 59 | getOnCreateViewHolderListener().onCreateEmptyViewHolder(holder); 60 | } 61 | break; 62 | default: 63 | TextView textView = new TextView(viewGroup.getContext()); 64 | textView.setTextColor(Color.RED); 65 | textView.setGravity(Gravity.CENTER); 66 | textView.setText("Unknown view type"); 67 | textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); 68 | holder = new BaseViewHolder(textView); 69 | break; 70 | } 71 | return holder; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleAdapter2.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | /** 4 | *
Email:1006368252@qq.com 5 | *
QQ:1006368252 6 | * create time: 2018/12/22 23:34 Saturday 7 | * 8 | * @author jsc 9 | */ 10 | public class SimpleAdapter2 extends SimpleAdapter { 11 | 12 | public SimpleAdapter2() { 13 | } 14 | 15 | public SimpleAdapter2(int dataLayoutId) { 16 | super(dataLayoutId); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleAdapter3.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | /** 4 | *
Email:1006368252@qq.com 5 | *
QQ:1006368252 6 | * create time: 2018/12/22 23:34 Saturday 7 | * 8 | * @author jsc 9 | */ 10 | public class SimpleAdapter3 extends SimpleAdapter2 { 11 | 12 | public SimpleAdapter3() { 13 | } 14 | 15 | public SimpleAdapter3(int dataLayoutId) { 16 | super(dataLayoutId); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleAdapter4.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | /** 4 | *
Email:1006368252@qq.com 5 | *
QQ:1006368252 6 | * create time: 2018/12/22 23:34 Saturday 7 | * 8 | * @author jsc 9 | */ 10 | public class SimpleAdapter4 extends SimpleAdapter { 11 | 12 | public SimpleAdapter4() { 13 | } 14 | 15 | public SimpleAdapter4(int dataLayoutId) { 16 | super(dataLayoutId); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleAnimationListener.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | import android.view.animation.Animation; 4 | 5 | /** 6 | *
Email:1006368252@qq.com 7 | *
QQ:1006368252 8 | * create time: 2018/12/27 21:46 Thursday 9 | * 10 | * @author jsc 11 | */ 12 | public class SimpleAnimationListener implements Animation.AnimationListener { 13 | @Override 14 | public void onAnimationStart(Animation animation) { 15 | 16 | } 17 | 18 | @Override 19 | public void onAnimationEnd(Animation animation) { 20 | 21 | } 22 | 23 | @Override 24 | public void onAnimationRepeat(Animation animation) { 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleAnimatorListener.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | import android.animation.Animator; 4 | 5 | /** 6 | *
Email:1006368252@qq.com 7 | *
QQ:1006368252 8 | * create time: 2018/12/27 21:44 Thursday 9 | * 10 | * @author jsc 11 | */ 12 | public class SimpleAnimatorListener implements Animator.AnimatorListener { 13 | 14 | @Override 15 | public void onAnimationStart(Animator animation) { 16 | 17 | } 18 | 19 | @Override 20 | public void onAnimationEnd(Animator animation) { 21 | 22 | } 23 | 24 | @Override 25 | public void onAnimationCancel(Animator animation) { 26 | 27 | } 28 | 29 | @Override 30 | public void onAnimationRepeat(Animator animation) { 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleCreateViewHolderListener.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | /** 6 | *
Email:1006368252@qq.com 7 | *
QQ:1006368252 8 | * create time: 2019/3/2 17:44 Saturday 9 | * 10 | * @author jsc 11 | */ 12 | public class SimpleCreateViewHolderListener implements OnCreateViewHolderListener { 13 | 14 | @Override 15 | public void onCreateHeaderViewHolder(@NonNull BaseHeaderFooterAdapter.BaseViewHolder holder) { 16 | 17 | } 18 | 19 | @Override 20 | public void onCreateDataViewHolder(@NonNull BaseHeaderFooterAdapter.BaseViewHolder holder) { 21 | 22 | } 23 | 24 | @Override 25 | public void onCreateFooterViewHolder(@NonNull BaseHeaderFooterAdapter.BaseViewHolder holder) { 26 | 27 | } 28 | 29 | @Override 30 | public void onCreateEmptyViewHolder(@NonNull BaseHeaderFooterAdapter.BaseViewHolder holder) { 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleItemChildClickListener.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.view.View; 5 | 6 | /** 7 | *
Email:1006368252@qq.com 8 | *
QQ:1006368252 9 | * create time: 2018/12/24 09:38 Monday 10 | * 11 | * @author jsc 12 | */ 13 | public class SimpleItemChildClickListener implements OnItemChildClickListener { 14 | 15 | @Override 16 | public void onHeaderItemChildClick(@NonNull View headerChild, int position, H headerBean) { 17 | 18 | } 19 | 20 | @Override 21 | public void onDataItemChildClick(@NonNull View dataItemChild, int position, D dataBean) { 22 | 23 | } 24 | 25 | @Override 26 | public void onFooterItemChildClick(@NonNull View footerChild, int position, F footerBean) { 27 | 28 | } 29 | 30 | @Override 31 | public void onEmptyItemChildClick(@NonNull View emptyChild, int position, E emptyBean) { 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleItemChildClickListener2.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | /** 4 | *
Email:1006368252@qq.com 5 | *
QQ:1006368252 6 | * create time: 2018/12/24 09:38 Monday 7 | * 8 | * @author jsc 9 | */ 10 | public class SimpleItemChildClickListener2 extends SimpleItemChildClickListener { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleItemChildClickListener3.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | /** 4 | *
Email:1006368252@qq.com 5 | *
QQ:1006368252 6 | * create time: 2018/12/24 09:38 Monday 7 | * 8 | * @author jsc 9 | */ 10 | public class SimpleItemChildClickListener3 extends SimpleItemChildClickListener2 { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleItemChildClickListener4.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | /** 4 | *
Email:1006368252@qq.com 5 | *
QQ:1006368252 6 | * create time: 2018/12/24 09:38 Monday 7 | * 8 | * @author jsc 9 | */ 10 | public class SimpleItemChildClickListener4 extends SimpleItemChildClickListener { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleItemChildLongClickListener.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.view.View; 5 | 6 | /** 7 | *
Email:1006368252@qq.com 8 | *
QQ:1006368252 9 | * create time: 2018/12/24 09:38 Monday 10 | * 11 | * @author jsc 12 | */ 13 | public class SimpleItemChildLongClickListener implements OnItemChildLongClickListener { 14 | 15 | @Override 16 | public boolean onHeaderItemChildLongClick(@NonNull View headerChild, int position, H headerBean) { 17 | return false; 18 | } 19 | 20 | @Override 21 | public boolean onDataItemChildLongClick(@NonNull View dataItemChild, int position, D dataBean) { 22 | return false; 23 | } 24 | 25 | @Override 26 | public boolean onFooterItemChildLongClick(@NonNull View footerChild, int position, F footerBean) { 27 | return false; 28 | } 29 | 30 | @Override 31 | public boolean onEmptyItemChildLongClick(@NonNull View emptyChild, int position, E emptyBean) { 32 | return false; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleItemChildLongClickListener2.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | /** 4 | *
Email:1006368252@qq.com 5 | *
QQ:1006368252 6 | * create time: 2018/12/24 09:38 Monday 7 | * 8 | * @author jsc 9 | */ 10 | public class SimpleItemChildLongClickListener2 extends SimpleItemChildLongClickListener { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleItemChildLongClickListener3.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | /** 4 | *
Email:1006368252@qq.com 5 | *
QQ:1006368252 6 | * create time: 2018/12/24 09:38 Monday 7 | * 8 | * @author jsc 9 | */ 10 | public class SimpleItemChildLongClickListener3 extends SimpleItemChildLongClickListener2 { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleItemChildLongClickListener4.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | /** 4 | *
Email:1006368252@qq.com 5 | *
QQ:1006368252 6 | * create time: 2018/12/24 09:38 Monday 7 | * 8 | * @author jsc 9 | */ 10 | public class SimpleItemChildLongClickListener4 extends SimpleItemChildLongClickListener { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleItemClickListener.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | 4 | import android.support.annotation.NonNull; 5 | import android.view.View; 6 | 7 | /** 8 | *
Email:1006368252@qq.com 9 | *
QQ:1006368252 10 | * create time: 2018/12/24 09:36 Monday 11 | * 12 | * @author jsc 13 | */ 14 | public class SimpleItemClickListener implements OnItemClickListener { 15 | 16 | @Override 17 | public void onHeaderItemClick(@NonNull View headerItemView, int position, H headerBean) { 18 | 19 | } 20 | 21 | @Override 22 | public void onDataItemClick(@NonNull View dataItemView, int position, D dataBean) { 23 | 24 | } 25 | 26 | @Override 27 | public void onFooterItemClick(@NonNull View footerItemView, int position, F footerBean) { 28 | 29 | } 30 | 31 | @Override 32 | public void onEmptyItemClick(@NonNull View emptyItemView, int position, E emptyBean) { 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleItemClickListener2.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | 4 | /** 5 | *
Email:1006368252@qq.com 6 | *
QQ:1006368252 7 | * create time: 2018/12/24 09:36 Monday 8 | * 9 | * @author jsc 10 | */ 11 | public class SimpleItemClickListener2 extends SimpleItemClickListener { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleItemClickListener3.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | 4 | /** 5 | *
Email:1006368252@qq.com 6 | *
QQ:1006368252 7 | * create time: 2018/12/24 09:36 Monday 8 | * 9 | * @author jsc 10 | */ 11 | public class SimpleItemClickListener3 extends SimpleItemClickListener2 { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleItemClickListener4.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | 4 | /** 5 | *
Email:1006368252@qq.com 6 | *
QQ:1006368252 7 | * create time: 2018/12/24 09:36 Monday 8 | * 9 | * @author jsc 10 | */ 11 | public class SimpleItemClickListener4 extends SimpleItemClickListener { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleItemLongClickListener.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | 4 | import android.support.annotation.NonNull; 5 | import android.view.View; 6 | 7 | /** 8 | *
Email:1006368252@qq.com 9 | *
QQ:1006368252 10 | * create time: 2018/12/24 09:36 Monday 11 | * 12 | * @author jsc 13 | */ 14 | public class SimpleItemLongClickListener implements OnItemLongClickListener { 15 | 16 | @Override 17 | public boolean onHeaderItemLongClick(@NonNull View headerItemView, int position, H headerBean) { 18 | return false; 19 | } 20 | 21 | @Override 22 | public boolean onDataItemLongClick(@NonNull View dataItemView, int position, D dataBean) { 23 | return false; 24 | } 25 | 26 | @Override 27 | public boolean onFooterItemLongClick(@NonNull View footerItemView, int position, F footerBean) { 28 | return false; 29 | } 30 | 31 | @Override 32 | public boolean onEmptyItemLongClick(@NonNull View emptyItemView, int position, E emptyBean) { 33 | return false; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleItemLongClickListener2.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | 4 | /** 5 | *
Email:1006368252@qq.com 6 | *
QQ:1006368252 7 | * create time: 2018/12/24 09:36 Monday 8 | * 9 | * @author jsc 10 | */ 11 | public class SimpleItemLongClickListener2 extends SimpleItemLongClickListener { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleItemLongClickListener3.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | 4 | /** 5 | *
Email:1006368252@qq.com 6 | *
QQ:1006368252 7 | * create time: 2018/12/24 09:36 Monday 8 | * 9 | * @author jsc 10 | */ 11 | public class SimpleItemLongClickListener3 extends SimpleItemLongClickListener2 { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/SimpleItemLongClickListener4.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | 4 | /** 5 | *
Email:1006368252@qq.com 6 | *
QQ:1006368252 7 | * create time: 2018/12/24 09:36 Monday 8 | * 9 | * @author jsc 10 | */ 11 | public class SimpleItemLongClickListener4 extends SimpleItemLongClickListener { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/bean/ISelectable.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter.bean; 2 | 3 | /** 4 | *
Email:1006368252@qq.com 5 | *
QQ:1006368252 6 | * create time: 2019/3/9 09:16 Saturday 7 | * 8 | * @author jsc 9 | */ 10 | public interface ISelectable { 11 | 12 | boolean isSelected(); 13 | 14 | void setSelected(boolean selected); 15 | } 16 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/bean/SelectableBean.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter.bean; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | *
Email:1006368252@qq.com 7 | *
QQ:1006368252 8 | * create time: 2019/1/15 14:58 Tuesday 9 | * 10 | * @author jsc 11 | */ 12 | public class SelectableBean implements Serializable, ISelectable { 13 | 14 | private transient boolean selected; 15 | 16 | @Override 17 | public boolean isSelected() { 18 | return selected; 19 | } 20 | 21 | @Override 22 | public void setSelected(boolean selected) { 23 | this.selected = selected; 24 | } 25 | 26 | public void toggleSelected(){ 27 | setSelected(!isSelected()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/decoration/LineItemDecoration.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter.decoration; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Paint; 5 | import android.graphics.Rect; 6 | import android.support.annotation.ColorInt; 7 | import android.support.annotation.NonNull; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.View; 10 | 11 | public class LineItemDecoration extends RecyclerView.ItemDecoration { 12 | 13 | private Paint paint; 14 | private Rect rect = new Rect(); 15 | private int leftMargin; 16 | private int rightMargin; 17 | private int lineHeight; 18 | 19 | public LineItemDecoration() { 20 | paint = new Paint(Paint.ANTI_ALIAS_FLAG); 21 | paint.setStyle(Paint.Style.FILL); 22 | } 23 | 24 | public LineItemDecoration setLineHeight(int lineHeight) { 25 | this.lineHeight = lineHeight; 26 | return this; 27 | } 28 | 29 | public LineItemDecoration setLineColor(@ColorInt int lineColor) { 30 | paint.setColor(lineColor); 31 | return this; 32 | } 33 | 34 | public LineItemDecoration setLeftMargin(int leftMargin) { 35 | this.leftMargin = leftMargin; 36 | return this; 37 | } 38 | 39 | public LineItemDecoration setRightMargin(int rightMargin) { 40 | this.rightMargin = rightMargin; 41 | return this; 42 | } 43 | 44 | @Override 45 | public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { 46 | int childCount = parent.getChildCount(); 47 | for (int i = 0; i < childCount; i++) { 48 | View child = parent.getChildAt(i); 49 | rect.set(leftMargin, child.getBottom(), child.getRight() - rightMargin, child.getBottom() + lineHeight); 50 | c.drawRect(rect, paint); 51 | } 52 | } 53 | 54 | @Override 55 | public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { 56 | super.getItemOffsets(outRect, view, parent, state); 57 | outRect.bottom = lineHeight; 58 | } 59 | } -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/decoration/SpaceItemDecoration.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter.decoration; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Rect; 5 | import android.support.annotation.NonNull; 6 | import android.support.v7.widget.GridLayoutManager; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.support.v7.widget.StaggeredGridLayoutManager; 10 | import android.view.View; 11 | 12 | /** 13 | *
Email:1006368252@qq.com 14 | *
QQ:1006368252 15 | * create time: 2018/12/16 17:22 16 | * 17 | * @author jsc 18 | */ 19 | public class SpaceItemDecoration extends RecyclerView.ItemDecoration { 20 | 21 | private int left; 22 | private int top; 23 | private int right; 24 | private int bottom; 25 | private boolean showFirstLeft = false; 26 | private boolean showFirstTop = false; 27 | private boolean showLastRight = false; 28 | private boolean showLastBottom = false; 29 | 30 | public SpaceItemDecoration(int space) { 31 | this(space, space, space, space); 32 | } 33 | 34 | public SpaceItemDecoration(int lr, int tb) { 35 | this(lr, tb, lr, tb); 36 | } 37 | 38 | public SpaceItemDecoration(int left, int top, int right, int bottom) { 39 | this.left = left; 40 | this.top = top; 41 | this.right = right; 42 | this.bottom = bottom; 43 | } 44 | 45 | public SpaceItemDecoration showFirstLeft(boolean show) { 46 | showFirstLeft = show; 47 | return this; 48 | } 49 | 50 | public SpaceItemDecoration showFirstTop(boolean show) { 51 | showFirstTop = show; 52 | return this; 53 | } 54 | 55 | public SpaceItemDecoration showLastRight(boolean show) { 56 | showLastRight = show; 57 | return this; 58 | } 59 | 60 | public SpaceItemDecoration showLastBottom(boolean show) { 61 | showLastBottom = show; 62 | return this; 63 | } 64 | 65 | @Override 66 | public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { 67 | super.getItemOffsets(outRect, view, parent, state); 68 | RecyclerView.Adapter adapter = parent.getAdapter(); 69 | RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); 70 | if (null == adapter || null == layoutManager || adapter.getItemCount() == 0) 71 | return; 72 | 73 | int viewIndex = parent.getChildAdapterPosition(view); 74 | if (layoutManager instanceof GridLayoutManager) { 75 | outRect.set(left, top, right, bottom); 76 | int spanCount = ((GridLayoutManager) layoutManager).getSpanCount(); 77 | int rowCount = adapter.getItemCount() / spanCount; 78 | if (adapter.getItemCount() % spanCount > 0) 79 | rowCount++; 80 | 81 | int rowIndex = viewIndex / spanCount; 82 | int columnIndex = viewIndex % spanCount; 83 | 84 | if (!showFirstTop && rowIndex == 0) 85 | outRect.top = 0; 86 | if (!showLastBottom && rowIndex == rowCount - 1) 87 | outRect.bottom = 0; 88 | if (!showFirstLeft && columnIndex == 0) 89 | outRect.left = 0; 90 | if (!showLastRight && columnIndex == spanCount - 1) 91 | outRect.right = 0; 92 | } else if (layoutManager instanceof LinearLayoutManager) { 93 | outRect.set(left, top, right, bottom); 94 | switch (((LinearLayoutManager) layoutManager).getOrientation()) { 95 | case LinearLayoutManager.HORIZONTAL: 96 | if (!showFirstLeft && viewIndex == 0) 97 | outRect.left = 0; 98 | if (!showLastRight && viewIndex == adapter.getItemCount() - 1) 99 | outRect.right = 0; 100 | break; 101 | case LinearLayoutManager.VERTICAL: 102 | if (!showFirstTop && viewIndex == 0) 103 | outRect.top = 0; 104 | if (!showLastBottom && viewIndex == adapter.getItemCount() - 1) 105 | outRect.bottom = 0; 106 | break; 107 | } 108 | } else if (layoutManager instanceof StaggeredGridLayoutManager) { 109 | 110 | } 111 | } 112 | 113 | @Override 114 | public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { 115 | super.onDraw(c, parent, state); 116 | } 117 | 118 | @Override 119 | public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { 120 | super.onDrawOver(c, parent, state); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/refresh/ILoadMore.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter.refresh; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.view.View; 5 | 6 | /** 7 | *
Email:1006368252@qq.com 8 | *
QQ:1006368252 9 | * create time: 2019/1/4 17:05 Friday 10 | * 11 | * @author jsc 12 | */ 13 | public interface ILoadMore { 14 | 15 | void initChildren(@NonNull View footerView); 16 | 17 | /** 18 | * The call back of pulling up to load more. 19 | * @param state See {@link PullToRefreshRecyclerView.State}. 20 | * @param txt the tips of pulling up. 21 | */ 22 | void onUpdateState(@PullToRefreshRecyclerView.State int state, CharSequence txt); 23 | 24 | /** 25 | * The call back of pulling up. 26 | * @param state See {@link PullToRefreshRecyclerView.State}. 27 | * @param loadMoreEnable load more enable or disable 28 | * @param isLoadingMore true, loading more, else false. 29 | * @param scrollY the scroll of y coordination 30 | * @param footerHeight the height of the load more view. 31 | */ 32 | void onScroll(@PullToRefreshRecyclerView.State int state, boolean loadMoreEnable, boolean isLoadingMore, int scrollY, int footerHeight, int loadMoreThresholdValue); 33 | } 34 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/refresh/IRefresh.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter.refresh; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.view.View; 5 | 6 | /** 7 | *
Email:1006368252@qq.com 8 | *
QQ:1006368252 9 | * create time: 2019/1/4 17:05 Friday 10 | * 11 | * @author jsc 12 | */ 13 | public interface IRefresh { 14 | 15 | void initChildren(@NonNull View headerView); 16 | void updateLastRefreshTime(long lastRefreshTimeStamp); 17 | void onUpdateState(@PullToRefreshRecyclerView.State int state, CharSequence txt); 18 | void onScroll(@PullToRefreshRecyclerView.State int state, boolean refreshEnable, boolean isRefreshing, int scrollY, int headerHeight, int refreshThresholdValue); 19 | } 20 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/java/jsc/kit/adapter/refresh/SwipeRefreshRecyclerView.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter.refresh; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ObjectAnimator; 5 | import android.content.Context; 6 | import android.content.res.TypedArray; 7 | import android.graphics.Rect; 8 | import android.support.annotation.NonNull; 9 | import android.support.annotation.Nullable; 10 | import android.support.v4.widget.SwipeRefreshLayout; 11 | import android.support.v7.widget.LinearLayoutManager; 12 | import android.support.v7.widget.RecyclerView; 13 | import android.support.v7.widget.StaggeredGridLayoutManager; 14 | import android.util.AttributeSet; 15 | import android.util.Log; 16 | import android.view.Gravity; 17 | import android.view.LayoutInflater; 18 | import android.view.View; 19 | import android.view.ViewGroup; 20 | import android.widget.FrameLayout; 21 | import android.widget.ImageView; 22 | 23 | import jsc.kit.adapter.R; 24 | import jsc.kit.adapter.SimpleAnimatorListener; 25 | 26 | /** 27 | *
Email:1006368252@qq.com 28 | *
QQ:1006368252 29 | * create time: 2018/12/23 15:51 30 | * 31 | * @author jsc 32 | */ 33 | public class SwipeRefreshRecyclerView extends FrameLayout { 34 | public static final String TAG = "SwipeRefresh"; 35 | public static final int DEFAULT_START_PAGE_NUMBER = 1; 36 | public static final int DEFAULT_PAGE_SIZE = 12; 37 | private SwipeRefreshLayout swipeRefreshLayout; 38 | private RecyclerView recyclerView; 39 | private View loadMoreView; 40 | 41 | private int startPageNumber = DEFAULT_START_PAGE_NUMBER; 42 | private int currentPageNumber = startPageNumber; 43 | private int pageSize = DEFAULT_PAGE_SIZE; 44 | private boolean isLoading = false; 45 | private boolean hasMorePage = false; 46 | private boolean refreshEnable = true; 47 | private boolean loadMoreEnable = true; 48 | private Rect visibleRect = new Rect(); 49 | private OnRefreshListener onRefreshListener = null; 50 | private int translationDistance = 0; 51 | private Animator defaultLoadingAnimator = null; 52 | private Animator defaultLoadedAnimator = null; 53 | private RecyclerView.OnScrollListener scrollListener = new RecyclerView.OnScrollListener() { 54 | @Override 55 | public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { 56 | super.onScrollStateChanged(recyclerView, newState); 57 | if (newState != RecyclerView.SCROLL_STATE_IDLE) 58 | return; 59 | 60 | RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); 61 | RecyclerView.Adapter adapter = recyclerView.getAdapter(); 62 | if (layoutManager == null || adapter == null) { 63 | // swipeRefreshLayout.setEnabled(false); 64 | return; 65 | } 66 | 67 | if (isLoading() || !isLoadMoreEnable() || !isHasMorePage() || !isScrollToBottom()) 68 | return; 69 | 70 | //如果第一条和最后一条同时可见 71 | if (swipeRefreshLayout.isEnabled()) { 72 | //如果SwipeRefreshLayout中的CircleImageView可见,则走刷新逻辑 73 | if (isCircleImageViewVisible()) { 74 | return; 75 | } 76 | } 77 | 78 | Log.i(TAG, "onScrollStateChanged: "); 79 | if (onRefreshListener != null) { 80 | showScrollUpAnim(); 81 | } 82 | } 83 | 84 | @Override 85 | public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { 86 | super.onScrolled(recyclerView, dx, dy); 87 | } 88 | }; 89 | 90 | public SwipeRefreshRecyclerView(Context context) { 91 | super(context); 92 | initView(context); 93 | initAttrs(context, null, 0); 94 | } 95 | 96 | public SwipeRefreshRecyclerView(Context context, @Nullable AttributeSet attrs) { 97 | super(context, attrs); 98 | initView(context); 99 | initAttrs(context, attrs, 0); 100 | } 101 | 102 | public SwipeRefreshRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 103 | super(context, attrs, defStyleAttr); 104 | initView(context); 105 | initAttrs(context, attrs, defStyleAttr); 106 | } 107 | 108 | private void initView(Context context) { 109 | inflate(context, R.layout.recycler_default_swipe_refresh_recycler_view_layout, this); 110 | swipeRefreshLayout = findViewById(R.id.swipe_refresh_layout); 111 | recyclerView = findViewById(R.id.recycler_view); 112 | 113 | swipeRefreshLayout.setColorSchemeColors(0xFF3F51B5, 0xFF303F9F); 114 | swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { 115 | @Override 116 | public void onRefresh() { 117 | setLoading(true); 118 | currentPageNumber = startPageNumber; 119 | onRefreshListener.onRefresh(currentPageNumber, pageSize); 120 | } 121 | }); 122 | recyclerView.addOnScrollListener(scrollListener); 123 | } 124 | 125 | private void initAttrs(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 126 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SwipeRefreshRecyclerView, defStyleAttr, 0); 127 | int layoutId = a.getResourceId(R.styleable.SwipeRefreshRecyclerView_srrvLoadMoreLayout, R.layout.recycler_default_load_more_layout); 128 | a.recycle(); 129 | 130 | if (loadMoreView != null) { 131 | removeView(loadMoreView); 132 | loadMoreView = null; 133 | } 134 | 135 | if (layoutId != -1) { 136 | LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); 137 | params.gravity = Gravity.BOTTOM; 138 | loadMoreView = LayoutInflater.from(context).inflate(layoutId, this, false); 139 | addView(loadMoreView, params); 140 | } 141 | } 142 | 143 | @Override 144 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 145 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 146 | translationDistance = loadMoreView.getMeasuredHeight(); 147 | loadMoreView.setTranslationY(translationDistance); 148 | } 149 | 150 | private boolean isCircleImageViewVisible() { 151 | for (int i = 0; i < swipeRefreshLayout.getChildCount(); i++) { 152 | View child = swipeRefreshLayout.getChildAt(i); 153 | if (child instanceof ImageView) { 154 | child.getLocalVisibleRect(visibleRect); 155 | if (visibleRect.bottom > 0) 156 | return true; 157 | } 158 | } 159 | return false; 160 | } 161 | 162 | public void reset() { 163 | setHasMorePage(false); 164 | setLoading(false); 165 | if (defaultLoadingAnimator != null && defaultLoadingAnimator.isRunning()) 166 | defaultLoadingAnimator.cancel(); 167 | if (defaultLoadedAnimator != null && defaultLoadedAnimator.isRunning()) 168 | defaultLoadedAnimator.cancel(); 169 | loadMoreView.setTranslationY(translationDistance); 170 | } 171 | 172 | private void showScrollUpAnim() { 173 | if (isLoading()) 174 | return; 175 | 176 | setLoading(true); 177 | swipeRefreshLayout.setEnabled(false); 178 | if (defaultLoadingAnimator == null) 179 | defaultLoadingAnimator = createDefaultLoadingAnimator(); 180 | defaultLoadingAnimator.start(); 181 | } 182 | 183 | private void showScrollDownAnim() { 184 | if (defaultLoadedAnimator == null) 185 | defaultLoadedAnimator = createDefaultLoadedAnimator(); 186 | defaultLoadedAnimator.start(); 187 | } 188 | 189 | /** 190 | * Whether scrolled to the bottom of list. 191 | * @return true, scrolled to the bottom of list, else false. 192 | */ 193 | private boolean isScrollToBottom() { 194 | return recyclerView.computeVerticalScrollRange() <= 195 | recyclerView.computeVerticalScrollOffset() + 196 | recyclerView.computeVerticalScrollExtent(); 197 | } 198 | 199 | public SwipeRefreshLayout getSwipeRefreshLayout() { 200 | return swipeRefreshLayout; 201 | } 202 | 203 | public RecyclerView getRecyclerView() { 204 | return recyclerView; 205 | } 206 | 207 | public View getLoadMoreView() { 208 | return loadMoreView; 209 | } 210 | 211 | public void setOnRefreshListener(OnRefreshListener onRefreshListener) { 212 | this.onRefreshListener = onRefreshListener; 213 | } 214 | 215 | public void loadComplete() { 216 | if (currentPageNumber == startPageNumber) 217 | refreshComplete(); 218 | else 219 | loadMoreComplete(); 220 | } 221 | 222 | public void refreshComplete() { 223 | isLoading = false; 224 | swipeRefreshLayout.setRefreshing(false); 225 | } 226 | 227 | public void loadMoreComplete() { 228 | showScrollDownAnim(); 229 | } 230 | 231 | public void refresh() { 232 | if (isLoading()) 233 | return; 234 | refreshDelay(0); 235 | } 236 | 237 | public void refreshDelay(long delay) { 238 | if (isLoading()) 239 | return; 240 | 241 | swipeRefreshLayout.setRefreshing(true); 242 | if (delay <= 0) { 243 | startRefreshing(); 244 | return; 245 | } 246 | postDelayed(new Runnable() { 247 | @Override 248 | public void run() { 249 | startRefreshing(); 250 | } 251 | }, delay); 252 | } 253 | 254 | private void startRefreshing() { 255 | isLoading = true; 256 | if (onRefreshListener != null) { 257 | currentPageNumber = startPageNumber; 258 | onRefreshListener.onRefresh(currentPageNumber, pageSize); 259 | } 260 | } 261 | 262 | public boolean isLoading() { 263 | return isLoading; 264 | } 265 | 266 | public void setLoading(boolean loading) { 267 | isLoading = loading; 268 | } 269 | 270 | public boolean isRefreshEnable() { 271 | return refreshEnable; 272 | } 273 | 274 | public void setRefreshEnable(boolean refreshEnable) { 275 | this.refreshEnable = refreshEnable; 276 | swipeRefreshLayout.setEnabled(refreshEnable); 277 | } 278 | 279 | public boolean isLoadMoreEnable() { 280 | return loadMoreEnable; 281 | } 282 | 283 | public void setLoadMoreEnable(boolean loadMoreEnable) { 284 | this.loadMoreEnable = loadMoreEnable; 285 | } 286 | 287 | public boolean isHasMorePage() { 288 | return hasMorePage; 289 | } 290 | 291 | public void setHasMorePage(boolean hasMorePage) { 292 | this.hasMorePage = hasMorePage; 293 | } 294 | 295 | public boolean isFirstPage() { 296 | return currentPageNumber == startPageNumber; 297 | } 298 | 299 | public int getStartPageNumber() { 300 | return startPageNumber; 301 | } 302 | 303 | public void setStartPageNumber(int startPageNumber) { 304 | this.startPageNumber = startPageNumber; 305 | } 306 | 307 | public int getCurrentPageNumber() { 308 | return currentPageNumber; 309 | } 310 | 311 | public int getPageSize() { 312 | return pageSize; 313 | } 314 | 315 | public void setPageSize(int pageSize) { 316 | this.pageSize = pageSize; 317 | } 318 | 319 | private Animator createDefaultLoadingAnimator() { 320 | ObjectAnimator animator = ObjectAnimator.ofFloat(loadMoreView, TRANSLATION_Y, loadMoreView.getTranslationY(), 0); 321 | animator.setDuration(300); 322 | animator.addListener(new SimpleAnimatorListener() { 323 | @Override 324 | public void onAnimationEnd(Animator animation) { 325 | if (onRefreshListener != null) { 326 | currentPageNumber++; 327 | onRefreshListener.onLoadMore(currentPageNumber, pageSize); 328 | } 329 | } 330 | }); 331 | return animator; 332 | } 333 | 334 | private Animator createDefaultLoadedAnimator() { 335 | ObjectAnimator animator = ObjectAnimator.ofFloat(loadMoreView, TRANSLATION_Y, loadMoreView.getTranslationY(), translationDistance); 336 | animator.setDuration(300); 337 | animator.addListener(new SimpleAnimatorListener() { 338 | @Override 339 | public void onAnimationEnd(Animator animation) { 340 | setLoading(false); 341 | swipeRefreshLayout.setEnabled(true 342 | ); 343 | } 344 | }); 345 | return animator; 346 | } 347 | 348 | @Override 349 | protected void onDetachedFromWindow() { 350 | getHandler().removeCallbacksAndMessages(null); 351 | reset(); 352 | super.onDetachedFromWindow(); 353 | } 354 | 355 | public interface OnRefreshListener { 356 | /** 357 | * Do refreshing. 358 | */ 359 | void onRefresh(int currentPageNumber, int pageSize); 360 | 361 | /** 362 | * Do loading more. 363 | */ 364 | void onLoadMore(int currentPageNumber, int pageSize); 365 | } 366 | } 367 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/res/drawable/recycler_header_arrow.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/res/layout/recycler_default_empty_list_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/res/layout/recycler_default_footer_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | 13 | 19 | 20 | 21 | 22 | 28 | 29 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/res/layout/recycler_default_header_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 18 | 19 | 23 | 24 | 27 | 28 | 34 | 35 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/res/layout/recycler_default_load_more_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 24 | 25 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/res/layout/recycler_default_swipe_refresh_recycler_view_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/res/layout/recycler_pull_to_refresh_recycler_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/res/values-zh/recycler_strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 上次刷新 : %s 4 | 下拉刷新 5 | 释放刷新 6 | 正在刷新,请稍后 7 | 已刷新 8 | 上拉加载更多 9 | 释放加载更多 10 | 正在加载,请稍后 11 | 已加载 12 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/res/values/recycler_attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/res/values/recycler_ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /adapterLibrary/src/main/res/values/recycler_strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Last refresh: %s 4 | Pull down to refresh. 5 | Release to refresh. 6 | Refreshing…, wait a minute. 7 | Refresh completed. 8 | Pull up to load more. 9 | Release to load more. 10 | Loading…, wait a minute. 11 | Load more completed. 12 | -------------------------------------------------------------------------------- /adapterLibrary/src/test/java/jsc/kit/adapter/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package jsc.kit.adapter; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | import java.text.SimpleDateFormat 2 | 3 | apply plugin: 'com.android.application' 4 | def apkName = "${rootProject.name}.apk" 5 | 6 | android { 7 | compileSdkVersion sdk_veriosn 8 | defaultConfig { 9 | applicationId "jsc.exam.com.adapter" 10 | minSdkVersion min_sdk_veriosn 11 | targetSdkVersion sdk_veriosn 12 | versionCode version_code 13 | versionName version_name 14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 15 | multiDexEnabled true 16 | 17 | buildConfigField("String", "BUILD_TIME", "\"${new SimpleDateFormat("yyyy年MM月dd日 HH:mm").format(new Date())}\"") 18 | buildConfigField("String", "BASE_URL", "\"https://raw.githubusercontent.com/\"") 19 | buildConfigField("String", "VERSION_URL", "\"JustinRoom/${rootProject.name}/master/output/output.json\"") 20 | buildConfigField("String", "DOWNLOAD_URL", "\"JustinRoom/${rootProject.name}/master/output/%s\"") 21 | buildConfigField("String", "GITHUB_URL", "\"https://github.com/JustinRoom/${rootProject.name}\"") 22 | buildConfigField("String", "APK_URL", "\"https://raw.githubusercontent.com/JustinRoom/${rootProject.name}/master/output/${apkName}\"") 23 | } 24 | 25 | signingConfigs { 26 | debug { 27 | keyAlias 'Jsc' 28 | keyPassword '123456' 29 | storeFile file('../JscTestKeyStore.jks') 30 | storePassword '123456' 31 | } 32 | release { 33 | keyAlias 'Jsc' 34 | keyPassword '123456' 35 | storeFile file('../JscTestKeyStore.jks') 36 | storePassword '123456' 37 | } 38 | } 39 | 40 | buildTypes { 41 | debug { 42 | signingConfig signingConfigs.debug 43 | } 44 | release { 45 | minifyEnabled false 46 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 47 | signingConfig signingConfigs.release 48 | } 49 | } 50 | applicationVariants.all { variant -> 51 | variant.outputs.all { 52 | outputFileName = "${apkName}" 53 | } 54 | } 55 | } 56 | 57 | dependencies { 58 | implementation fileTree(include: ['*.jar'], dir: 'libs') 59 | implementation 'com.android.support:appcompat-v7:28.0.0' 60 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 61 | testImplementation 'junit:junit:4.12' 62 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 63 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 64 | implementation project(':adapterLibrary') 65 | implementation 'com.android.support:recyclerview-v7:28.0.0' 66 | 67 | implementation 'com.squareup.retrofit2:retrofit:2.4.0' 68 | implementation 'com.squareup.retrofit2:converter-gson:2.4.0' 69 | implementation 'com.squareup.retrofit2:converter-scalars:2.4.0' 70 | implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0' 71 | //https://github.com/square/okhttp 72 | implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0' 73 | 74 | //https://github.com/ReactiveX/RxAndroid 75 | implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' 76 | implementation 'io.reactivex.rxjava2:rxjava:2.1.12' 77 | } 78 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/jsc/exam/com/adapter/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter; 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 | * Instrumented 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() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("jsc.exam.com.wheelview", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter; 2 | 3 | import android.graphics.Color; 4 | import android.support.annotation.StringRes; 5 | import android.support.v7.app.ActionBar; 6 | import android.support.v7.widget.ActionMenuView; 7 | import android.util.TypedValue; 8 | import android.view.Gravity; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.FrameLayout; 12 | import android.widget.ImageView; 13 | import android.widget.TextView; 14 | 15 | import jsc.exam.com.adapter.utils.CompatResourceUtils; 16 | import jsc.exam.com.adapter.utils.WindowUtils; 17 | 18 | public abstract class BaseActivity extends BaseAppCompatActivity { 19 | 20 | private ImageView ivBack; 21 | private TextView tvTitle; 22 | private ActionMenuView actionMenuView; 23 | 24 | @Override 25 | protected void initActionBar(ActionBar actionBar) { 26 | if (actionBar == null) 27 | return; 28 | 29 | int padding = CompatResourceUtils.getDimensionPixelSize(this, R.dimen.space_12); 30 | FrameLayout customView = new FrameLayout(this); 31 | // customView.setPadding(padding, 0, padding, 0); 32 | ActionBar.LayoutParams barParams = new ActionBar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, WindowUtils.getActionBarSize(this)); 33 | actionBar.setDisplayShowCustomEnabled(true); 34 | actionBar.setCustomView(customView, barParams); 35 | //添加标题 36 | tvTitle = new TextView(this); 37 | tvTitle.setTextColor(Color.WHITE); 38 | tvTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18); 39 | tvTitle.setGravity(Gravity.CENTER); 40 | customView.addView(tvTitle, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)); 41 | //添加返回按钮 42 | ivBack = new ImageView(this); 43 | ivBack.setPadding(padding / 2, 0, padding / 2, 0); 44 | ivBack.setScaleType(ImageView.ScaleType.CENTER_INSIDE); 45 | ivBack.setImageResource(R.drawable.ic_chevron_left_white_24dp); 46 | ivBack.setBackground(WindowUtils.getSelectableItemBackgroundBorderless(this)); 47 | customView.addView(ivBack, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)); 48 | ivBack.setOnClickListener(new View.OnClickListener() { 49 | @Override 50 | public void onClick(View v) { 51 | onBackPressed(); 52 | } 53 | }); 54 | //添加menu菜单 55 | actionMenuView = new ActionMenuView(this); 56 | FrameLayout.LayoutParams menuParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT); 57 | menuParams.gravity = Gravity.END | Gravity.CENTER_VERTICAL; 58 | customView.addView(actionMenuView, menuParams); 59 | } 60 | 61 | public ActionMenuView getActionMenuView() { 62 | return actionMenuView; 63 | } 64 | 65 | public final void showTitleBarBackView(boolean show) { 66 | if (ivBack != null) 67 | ivBack.setVisibility(show ? View.VISIBLE : View.GONE); 68 | } 69 | 70 | public final void setTitleBarTitle(CharSequence title) { 71 | if (tvTitle != null) 72 | tvTitle.setText(title); 73 | } 74 | 75 | public final void setTitleBarTitle(@StringRes int resId) { 76 | if (tvTitle != null) 77 | tvTitle.setText(resId); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/BaseAppCompatActivity.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.CallSuper; 5 | import android.support.annotation.Nullable; 6 | import android.support.annotation.StringRes; 7 | import android.support.v7.app.ActionBar; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.view.Window; 10 | import android.view.WindowManager; 11 | import android.widget.Toast; 12 | 13 | /** 14 | *
Email:1006368252@qq.com 15 | *
QQ:1006368252 16 | * create time: 2019/1/2 11:45 17 | * 18 | * @author jsc 19 | */ 20 | public abstract class BaseAppCompatActivity extends AppCompatActivity { 21 | 22 | /** 23 | * Show full screen or not. 24 | * 25 | * @return {@code true}, show full screen, else not. 26 | */ 27 | protected boolean fullScreen() { 28 | return false; 29 | } 30 | 31 | protected void initActionBar(ActionBar actionBar) { 32 | 33 | } 34 | 35 | @Override 36 | protected void onCreate(@Nullable Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | initComponent(); 39 | if (fullScreen()) { 40 | //without ActionBar 41 | requestWindowFeature(Window.FEATURE_NO_TITLE); 42 | if (getSupportActionBar() != null) 43 | getSupportActionBar().hide(); 44 | //show full screen 45 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 46 | } else { 47 | initActionBar(getSupportActionBar()); 48 | } 49 | } 50 | 51 | /** 52 | * Initialize components here. 53 | */ 54 | protected void initComponent() { 55 | 56 | } 57 | 58 | /** 59 | * Destroy components here. 60 | */ 61 | @CallSuper 62 | protected void destroyComponent() { 63 | 64 | } 65 | 66 | @Override 67 | protected void onDestroy() { 68 | destroyComponent(); 69 | super.onDestroy(); 70 | } 71 | 72 | public final void showToast(@StringRes int resId) { 73 | Toast.makeText(this, resId, Toast.LENGTH_SHORT).show(); 74 | } 75 | 76 | public final void showToast(CharSequence txt) { 77 | Toast.makeText(this, txt, Toast.LENGTH_SHORT).show(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/BaseEmptyFragmentActivity.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter; 2 | 3 | import android.content.pm.ActivityInfo; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.support.v7.app.ActionBar; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.view.Window; 10 | import android.view.WindowManager; 11 | 12 | /** 13 | *
Email:1006368252@qq.com 14 | *
QQ:1006368252 15 | * create time: 2019/1/2 11:45 16 | * 17 | * @author jsc 18 | */ 19 | public abstract class BaseEmptyFragmentActivity extends AppCompatActivity { 20 | 21 | public final static String EXTRA_FULL_SCREEN = "full_screen"; 22 | public final static String EXTRA_SHOW_ACTION_BAR = "show_action_bar"; 23 | public final static String EXTRA_FRAGMENT_CLASS_NAME = "class_name"; 24 | public final static String EXTRA_TITLE = "title"; 25 | public final static String EXTRA_LANDSCAPE = "landscape"; 26 | 27 | public abstract void initActionBar(ActionBar actionBar); 28 | 29 | @Override 30 | protected void onCreate(@Nullable Bundle savedInstanceState) { 31 | super.onCreate(savedInstanceState); 32 | if (getIntent().getBooleanExtra(EXTRA_FULL_SCREEN, false)) { 33 | //without ActionBar 34 | requestWindowFeature(Window.FEATURE_NO_TITLE); 35 | if (getSupportActionBar() != null) 36 | getSupportActionBar().hide(); 37 | //show full screen 38 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 39 | } else { 40 | if (getIntent().getBooleanExtra(EXTRA_SHOW_ACTION_BAR, true)) { 41 | initActionBar(getSupportActionBar()); 42 | } else if (getSupportActionBar() != null) { 43 | getSupportActionBar().hide(); 44 | } 45 | } 46 | 47 | String className = getIntent().getStringExtra(EXTRA_FRAGMENT_CLASS_NAME); 48 | if (className != null && className.length() > 0) { 49 | Class clzz = null; 50 | Object obj = null; 51 | try { 52 | clzz = Class.forName(className); 53 | obj = clzz.newInstance(); 54 | } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) { 55 | e.printStackTrace(); 56 | } 57 | if (obj instanceof Fragment) { 58 | Fragment fragment = (Fragment) obj; 59 | Bundle arguments = getIntent().getExtras(); 60 | if (arguments != null) { 61 | fragment.setArguments(arguments); 62 | } 63 | getSupportFragmentManager().beginTransaction().replace(android.R.id.content, fragment).commit(); 64 | } 65 | } 66 | } 67 | 68 | @Override 69 | protected void onResume() { 70 | if (getIntent().getBooleanExtra(EXTRA_LANDSCAPE, false) && getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) { 71 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 72 | } 73 | super.onResume(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/EmptyFragmentActivity.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter; 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.ActionBar; 8 | import android.support.v7.widget.ActionMenuView; 9 | import android.text.TextUtils; 10 | import android.util.TypedValue; 11 | import android.view.Gravity; 12 | import android.view.View; 13 | import android.view.ViewGroup; 14 | import android.widget.FrameLayout; 15 | import android.widget.ImageView; 16 | import android.widget.TextView; 17 | 18 | import jsc.exam.com.adapter.utils.CompatResourceUtils; 19 | import jsc.exam.com.adapter.utils.WindowUtils; 20 | 21 | /** 22 | *
Email:1006368252@qq.com 23 | *
QQ:1006368252 24 | * create time: 2019/1/2 11:45 25 | * 26 | * @author jsc 27 | */ 28 | public class EmptyFragmentActivity extends BaseEmptyFragmentActivity { 29 | 30 | public static void launch(Context context, Bundle extras) { 31 | context.startActivity(createIntent(context, extras)); 32 | } 33 | 34 | private static Intent createIntent(Context context, Bundle extras) { 35 | Intent intent = new Intent(context, EmptyFragmentActivity.class); 36 | if (extras != null) 37 | intent.putExtras(extras); 38 | return intent; 39 | } 40 | 41 | @Override 42 | public void initActionBar(ActionBar actionBar) { 43 | if (actionBar == null) 44 | return; 45 | 46 | //You can initialize custom action bar here. 47 | int padding = CompatResourceUtils.getDimensionPixelSize(this, R.dimen.space_12); 48 | FrameLayout customView = new FrameLayout(this); 49 | // customView.setPadding(padding, 0, padding, 0); 50 | ActionBar.LayoutParams barParams = new ActionBar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, WindowUtils.getActionBarSize(this)); 51 | actionBar.setDisplayShowCustomEnabled(true); 52 | actionBar.setCustomView(customView, barParams); 53 | //添加标题 54 | TextView tvTitle = new TextView(this); 55 | tvTitle.setTextColor(Color.WHITE); 56 | tvTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18); 57 | tvTitle.setGravity(Gravity.CENTER); 58 | tvTitle.setText(getClass().getSimpleName().replace("Activity", "")); 59 | customView.addView(tvTitle, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)); 60 | //添加返回按钮 61 | ImageView ivBack = new ImageView(this); 62 | ivBack.setPadding(padding / 2, 0, padding / 2, 0); 63 | ivBack.setScaleType(ImageView.ScaleType.CENTER_INSIDE); 64 | ivBack.setImageResource(R.drawable.ic_chevron_left_white_24dp); 65 | ivBack.setBackground(WindowUtils.getSelectableItemBackgroundBorderless(this)); 66 | customView.addView(ivBack, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)); 67 | ivBack.setOnClickListener(new View.OnClickListener() { 68 | @Override 69 | public void onClick(View v) { 70 | onBackPressed(); 71 | } 72 | }); 73 | //添加menu菜单 74 | ActionMenuView actionMenuView = new ActionMenuView(this); 75 | FrameLayout.LayoutParams menuParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT); 76 | menuParams.gravity = Gravity.END | Gravity.CENTER_VERTICAL; 77 | customView.addView(actionMenuView, menuParams); 78 | 79 | String title = getIntent().getStringExtra(EXTRA_TITLE); 80 | tvTitle.setText(TextUtils.isEmpty(title) ? getClass().getSimpleName().replace("Activity", "") : title); 81 | } 82 | } -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/MainActivity.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter; 2 | 3 | import android.Manifest; 4 | import android.content.DialogInterface; 5 | import android.content.Intent; 6 | import android.content.SharedPreferences; 7 | import android.content.pm.PackageInfo; 8 | import android.content.pm.PackageManager; 9 | import android.net.Uri; 10 | import android.os.Bundle; 11 | import android.support.annotation.NonNull; 12 | import android.support.v4.app.ActivityCompat; 13 | import android.support.v7.app.AlertDialog; 14 | import android.support.v7.widget.LinearLayoutManager; 15 | import android.support.v7.widget.RecyclerView; 16 | import android.util.Log; 17 | import android.util.Pair; 18 | import android.view.View; 19 | import android.widget.FrameLayout; 20 | 21 | import org.json.JSONException; 22 | import org.json.JSONObject; 23 | 24 | import java.util.ArrayList; 25 | import java.util.Date; 26 | import java.util.List; 27 | import java.util.Locale; 28 | 29 | import io.reactivex.android.schedulers.AndroidSchedulers; 30 | import io.reactivex.disposables.Disposable; 31 | import io.reactivex.functions.Action; 32 | import io.reactivex.functions.Consumer; 33 | import io.reactivex.schedulers.Schedulers; 34 | import jsc.exam.com.adapter.bean.ClassItem; 35 | import jsc.exam.com.adapter.fragments.AboutFragment; 36 | import jsc.exam.com.adapter.fragments.BaseItemAdapterFragment; 37 | import jsc.exam.com.adapter.fragments.CheckableFragment; 38 | import jsc.exam.com.adapter.fragments.OptionalFragment; 39 | import jsc.exam.com.adapter.fragments.PullToRefreshFragment; 40 | import jsc.exam.com.adapter.fragments.SimpleAdapterFragment; 41 | import jsc.exam.com.adapter.fragments.SwipeRefreshFragment; 42 | import jsc.exam.com.adapter.retrofit.ApiService; 43 | import jsc.exam.com.adapter.retrofit.CustomHttpClient; 44 | import jsc.exam.com.adapter.retrofit.CustomRetrofit; 45 | import jsc.exam.com.adapter.utils.CompatResourceUtils; 46 | import jsc.kit.adapter.SimpleAdapter3; 47 | import jsc.kit.adapter.SimpleItemClickListener3; 48 | import jsc.kit.adapter.decoration.SpaceItemDecoration; 49 | import jsc.kit.adapter.refresh.PullToRefreshRecyclerView; 50 | import okhttp3.OkHttpClient; 51 | import retrofit2.Retrofit; 52 | 53 | public class MainActivity extends BaseActivity { 54 | 55 | SharedPreferences sharedPreferences = null; 56 | @Override 57 | protected void onCreate(Bundle savedInstanceState) { 58 | super.onCreate(savedInstanceState); 59 | PullToRefreshRecyclerView pullToRefreshRecyclerView = new PullToRefreshRecyclerView(this); 60 | pullToRefreshRecyclerView.setRefreshEnable(false); 61 | pullToRefreshRecyclerView.setLoadMoreEnable(false); 62 | pullToRefreshRecyclerView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)); 63 | setContentView(pullToRefreshRecyclerView); 64 | 65 | RecyclerView recyclerView = pullToRefreshRecyclerView.getRecyclerView(); 66 | recyclerView.setLayoutManager(new LinearLayoutManager(this)); 67 | recyclerView.addItemDecoration(new SpaceItemDecoration( 68 | CompatResourceUtils.getDimensionPixelSize(this, R.dimen.space_16), 69 | CompatResourceUtils.getDimensionPixelSize(this, R.dimen.space_2) 70 | )); 71 | setTitleBarTitle(getClass().getSimpleName().replace("Activity", "")); 72 | showTitleBarBackView(false); 73 | 74 | SimpleAdapter3 adapter3 = new SimpleAdapter3() { 75 | @Override 76 | protected void onBindDataViewHolder(@NonNull BaseViewHolder holder, int position, ClassItem dataBean) { 77 | holder.setText(R.id.tv_label, dataBean.getLabel()); 78 | } 79 | }; 80 | adapter3.setOnItemClickListener(new SimpleItemClickListener3() { 81 | @Override 82 | public void onDataItemClick(@NonNull View dataItemView, int position, ClassItem dataBean) { 83 | toNewActivity(dataBean); 84 | } 85 | }); 86 | adapter3.setDataLayoutId(R.layout.main_list_item_layout); 87 | adapter3.bindRecyclerView(recyclerView); 88 | adapter3.setData(getClassItems()); 89 | 90 | //check upgrade if the latest checking time is 2 hours ago 91 | sharedPreferences = getSharedPreferences("share_arc", MODE_PRIVATE); 92 | long lastCheckUpdateTimeStamp = sharedPreferences.getLong("lastCheckUpdateTimeStamp", 0); 93 | long curTime = new Date().getTime(); 94 | if (curTime - lastCheckUpdateTimeStamp > 2 * 60 * 60_000) { 95 | checkUpdate(); 96 | } 97 | 98 | ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0x100); 99 | } 100 | 101 | private void toNewActivity(ClassItem item) { 102 | switch (item.getType()) { 103 | case ClassItem.TYPE_ACTIVITY: 104 | startActivity(new Intent(this, item.getClazz())); 105 | break; 106 | case ClassItem.TYPE_FRAGMENT: 107 | Bundle bundle = new Bundle(); 108 | bundle.putString(EmptyFragmentActivity.EXTRA_TITLE, item.getLabel()); 109 | bundle.putBoolean(EmptyFragmentActivity.EXTRA_SHOW_ACTION_BAR, true); 110 | bundle.putBoolean(EmptyFragmentActivity.EXTRA_LANDSCAPE, item.isLandscape()); 111 | bundle.putString(EmptyFragmentActivity.EXTRA_FRAGMENT_CLASS_NAME, item.getClazz().getName()); 112 | EmptyFragmentActivity.launch(this, bundle); 113 | break; 114 | } 115 | } 116 | 117 | private List getClassItems() { 118 | List classItems = new ArrayList<>(); 119 | classItems.add(new ClassItem(ClassItem.TYPE_FRAGMENT, "SimpleAdapter", SimpleAdapterFragment.class, false)); 120 | classItems.add(new ClassItem(ClassItem.TYPE_FRAGMENT, "SwipeRefresh", SwipeRefreshFragment.class, false)); 121 | classItems.add(new ClassItem(ClassItem.TYPE_FRAGMENT, "PullToRefresh", PullToRefreshFragment.class, false)); 122 | classItems.add(new ClassItem(ClassItem.TYPE_FRAGMENT, "Optional", OptionalFragment.class, false)); 123 | classItems.add(new ClassItem(ClassItem.TYPE_FRAGMENT, "Checkable", CheckableFragment.class, false)); 124 | classItems.add(new ClassItem(ClassItem.TYPE_FRAGMENT, "BaseItemAdapter", BaseItemAdapterFragment.class, true)); 125 | classItems.add(new ClassItem(ClassItem.TYPE_FRAGMENT, "About", AboutFragment.class, false)); 126 | return classItems; 127 | } 128 | 129 | private void checkUpdate() { 130 | OkHttpClient client = new CustomHttpClient() 131 | .addHeader(new Pair<>("token", "")) 132 | .setConnectTimeout(5_000) 133 | .setShowLog(true) 134 | .createOkHttpClient(); 135 | Retrofit retrofit = new CustomRetrofit() 136 | //我在app的build.gradle文件的defaultConfig标签里定义了BASE_URL 137 | .setBaseUrl(BuildConfig.BASE_URL) 138 | .setOkHttpClient(client) 139 | .createRetrofit(); 140 | Disposable disposable = retrofit.create(ApiService.class) 141 | .getVersionInfo() 142 | .subscribeOn(Schedulers.io()) 143 | .observeOn(AndroidSchedulers.mainThread()) 144 | .subscribe(new Consumer() { 145 | @Override 146 | public void accept(String s) throws Exception { 147 | explainVersionInfoJson(s); 148 | } 149 | }, new Consumer() { 150 | @Override 151 | public void accept(Throwable throwable) throws Exception { 152 | showToast(throwable.getLocalizedMessage()); 153 | } 154 | }, new Action() { 155 | @Override 156 | public void run() throws Exception { 157 | 158 | } 159 | }); 160 | } 161 | 162 | private void explainVersionInfoJson(String json) { 163 | json = json.substring(1, json.length() - 1); 164 | try { 165 | JSONObject object = new JSONObject(json).getJSONObject("apkInfo"); 166 | int versionCode = object.getInt("versionCode"); 167 | String versionName = object.getString("versionName"); 168 | String fileName = object.getString("outputFile"); 169 | String content = object.getString("content"); 170 | 171 | PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_GIDS); 172 | long curVersionCode = packageInfo.versionCode; 173 | String curVersionName = packageInfo.versionName; 174 | 175 | Log.i("MainActivity", "explainVersionInfoJson: {versionCod" + versionCode + ", curVersionCode:" + curVersionCode); 176 | //a new version 177 | if (versionCode > curVersionCode) { 178 | sharedPreferences.edit().putLong("lastCheckUpdateTimeStamp", new Date().getTime()).apply(); 179 | showNewVersionDialog(String.format( 180 | Locale.CHINA, 181 | "当前版本:\u2000%1s\n" 182 | + "最新版本:\u2000%2s\n\n" 183 | + "更新内容:\n%3s" 184 | + "\n\n立即更新?", 185 | curVersionName, 186 | versionName, 187 | content 188 | ), fileName); 189 | } 190 | } catch (JSONException | PackageManager.NameNotFoundException e) { 191 | e.printStackTrace(); 192 | } 193 | } 194 | 195 | private void showNewVersionDialog(String content, final String fileName) { 196 | new AlertDialog.Builder(this) 197 | .setTitle("新版本提示") 198 | .setMessage(content) 199 | .setPositiveButton("更新", new DialogInterface.OnClickListener() { 200 | @Override 201 | public void onClick(DialogInterface dialog, int which) { 202 | String url = BuildConfig.BASE_URL + BuildConfig.DOWNLOAD_URL; 203 | Uri uri = Uri.parse(String.format(Locale.CHINA, url, fileName)); 204 | Intent intent = new Intent(Intent.ACTION_VIEW, uri); 205 | startActivity(intent); 206 | 207 | } 208 | }) 209 | .setNegativeButton("知道了", null) 210 | .show(); 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/bean/ClassItem.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter.bean; 2 | 3 | import android.support.annotation.IntDef; 4 | 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | 8 | public class ClassItem { 9 | public static final int TYPE_ACTIVITY = 0; 10 | public static final int TYPE_FRAGMENT = 1; 11 | @IntDef({TYPE_ACTIVITY, TYPE_FRAGMENT}) 12 | @Retention(RetentionPolicy.SOURCE) 13 | public @interface Type { 14 | } 15 | 16 | private String label; 17 | private Class clazz; 18 | private int type; 19 | private boolean updated; 20 | private boolean isLandscape; 21 | 22 | public ClassItem() { 23 | } 24 | 25 | public ClassItem(@Type int type, String label, Class clazz, boolean updated) { 26 | this(type, label, clazz, updated, false); 27 | } 28 | public ClassItem(@Type int type, String label, Class clazz, boolean updated, boolean isLandscape) { 29 | this.type = type; 30 | this.label = label; 31 | this.clazz = clazz; 32 | this.updated = updated; 33 | this.isLandscape = isLandscape; 34 | } 35 | 36 | public String getLabel() { 37 | return label; 38 | } 39 | 40 | public void setLabel(String label) { 41 | this.label = label; 42 | } 43 | 44 | public Class getClazz() { 45 | return clazz; 46 | } 47 | 48 | public void setClazz(Class clazz) { 49 | this.clazz = clazz; 50 | } 51 | 52 | public boolean isUpdated() { 53 | return updated; 54 | } 55 | 56 | public void setUpdated(boolean updated) { 57 | this.updated = updated; 58 | } 59 | 60 | public void setType(@Type int type) { 61 | this.type = type; 62 | } 63 | 64 | public int getType() { 65 | return type; 66 | } 67 | 68 | public boolean isLandscape() { 69 | return isLandscape; 70 | } 71 | 72 | public void setLandscape(boolean landscape) { 73 | isLandscape = landscape; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/bean/CustomBean.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter.bean; 2 | 3 | import jsc.kit.adapter.bean.SelectableBean; 4 | 5 | /** 6 | *
Email:1006368252@qq.com 7 | *
QQ:1006368252 8 | * create time: 2019/1/18 20:08 Friday 9 | * 10 | * @author jsc 11 | */ 12 | public class CustomBean extends SelectableBean { 13 | 14 | private String label; 15 | 16 | public CustomBean() { 17 | } 18 | 19 | public CustomBean(String label) { 20 | this.label = label; 21 | } 22 | 23 | public String getLabel() { 24 | return label; 25 | } 26 | 27 | public void setLabel(String label) { 28 | this.label = label; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/fragments/AboutFragment.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter.fragments; 2 | 3 | import android.content.Context; 4 | import android.content.DialogInterface; 5 | import android.content.Intent; 6 | import android.content.pm.PackageInfo; 7 | import android.content.pm.PackageManager; 8 | import android.net.Uri; 9 | import android.os.Bundle; 10 | import android.support.annotation.NonNull; 11 | import android.support.annotation.Nullable; 12 | import android.support.v7.app.AlertDialog; 13 | import android.util.Log; 14 | import android.util.Pair; 15 | import android.view.LayoutInflater; 16 | import android.view.View; 17 | import android.view.ViewGroup; 18 | import android.widget.TextView; 19 | import android.widget.Toast; 20 | 21 | import org.json.JSONException; 22 | import org.json.JSONObject; 23 | 24 | import java.util.Locale; 25 | 26 | import io.reactivex.android.schedulers.AndroidSchedulers; 27 | import io.reactivex.disposables.Disposable; 28 | import io.reactivex.functions.Action; 29 | import io.reactivex.functions.Consumer; 30 | import io.reactivex.schedulers.Schedulers; 31 | import jsc.exam.com.adapter.BuildConfig; 32 | import jsc.exam.com.adapter.R; 33 | import jsc.exam.com.adapter.retrofit.ApiService; 34 | import jsc.exam.com.adapter.retrofit.CustomHttpClient; 35 | import jsc.exam.com.adapter.retrofit.CustomRetrofit; 36 | import okhttp3.OkHttpClient; 37 | import retrofit2.Retrofit; 38 | 39 | /** 40 | *
Email:1006368252@qq.com 41 | *
QQ:1006368252 42 | * create time: 2019/1/2 11:43 43 | * 44 | * @author jsc 45 | */ 46 | public class AboutFragment extends BaseFragment { 47 | 48 | TextView tvVersion; 49 | TextView tvUpdateContent; 50 | TextView tvBuildTime; 51 | 52 | @Nullable 53 | @Override 54 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 55 | View root = inflater.inflate(R.layout.fragment_about, container, false); 56 | tvVersion = root.findViewById(R.id.tv_version); 57 | tvUpdateContent = root.findViewById(R.id.tv_update_content); 58 | tvBuildTime = root.findViewById(R.id.tv_build_time); 59 | root.findViewById(R.id.btn_check_update).setOnClickListener(new View.OnClickListener() { 60 | @Override 61 | public void onClick(View v) { 62 | v.setEnabled(false); 63 | checkUpdate(); 64 | } 65 | }); 66 | return root; 67 | } 68 | 69 | @Override 70 | void onLoadData(Context context) { 71 | loadLocalVersionInfo(context); 72 | } 73 | 74 | private void loadLocalVersionInfo(Context context) { 75 | try { 76 | PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_GIDS); 77 | tvVersion.setText(String.format(Locale.CHINA, "version:%s", packageInfo.versionName)); 78 | } catch (PackageManager.NameNotFoundException e) { 79 | e.printStackTrace(); 80 | } 81 | tvBuildTime.setText(String.format(Locale.CHINA, "build time:%s", BuildConfig.BUILD_TIME)); 82 | tvUpdateContent.setText("当前版本更新内容:" + getString(R.string.app_update_content)); 83 | } 84 | 85 | private void checkUpdate() { 86 | OkHttpClient client = new CustomHttpClient() 87 | .addHeader(new Pair<>("token", "")) 88 | .setConnectTimeout(5_000) 89 | .setShowLog(true) 90 | .createOkHttpClient(); 91 | Retrofit retrofit = new CustomRetrofit() 92 | //我在app的build.gradle文件的defaultConfig标签里定义了BASE_URL 93 | .setBaseUrl(BuildConfig.BASE_URL) 94 | .setOkHttpClient(client) 95 | .createRetrofit(); 96 | Disposable disposable = retrofit.create(ApiService.class) 97 | .getVersionInfo() 98 | .subscribeOn(Schedulers.io()) 99 | .observeOn(AndroidSchedulers.mainThread()) 100 | .subscribe(new Consumer() { 101 | @Override 102 | public void accept(String s) throws Exception { 103 | if (getView() != null) { 104 | getView().findViewById(R.id.btn_check_update).setEnabled(true); 105 | explainVersionInfoJson(s); 106 | } 107 | } 108 | }, new Consumer() { 109 | @Override 110 | public void accept(Throwable throwable) throws Exception { 111 | if (getView() != null) { 112 | Toast.makeText(getView().getContext(), throwable.getLocalizedMessage(), Toast.LENGTH_SHORT).show(); 113 | getView().findViewById(R.id.btn_check_update).setEnabled(true); 114 | } 115 | } 116 | }, new Action() { 117 | @Override 118 | public void run() throws Exception { 119 | if (getView() != null) { 120 | getView().findViewById(R.id.btn_check_update).setEnabled(true); 121 | } 122 | } 123 | }); 124 | } 125 | 126 | private void explainVersionInfoJson(String json) { 127 | json = json.substring(1, json.length() - 1); 128 | try { 129 | JSONObject object = new JSONObject(json).getJSONObject("apkInfo"); 130 | int versionCode = object.getInt("versionCode"); 131 | String versionName = object.getString("versionName"); 132 | String fileName = object.getString("outputFile"); 133 | String content = object.getString("content"); 134 | 135 | PackageInfo packageInfo = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), PackageManager.GET_GIDS); 136 | long curVersionCode = packageInfo.versionCode; 137 | String curVersionName = packageInfo.versionName; 138 | 139 | Log.i("MainActivity", "explainVersionInfoJson: {versionCod" + versionCode + ", curVersionCode:" + curVersionCode); 140 | //a new version 141 | if (versionCode > curVersionCode) { 142 | showNewVersionDialog(String.format( 143 | Locale.CHINA, 144 | "当前版本:\u2000%1s\n" 145 | + "最新版本:\u2000%2s\n\n" 146 | + "更新内容:\n%3s" 147 | + "\n立即更新?", 148 | curVersionName, 149 | versionName, 150 | content 151 | ), fileName); 152 | } else { 153 | Toast.makeText(getActivity(), "已是最新版本!", Toast.LENGTH_SHORT).show(); 154 | } 155 | } catch (JSONException | PackageManager.NameNotFoundException e) { 156 | e.printStackTrace(); 157 | } 158 | } 159 | 160 | private void showNewVersionDialog(String content, final String fileName) { 161 | if (getActivity() == null) 162 | return; 163 | 164 | new AlertDialog.Builder(getActivity()) 165 | .setTitle("新版本提示") 166 | .setMessage(content) 167 | .setPositiveButton("更新", new DialogInterface.OnClickListener() { 168 | @Override 169 | public void onClick(DialogInterface dialog, int which) { 170 | String url = BuildConfig.BASE_URL + BuildConfig.DOWNLOAD_URL; 171 | Uri uri = Uri.parse(String.format(Locale.CHINA, url, fileName)); 172 | Intent intent = new Intent(Intent.ACTION_VIEW, uri); 173 | startActivity(intent); 174 | 175 | } 176 | }) 177 | .setNegativeButton("知道了", null) 178 | .show(); 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/fragments/BaseFragment.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter.fragments; 2 | 3 | import android.content.Context; 4 | import android.support.v4.app.Fragment; 5 | 6 | public abstract class BaseFragment extends Fragment { 7 | 8 | private boolean isDataLoaded = false; 9 | 10 | abstract void onLoadData(Context context); 11 | 12 | @Override 13 | public void onResume() { 14 | super.onResume(); 15 | if (!isDataLoaded) { 16 | isDataLoaded = true; 17 | if (getActivity() != null) 18 | onLoadData(getActivity()); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/fragments/BaseItemAdapterFragment.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter.fragments; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.os.Bundle; 6 | import android.support.annotation.NonNull; 7 | import android.support.annotation.Nullable; 8 | import android.support.v7.widget.LinearLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.Toast; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | import jsc.exam.com.adapter.R; 19 | import jsc.exam.com.adapter.bean.CustomBean; 20 | import jsc.exam.com.adapter.utils.CompatResourceUtils; 21 | import jsc.kit.adapter.BaseItemAdapter; 22 | import jsc.kit.adapter.SimpleAdapter3; 23 | import jsc.kit.adapter.SimpleItemClickListener3; 24 | import jsc.kit.adapter.decoration.SpaceItemDecoration; 25 | 26 | /** 27 | * 快速实现复选示例 28 | *
Email:1006368252@qq.com 29 | *
QQ:1006368252 30 | * create time: 2019/1/3 10:31 Thursday 31 | * 32 | * @author jsc 33 | */ 34 | public class BaseItemAdapterFragment extends BaseFragment { 35 | 36 | BaseItemAdapter adapter = null; 37 | 38 | @Nullable 39 | @Override 40 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 41 | View root = inflater.inflate(R.layout.fragment_recycler_view, container, false); 42 | RecyclerView recyclerView = root.findViewById(R.id.recycler_view); 43 | recyclerView.setLayoutManager(new LinearLayoutManager(inflater.getContext())); 44 | recyclerView.addItemDecoration(new SpaceItemDecoration( 45 | CompatResourceUtils.getDimensionPixelSize(this, R.dimen.space_16), 46 | CompatResourceUtils.getDimensionPixelSize(this, R.dimen.space_2) 47 | )); 48 | adapter = new BaseItemAdapter(R.layout.checkable_list_item_layout) { 49 | @Override 50 | protected void onBindItemViewHolder(@NonNull BaseItemViewHolder holder, int position, CustomBean item) { 51 | holder.setText(R.id.tv_label, item.getLabel()) 52 | .setTextColor(R.id.tv_label, item.isSelected() ? Color.GREEN : 0xFF333333) 53 | .setSelected(R.id.iv_selected_state, item.isSelected()); 54 | } 55 | }; 56 | adapter.setOnCreateViewHolderListener(new BaseItemAdapter.OnCreateViewHolderListener() { 57 | @Override 58 | public View onCreateItemView(@NonNull ViewGroup viewGroup) { 59 | return null; 60 | } 61 | 62 | @Override 63 | public void afterCreateViewHolder(@NonNull BaseItemAdapter.BaseItemViewHolder holder) { 64 | holder.addClickListener(R.id.iv_selected_state); 65 | } 66 | }); 67 | adapter.setOnItemClickListener(new BaseItemAdapter.OnItemClickListener() { 68 | @Override 69 | public void onItemClick(@NonNull View itemView, int position, CustomBean item) { 70 | Toast.makeText(itemView.getContext(), "clicked item: " + item.getLabel(), Toast.LENGTH_SHORT).show(); 71 | } 72 | }); 73 | adapter.setOnItemChildClickListener(new BaseItemAdapter.OnItemChildClickListener() { 74 | @Override 75 | public void onItemChildClick(@NonNull View child, int position, CustomBean item) { 76 | item.setSelected(!item.isSelected()); 77 | adapter.notifyItemChanged(position); 78 | } 79 | }); 80 | adapter.bindRecyclerView(recyclerView); 81 | return root; 82 | } 83 | 84 | @Override 85 | void onLoadData(Context context) { 86 | loadNetData(); 87 | } 88 | 89 | private void loadNetData() { 90 | List items = new ArrayList<>(); 91 | for (int i = 0; i < 32; i++) { 92 | CustomBean item = new CustomBean(); 93 | item.setLabel("this is " + i); 94 | items.add(item); 95 | } 96 | adapter.setItems(items); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/fragments/CheckableFragment.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter.fragments; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.NonNull; 6 | import android.support.annotation.Nullable; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | import jsc.exam.com.adapter.R; 17 | import jsc.exam.com.adapter.bean.CustomBean; 18 | import jsc.exam.com.adapter.utils.CompatResourceUtils; 19 | import jsc.kit.adapter.SimpleAdapter3; 20 | import jsc.kit.adapter.SimpleItemClickListener3; 21 | import jsc.kit.adapter.decoration.SpaceItemDecoration; 22 | 23 | /** 24 | * 快速实现复选示例 25 | *
Email:1006368252@qq.com 26 | *
QQ:1006368252 27 | * create time: 2019/1/3 10:31 Thursday 28 | * 29 | * @author jsc 30 | */ 31 | public class CheckableFragment extends BaseFragment { 32 | 33 | SimpleAdapter3 adapter3 = null; 34 | 35 | @Nullable 36 | @Override 37 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 38 | View root = inflater.inflate(R.layout.fragment_recycler_view, container, false); 39 | RecyclerView recyclerView = root.findViewById(R.id.recycler_view); 40 | recyclerView.setLayoutManager(new LinearLayoutManager(inflater.getContext())); 41 | recyclerView.addItemDecoration(new SpaceItemDecoration( 42 | CompatResourceUtils.getDimensionPixelSize(this, R.dimen.space_16), 43 | CompatResourceUtils.getDimensionPixelSize(this, R.dimen.space_2) 44 | )); 45 | adapter3 = new SimpleAdapter3(R.layout.checkable_list_item_layout) { 46 | @Override 47 | protected void onBindDataViewHolder(@NonNull BaseViewHolder holder, int position, CustomBean dataBean) { 48 | holder.setText(R.id.tv_label, dataBean.getLabel()) 49 | .setSelected(R.id.iv_selected_state, dataBean.isSelected()); 50 | } 51 | }; 52 | adapter3.setOnItemClickListener(new SimpleItemClickListener3() { 53 | @Override 54 | public void onDataItemClick(@NonNull View dataItemView, int position, CustomBean dataBean) { 55 | dataBean.setSelected(!dataBean.isSelected()); 56 | adapter3.notifyItemChanged(position); 57 | } 58 | }); 59 | adapter3.bindRecyclerView(recyclerView); 60 | adapter3.addEmpty(new Object()); 61 | return root; 62 | } 63 | 64 | @Override 65 | void onLoadData(Context context) { 66 | loadNetData(); 67 | } 68 | 69 | private void loadNetData() { 70 | List items = new ArrayList<>(); 71 | for (int i = 0; i < 32; i++) { 72 | CustomBean item = new CustomBean(); 73 | item.setLabel("this is " + i); 74 | items.add(item); 75 | } 76 | adapter3.setData(items); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/fragments/OptionalFragment.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter.fragments; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.NonNull; 6 | import android.support.annotation.Nullable; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | import jsc.exam.com.adapter.R; 17 | import jsc.exam.com.adapter.bean.CustomBean; 18 | import jsc.exam.com.adapter.utils.CompatResourceUtils; 19 | import jsc.kit.adapter.SimpleAdapter3; 20 | import jsc.kit.adapter.SimpleItemClickListener3; 21 | import jsc.kit.adapter.decoration.SpaceItemDecoration; 22 | 23 | /** 24 | * 快速实现单选示例 25 | *
Email:1006368252@qq.com 26 | *
QQ:1006368252 27 | * create time: 2019/1/3 10:31 Thursday 28 | * 29 | * @author jsc 30 | */ 31 | public class OptionalFragment extends BaseFragment { 32 | 33 | SimpleAdapter3 adapter3 = null; 34 | int lastSelectedPosition = -1; 35 | 36 | @Nullable 37 | @Override 38 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 39 | View root = inflater.inflate(R.layout.fragment_recycler_view, container, false); 40 | RecyclerView recyclerView = root.findViewById(R.id.recycler_view); 41 | recyclerView.setLayoutManager(new LinearLayoutManager(inflater.getContext())); 42 | recyclerView.addItemDecoration(new SpaceItemDecoration( 43 | CompatResourceUtils.getDimensionPixelSize(this, R.dimen.space_16), 44 | CompatResourceUtils.getDimensionPixelSize(this, R.dimen.space_2) 45 | )); 46 | adapter3 = new SimpleAdapter3(R.layout.checkable_list_item_layout) { 47 | @Override 48 | protected void onBindDataViewHolder(@NonNull BaseViewHolder holder, int position, CustomBean dataBean) { 49 | holder.setText(R.id.tv_label, dataBean.getLabel()) 50 | .setSelected(R.id.iv_selected_state, dataBean.isSelected()); 51 | if (dataBean.isSelected()) 52 | lastSelectedPosition = position; 53 | } 54 | }; 55 | adapter3.setOnItemClickListener(new SimpleItemClickListener3() { 56 | @Override 57 | public void onDataItemClick(@NonNull View dataItemView, int position, CustomBean dataBean) { 58 | //实现单选 59 | updateSelected(position); 60 | } 61 | }); 62 | adapter3.bindRecyclerView(recyclerView); 63 | adapter3.addEmpty(new Object()); 64 | return root; 65 | } 66 | 67 | private void updateSelected(int position) { 68 | if (lastSelectedPosition == position) 69 | return; 70 | 71 | if (lastSelectedPosition >= 0) { 72 | adapter3.getDataAt(lastSelectedPosition).setSelected(false); 73 | adapter3.notifyItemChanged(lastSelectedPosition); 74 | } 75 | lastSelectedPosition = position; 76 | adapter3.getDataAt(lastSelectedPosition).setSelected(true); 77 | adapter3.notifyItemChanged(lastSelectedPosition); 78 | } 79 | 80 | @Override 81 | void onLoadData(Context context) { 82 | loadNetData(); 83 | } 84 | 85 | private void loadNetData() { 86 | List items = new ArrayList<>(); 87 | for (int i = 0; i < 32; i++) { 88 | CustomBean item = new CustomBean(); 89 | item.setLabel("this is " + i); 90 | items.add(item); 91 | } 92 | items.get(0).setSelected(true); 93 | adapter3.setData(items); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/fragments/PullToRefreshFragment.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter.fragments; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.NonNull; 6 | import android.support.annotation.Nullable; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.Toast; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import java.util.Random; 17 | 18 | import jsc.exam.com.adapter.R; 19 | import jsc.exam.com.adapter.bean.ClassItem; 20 | import jsc.exam.com.adapter.utils.CompatResourceUtils; 21 | import jsc.kit.adapter.SimpleAdapter2; 22 | import jsc.kit.adapter.SimpleItemClickListener2; 23 | import jsc.kit.adapter.refresh.PullToRefreshRecyclerView; 24 | import jsc.kit.adapter.decoration.SpaceItemDecoration; 25 | 26 | /** 27 | *
Email:1006368252@qq.com 28 | *
QQ:1006368252 29 | * create time: 2019/1/3 10:31 Thursday 30 | * 31 | * @author jsc 32 | */ 33 | public class PullToRefreshFragment extends BaseFragment { 34 | 35 | PullToRefreshRecyclerView pullToRefreshRecyclerView; 36 | SimpleAdapter2 adapter = null; 37 | 38 | @Nullable 39 | @Override 40 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 41 | View root = inflater.inflate(R.layout.fragment_pull_to_refresh, container, false); 42 | pullToRefreshRecyclerView = root.findViewById(R.id.pull_to_refresh_view); 43 | pullToRefreshRecyclerView.initializeParameters(1, 10); 44 | // pullToRefreshRecyclerView.setRefreshEnable(false); 45 | // pullToRefreshRecyclerView.setLoadMoreEnable(false); 46 | pullToRefreshRecyclerView.setOnRefreshListener(new PullToRefreshRecyclerView.OnRefreshListener() { 47 | @Override 48 | public void onRefresh(@NonNull Context context, int nextPage, int pageSize) { 49 | index = -1; 50 | loadNetData(); 51 | } 52 | 53 | @Override 54 | public void onLoadMore(@NonNull Context context, int nextPage, int pageSize) { 55 | loadNetData(); 56 | } 57 | }); 58 | RecyclerView recyclerView = pullToRefreshRecyclerView.getRecyclerView(); 59 | recyclerView.setLayoutManager(new LinearLayoutManager(inflater.getContext())); 60 | recyclerView.addItemDecoration(new SpaceItemDecoration( 61 | CompatResourceUtils.getDimensionPixelSize(this, R.dimen.space_16), 62 | CompatResourceUtils.getDimensionPixelSize(this, R.dimen.space_2) 63 | )); 64 | adapter = new SimpleAdapter2(R.layout.main_list_item_layout) { 65 | @Override 66 | protected void onBindDataViewHolder(@NonNull BaseViewHolder holder, int position, ClassItem dataBean) { 67 | holder.setText(R.id.tv_label, dataBean.getLabel()) 68 | .setVisibility(R.id.red_dot_view, View.GONE); 69 | } 70 | 71 | @Override 72 | protected void onBindFooterViewHolder(@NonNull BaseViewHolder holder, int position, String footerBean) { 73 | holder.setText(R.id.tv_footer, footerBean); 74 | } 75 | }; 76 | adapter.setOnItemClickListener(new SimpleItemClickListener2() { 77 | @Override 78 | public void onDataItemClick(@NonNull View dataItemView, int position, ClassItem dataBean) { 79 | Toast.makeText(dataItemView.getContext(), "clicked:" + dataBean.getLabel(), Toast.LENGTH_SHORT).show(); 80 | } 81 | 82 | @Override 83 | public void onEmptyItemClick(@NonNull View emptyItemView, int position, Object emptyBean) { 84 | pullToRefreshRecyclerView.refresh(); 85 | } 86 | }); 87 | adapter.setFooterLayoutId(R.layout.list_footer_layout); 88 | adapter.bindRecyclerView(recyclerView); 89 | adapter.addEmpty(new Object()); 90 | return root; 91 | } 92 | 93 | @Override 94 | void onLoadData(Context context) { 95 | // pullToRefreshRecyclerView.refreshDelay(300); 96 | // loadNetData(); 97 | } 98 | 99 | private int index = -1; 100 | private Random random = new Random(); 101 | 102 | private void loadNetData() { 103 | pullToRefreshRecyclerView.postDelayed(new Runnable() { 104 | @Override 105 | public void run() { 106 | pullToRefreshRecyclerView.completed(); 107 | List items = new ArrayList<>(); 108 | int count = 7 + random.nextInt(12); 109 | for (int i = 0; i < count; i++) { 110 | index++; 111 | ClassItem item = new ClassItem(); 112 | item.setLabel("this is " + index); 113 | items.add(item); 114 | } 115 | 116 | if (pullToRefreshRecyclerView.isFirstPage()) { 117 | adapter.removeFooter(0); 118 | adapter.setData(items); 119 | } else { 120 | adapter.addData(items); 121 | } 122 | boolean hasMore = items.size() >= pullToRefreshRecyclerView.getPageSize(); 123 | pullToRefreshRecyclerView.setHaveMore(hasMore); 124 | if (!hasMore) { 125 | adapter.addFooter("已全部加载"); 126 | } 127 | } 128 | }, 50 + random.nextInt(2000)); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/fragments/SimpleAdapterFragment.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter.fragments; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.NonNull; 6 | import android.support.annotation.Nullable; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.Toast; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | import jsc.exam.com.adapter.R; 18 | import jsc.exam.com.adapter.bean.CustomBean; 19 | import jsc.exam.com.adapter.utils.CompatResourceUtils; 20 | import jsc.kit.adapter.SimpleAdapter; 21 | import jsc.kit.adapter.SimpleItemChildClickListener; 22 | import jsc.kit.adapter.SimpleItemClickListener; 23 | import jsc.kit.adapter.decoration.SpaceItemDecoration; 24 | 25 | /** 26 | * 快速实现单选示例 27 | *
Email:1006368252@qq.com 28 | *
QQ:1006368252 29 | * create time: 2019/1/3 10:31 Thursday 30 | * 31 | * @author jsc 32 | */ 33 | public class SimpleAdapterFragment extends BaseFragment implements View.OnClickListener { 34 | 35 | SimpleAdapter adapter = null; 36 | 37 | @Nullable 38 | @Override 39 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 40 | View root = inflater.inflate(R.layout.fragment_simple_adapter, container, false); 41 | RecyclerView recyclerView = root.findViewById(R.id.recycler_view); 42 | root.findViewById(R.id.btn_add_header).setOnClickListener(this); 43 | root.findViewById(R.id.btn_remove_header).setOnClickListener(this); 44 | root.findViewById(R.id.btn_add_data_before).setOnClickListener(this); 45 | root.findViewById(R.id.btn_add_data).setOnClickListener(this); 46 | root.findViewById(R.id.btn_remove_data).setOnClickListener(this); 47 | recyclerView.setLayoutManager(new LinearLayoutManager(inflater.getContext())); 48 | recyclerView.addItemDecoration(new SpaceItemDecoration( 49 | 0, 50 | CompatResourceUtils.getDimensionPixelSize(this, R.dimen.space_2) 51 | )); 52 | adapter = new SimpleAdapter(R.layout.checkable_list_item_layout) { 53 | @Override 54 | protected void onBindHeaderViewHolder(@NonNull BaseViewHolder holder, int position, Object headerBean) { 55 | holder.setImageResource(R.id.iv_header, R.drawable.picture); 56 | addOnChildClickListener(holder, R.id.btn_header); 57 | } 58 | 59 | @Override 60 | protected void onBindDataViewHolder(@NonNull BaseViewHolder holder, int position, CustomBean dataBean) { 61 | holder.setText(R.id.tv_label, dataBean.getLabel()); 62 | } 63 | }; 64 | adapter.setOnItemClickListener(new SimpleItemClickListener() { 65 | @Override 66 | public void onDataItemClick(@NonNull View dataItemView, int position, CustomBean dataBean) { 67 | Toast.makeText(dataItemView.getContext(), "clicked:" + dataBean.getLabel(), Toast.LENGTH_SHORT).show(); 68 | } 69 | }); 70 | adapter.setOnItemChildClickListener(new SimpleItemChildClickListener() { 71 | @Override 72 | public void onHeaderItemChildClick(@NonNull View headerChild, int position, Object headerBean) { 73 | Toast.makeText(headerChild.getContext(), "clicked header:" + position, Toast.LENGTH_SHORT).show(); 74 | } 75 | }); 76 | adapter.setHeaderLayoutId(R.layout.list_header_layout); 77 | adapter.setFooterLayoutId(R.layout.list_footer_layout); 78 | adapter.bindRecyclerView(recyclerView); 79 | adapter.addEmpty(new Object()); 80 | return root; 81 | } 82 | 83 | @Override 84 | public void onClick(View v) { 85 | switch (v.getId()) { 86 | case R.id.btn_add_header: 87 | adapter.addHeader(new Object()); 88 | break; 89 | case R.id.btn_remove_header: 90 | adapter.removeHeader(adapter.getHeaderSize() - 1); 91 | break; 92 | case R.id.btn_add_data_before: 93 | indexBefore++; 94 | CustomBean item1 = new CustomBean(); 95 | item1.setLabel("data before " + indexBefore); 96 | adapter.addData(indexBefore, item1); 97 | break; 98 | case R.id.btn_add_data: 99 | index++; 100 | CustomBean item2 = new CustomBean(); 101 | item2.setLabel("this is " + index); 102 | adapter.addData(item2); 103 | break; 104 | case R.id.btn_remove_data: 105 | adapter.removeData(adapter.getDataSize() - 1); 106 | if (index >= 0) 107 | index--; 108 | else 109 | indexBefore--; 110 | break; 111 | } 112 | } 113 | 114 | @Override 115 | void onLoadData(Context context) { 116 | loadNetData(); 117 | } 118 | 119 | int index = -1; 120 | int indexBefore = -1; 121 | 122 | private void loadNetData() { 123 | List items = new ArrayList<>(); 124 | for (int i = 0; i < 4; i++) { 125 | index++; 126 | CustomBean item = new CustomBean(); 127 | item.setLabel("this is " + index); 128 | items.add(item); 129 | } 130 | adapter.setData(items); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/fragments/SwipeRefreshFragment.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter.fragments; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.NonNull; 6 | import android.support.annotation.Nullable; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.Toast; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | import java.util.Random; 16 | 17 | import jsc.exam.com.adapter.R; 18 | import jsc.exam.com.adapter.bean.ClassItem; 19 | import jsc.exam.com.adapter.utils.CompatResourceUtils; 20 | import jsc.kit.adapter.SimpleAdapter3; 21 | import jsc.kit.adapter.SimpleItemClickListener3; 22 | import jsc.kit.adapter.SimpleItemLongClickListener3; 23 | import jsc.kit.adapter.decoration.SpaceItemDecoration; 24 | import jsc.kit.adapter.refresh.SwipeRefreshRecyclerView; 25 | 26 | 27 | /** 28 | *
Email:1006368252@qq.com 29 | *
QQ:1006368252 30 | * create time: 2018/12/22 23:24 Saturday 31 | * 32 | * @author jsc 33 | */ 34 | public class SwipeRefreshFragment extends BaseFragment { 35 | 36 | SwipeRefreshRecyclerView swipeRefreshRecyclerView; 37 | SimpleAdapter3 adapter3; 38 | 39 | @Nullable 40 | @Override 41 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 42 | View root = inflater.inflate(R.layout.fragment_swipe_refresh, container, false); 43 | swipeRefreshRecyclerView = root.findViewById(R.id.swipe_refresh_view); 44 | swipeRefreshRecyclerView.setPageSize(12); 45 | swipeRefreshRecyclerView.getRecyclerView().setLayoutManager(new LinearLayoutManager(inflater.getContext())); 46 | swipeRefreshRecyclerView.getRecyclerView().addItemDecoration(new SpaceItemDecoration( 47 | CompatResourceUtils.getDimensionPixelSize(this, R.dimen.space_16), 48 | CompatResourceUtils.getDimensionPixelSize(this, R.dimen.space_2) 49 | )); 50 | swipeRefreshRecyclerView.setOnRefreshListener(new SwipeRefreshRecyclerView.OnRefreshListener() { 51 | @Override 52 | public void onRefresh(int currentPageNumber, int pageSize) { 53 | itemIndex = -1; 54 | loadData(); 55 | } 56 | 57 | @Override 58 | public void onLoadMore(int currentPageNumber, int pageSize) { 59 | loadData(); 60 | } 61 | }); 62 | adapter3 = new SimpleAdapter3() { 63 | @Override 64 | protected void onBindDataViewHolder(@NonNull BaseViewHolder holder, int position, ClassItem dataBean) { 65 | holder.setText(R.id.tv_label, dataBean.getLabel()); 66 | //给child添加点击事件 67 | // addOnChildClickListener(holder, R.id.tv_label); 68 | //给child添加长按事件 69 | // addOnChildLongClickListener(holder, R.id.tv_label); 70 | } 71 | }; 72 | adapter3.setOnItemClickListener(new SimpleItemClickListener3() { 73 | @Override 74 | public void onDataItemClick(@NonNull View dataItemView, int position, ClassItem dataBean) { 75 | Toast.makeText(dataItemView.getContext(), "clicked: " + dataBean.getLabel(), Toast.LENGTH_SHORT).show(); 76 | } 77 | 78 | @Override 79 | public void onEmptyItemClick(@NonNull View emptyItemView, int position, Object emptyBean) { 80 | swipeRefreshRecyclerView.refresh(); 81 | } 82 | }); 83 | adapter3.setOnItemLongClickListener(new SimpleItemLongClickListener3() { 84 | @Override 85 | public boolean onDataItemLongClick(@NonNull View dataItemView, int position, ClassItem dataBean) { 86 | Toast.makeText(dataItemView.getContext(), "long clicked:" + dataBean.getLabel(), Toast.LENGTH_SHORT).show(); 87 | return true; 88 | } 89 | }); 90 | adapter3.setDataLayoutId(R.layout.main_list_item_layout); 91 | adapter3.bindRecyclerView(swipeRefreshRecyclerView.getRecyclerView()); 92 | 93 | adapter3.addEmpty(new Object()); 94 | return root; 95 | } 96 | 97 | @Override 98 | void onLoadData(Context context) { 99 | // swipeRefreshRecyclerView.refresh(); 100 | } 101 | 102 | private void loadData() { 103 | swipeRefreshRecyclerView.postDelayed(new Runnable() { 104 | @Override 105 | public void run() { 106 | swipeRefreshRecyclerView.loadComplete(); 107 | List items = loadRandomData(); 108 | if (swipeRefreshRecyclerView.isFirstPage()) 109 | adapter3.setData(items); 110 | else 111 | adapter3.addData(items); 112 | swipeRefreshRecyclerView.setHasMorePage(items.size() >= 12); 113 | } 114 | }, new Random().nextInt(3000)); 115 | } 116 | 117 | private int itemIndex = -1; 118 | 119 | private List loadRandomData() { 120 | List items = new ArrayList<>(); 121 | int count = 8 + new Random().nextInt(16); 122 | for (int i = 0; i < count; i++) { 123 | itemIndex++; 124 | ClassItem item = new ClassItem(); 125 | item.setLabel("list item " + itemIndex); 126 | items.add(item); 127 | } 128 | return items; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/retrofit/ApiService.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter.retrofit; 2 | 3 | import io.reactivex.Observable; 4 | import jsc.exam.com.adapter.BuildConfig; 5 | import retrofit2.http.GET; 6 | 7 | public interface ApiService { 8 | 9 | @GET(BuildConfig.VERSION_URL) 10 | Observable getVersionInfo(); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/retrofit/CustomHttpClient.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter.retrofit; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import android.util.Pair; 6 | 7 | import java.io.File; 8 | import java.io.IOException; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | import io.reactivex.annotations.NonNull; 14 | import jsc.exam.com.adapter.utils.ConnectivityHelper; 15 | import okhttp3.Cache; 16 | import okhttp3.CacheControl; 17 | import okhttp3.Interceptor; 18 | import okhttp3.OkHttpClient; 19 | import okhttp3.Request; 20 | import okhttp3.Response; 21 | import okhttp3.logging.HttpLoggingInterceptor; 22 | 23 | /** 24 | *
Email:1006368252@qq.com 25 | *
QQ:1006368252 26 | * create time: 2019/1/2 11:44 27 | * 28 | * @author jsc 29 | */ 30 | public class CustomHttpClient { 31 | private boolean showLog = false; 32 | private int connectTimeout = 10_000; 33 | private int readTimeout = 10_000; 34 | private int writeTimeout = 10_000; 35 | private List> headers = null; 36 | private List interceptors = null; 37 | private Context context; 38 | private Cache cache; 39 | 40 | public CustomHttpClient setShowLog(boolean showLog) { 41 | this.showLog = showLog; 42 | return this; 43 | } 44 | 45 | public CustomHttpClient setConnectTimeout(int connectTimeout) { 46 | this.connectTimeout = connectTimeout; 47 | return this; 48 | } 49 | 50 | public CustomHttpClient setReadTimeout(int readTimeout) { 51 | this.readTimeout = readTimeout; 52 | return this; 53 | } 54 | 55 | public CustomHttpClient setWriteTimeout(int writeTimeout) { 56 | this.writeTimeout = writeTimeout; 57 | return this; 58 | } 59 | 60 | public CustomHttpClient addHeader(@NonNull Pair header) { 61 | if (headers == null) { 62 | headers = new ArrayList<>(); 63 | } 64 | headers.add(header); 65 | return this; 66 | } 67 | 68 | public CustomHttpClient addInterceptor(Interceptor interceptor) { 69 | if (interceptors == null) { 70 | interceptors = new ArrayList<>(); 71 | } 72 | interceptors.add(interceptor); 73 | return this; 74 | } 75 | 76 | 77 | public CustomHttpClient setContext(Application applicationContext) { 78 | this.context = applicationContext; 79 | return this; 80 | } 81 | 82 | /** 83 | * Set network cache config. 84 | * You must call method {@link #setContext(Application)} before calling this method. 85 | * 86 | * @param cacheFileName cache file name. 87 | * @param maxCacheSize cache max size. 88 | * @return CustomHttpClient 89 | */ 90 | public CustomHttpClient setCache(String cacheFileName, long maxCacheSize) { 91 | if (context != null){ 92 | File cacheFile = new File(context.getCacheDir(), cacheFileName); 93 | cache = new Cache(cacheFile, maxCacheSize); 94 | } 95 | return this; 96 | } 97 | 98 | public OkHttpClient createOkHttpClient() { 99 | OkHttpClient.Builder builder = new OkHttpClient.Builder(); 100 | builder.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS) 101 | .readTimeout(readTimeout, TimeUnit.MILLISECONDS) 102 | .writeTimeout(writeTimeout, TimeUnit.MILLISECONDS); 103 | //拦截服务器端的Log日志并打印,如果未debug状态就打印日志,否则就什么都不做 104 | builder.addInterceptor(new HttpLoggingInterceptor().setLevel(showLog ? HttpLoggingInterceptor.Level.BODY : HttpLoggingInterceptor.Level.NONE)); 105 | 106 | if (headers != null && !headers.isEmpty()) 107 | builder.addInterceptor(createHeaderInterceptor()); 108 | 109 | if (interceptors != null && !interceptors.isEmpty()) { 110 | for (Interceptor it : interceptors) { 111 | builder.addInterceptor(it); 112 | } 113 | } 114 | 115 | if (cache != null) { 116 | builder.cache(cache); 117 | builder.addNetworkInterceptor(createCacheInterceptor()); 118 | } 119 | return builder.build(); 120 | } 121 | 122 | private Interceptor createHeaderInterceptor() { 123 | return new Interceptor() { 124 | @Override 125 | public Response intercept(Chain chain) throws IOException { 126 | Request original = chain.request(); 127 | Request.Builder requestBuilder = original.newBuilder(); 128 | for (Pair header : headers) { 129 | requestBuilder.addHeader(header.first, header.second); 130 | } 131 | Request request = requestBuilder.build(); 132 | return chain.proceed(request); 133 | } 134 | }; 135 | } 136 | 137 | private Interceptor createCacheInterceptor() { 138 | return new Interceptor() { 139 | @Override 140 | public Response intercept(Chain chain) throws IOException { 141 | Request request = chain.request(); 142 | // Add FORCE_CACHE cache control for each request if network is not available. 143 | if (!ConnectivityHelper.isNetworkAvailable(context)) { 144 | request = request.newBuilder() 145 | .cacheControl(CacheControl.FORCE_CACHE) 146 | .build(); 147 | } 148 | 149 | Response originalResponse = chain.proceed(request); 150 | if (ConnectivityHelper.isNetworkAvailable(context)) { 151 | String cacheControl = request.cacheControl().toString(); 152 | // Add cache control header for response same as request's while network is available. 153 | return originalResponse.newBuilder() 154 | .header("Cache-Control", cacheControl) 155 | .build(); 156 | } else { 157 | // Add cache control header for response to FORCE_CACHE while network is not available. 158 | return originalResponse.newBuilder() 159 | .header("Cache-Control", CacheControl.FORCE_CACHE.toString()) 160 | .build(); 161 | } 162 | } 163 | }; 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/retrofit/CustomRetrofit.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter.retrofit; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import io.reactivex.annotations.NonNull; 7 | import okhttp3.OkHttpClient; 8 | import retrofit2.CallAdapter; 9 | import retrofit2.Converter; 10 | import retrofit2.Retrofit; 11 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; 12 | import retrofit2.converter.gson.GsonConverterFactory; 13 | import retrofit2.converter.scalars.ScalarsConverterFactory; 14 | 15 | /** 16 | *
Email:1006368252@qq.com 17 | *
QQ:1006368252 18 | * create time: 2019/1/2 11:44 19 | * 20 | * @author jsc 21 | */ 22 | public class CustomRetrofit { 23 | private String baseUrl; 24 | private OkHttpClient okHttpClient; 25 | private List converterFactories = new ArrayList<>(); 26 | private List callAdapterFactories = new ArrayList<>(); 27 | private boolean isDefaultFactoriesAdded = false; 28 | 29 | public CustomRetrofit setBaseUrl(@NonNull String baseUrl) { 30 | this.baseUrl = baseUrl; 31 | return this; 32 | } 33 | 34 | public CustomRetrofit setOkHttpClient(@NonNull OkHttpClient okHttpClient) { 35 | this.okHttpClient = okHttpClient; 36 | return this; 37 | } 38 | 39 | private CustomRetrofit addConverterFactory(@NonNull Converter.Factory factory){ 40 | checkIsDefaultFactoriesAdded(); 41 | converterFactories.add(factory); 42 | return this; 43 | } 44 | 45 | private CustomRetrofit addCallAdapterFactory(@NonNull CallAdapter.Factory factory){ 46 | checkIsDefaultFactoriesAdded(); 47 | callAdapterFactories.add(factory); 48 | return this; 49 | } 50 | 51 | public Retrofit createRetrofit() { 52 | if (baseUrl == null || baseUrl.trim().length() == 0) 53 | throw new IllegalArgumentException("Base url can't be null."); 54 | 55 | if (okHttpClient == null) 56 | throw new IllegalArgumentException("You have not initialized OkHttpClient."); 57 | 58 | Retrofit.Builder builder = new Retrofit.Builder(); 59 | builder.baseUrl(baseUrl).client(okHttpClient); 60 | checkIsDefaultFactoriesAdded(); 61 | for (Converter.Factory factory : converterFactories) { 62 | builder.addConverterFactory(factory); 63 | } 64 | for (CallAdapter.Factory factory : callAdapterFactories) { 65 | builder.addCallAdapterFactory(factory); 66 | } 67 | return builder.build(); 68 | } 69 | 70 | private void checkIsDefaultFactoriesAdded(){ 71 | if (isDefaultFactoriesAdded) 72 | return; 73 | 74 | //增加返回值为String的支持 75 | converterFactories.add(ScalarsConverterFactory.create()); 76 | //增加返回值为Gson的支持(以实体类返回) 77 | converterFactories.add(GsonConverterFactory.create()); 78 | //增加返回值为Oservable的支持 79 | callAdapterFactories.add(RxJava2CallAdapterFactory.create()); 80 | isDefaultFactoriesAdded = true; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/retrofit/LoadingDialogObserver.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter.retrofit; 2 | 3 | import android.app.Dialog; 4 | import android.content.DialogInterface; 5 | import android.os.Handler; 6 | import android.os.Looper; 7 | import android.os.Message; 8 | 9 | import io.reactivex.Observer; 10 | import io.reactivex.disposables.Disposable; 11 | 12 | /** 13 | *
Email:1006368252@qq.com 14 | *
QQ:1006368252 15 | * create time: 2019/1/2 11:44 16 | * 17 | * @author jsc 18 | */ 19 | public abstract class LoadingDialogObserver implements Observer, DialogInterface.OnCancelListener { 20 | 21 | private final int SHOW_DIALOG = 0x6990; 22 | private final int HIDE_DIALOG = 0x6991; 23 | private Dialog loadingDialog; 24 | private boolean ifShowDialog; 25 | private Handler handler = new Handler(Looper.getMainLooper(), new Handler.Callback() { 26 | @Override 27 | public boolean handleMessage(Message message) { 28 | switch (message.what) { 29 | case SHOW_DIALOG: 30 | if (loadingDialog != null && !loadingDialog.isShowing()) 31 | loadingDialog.show(); 32 | break; 33 | case HIDE_DIALOG: 34 | if (loadingDialog != null && loadingDialog.isShowing()) 35 | loadingDialog.dismiss(); 36 | break; 37 | } 38 | return true; 39 | } 40 | }); 41 | private Disposable disposable; 42 | 43 | /** 44 | * Constructor. 45 | */ 46 | public LoadingDialogObserver() { 47 | this(null); 48 | } 49 | 50 | /** 51 | * Constructor. 52 | * @param loadingDialog loading dialog 53 | */ 54 | public LoadingDialogObserver(Dialog loadingDialog) { 55 | this(loadingDialog, true); 56 | } 57 | 58 | /** 59 | * Constructor. 60 | * 61 | * @param loadingDialog loading dialog 62 | * @param ifShowDialog Show loadingDialog if true else not. 63 | */ 64 | public LoadingDialogObserver(Dialog loadingDialog, boolean ifShowDialog) { 65 | this.loadingDialog = loadingDialog; 66 | this.ifShowDialog = ifShowDialog; 67 | if (loadingDialog != null) 68 | loadingDialog.setOnCancelListener(this); 69 | } 70 | 71 | @Override 72 | public void onSubscribe(Disposable d) { 73 | disposable = d; 74 | if (ifShowDialog) 75 | handler.sendEmptyMessage(SHOW_DIALOG); 76 | onStart(d); 77 | } 78 | 79 | @Override 80 | public void onNext(T t) { 81 | try { 82 | onResult(t); 83 | } catch (Exception e){ 84 | onError(e); 85 | } 86 | } 87 | 88 | @Override 89 | public void onError(Throwable e) { 90 | if (ifShowDialog) 91 | handler.sendEmptyMessage(HIDE_DIALOG); 92 | onException(e); 93 | onCompleteOrCancel(disposable); 94 | } 95 | 96 | @Override 97 | public void onComplete() { 98 | if (ifShowDialog) 99 | handler.sendEmptyMessage(HIDE_DIALOG); 100 | onCompleteOrCancel(disposable); 101 | } 102 | 103 | @Override 104 | public void onCancel(DialogInterface dialog) { 105 | disposable.dispose(); 106 | onCompleteOrCancel(disposable); 107 | } 108 | 109 | /** 110 | * Show loading dialog here if necessary. 111 | * @param disposable disposable, the same as the return of {@link io.reactivex.Observable#subscribe(Observer)}. 112 | */ 113 | public abstract void onStart(Disposable disposable); 114 | 115 | /** 116 | * Call back the response. 117 | * @param t response 118 | */ 119 | public abstract void onResult(T t); 120 | 121 | /** 122 | * Call back when a exception appears. 123 | * @param e exception 124 | */ 125 | public abstract void onException(Throwable e); 126 | 127 | /** 128 | * Call back when {@link Observer#onComplete()} or loading dialog is canceled. 129 | * @param disposable disposable, the same as the return of {@link io.reactivex.Observable#subscribe(Observer)}. 130 | */ 131 | public abstract void onCompleteOrCancel(Disposable disposable); 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/utils/CompatResourceUtils.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter.utils; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.Drawable; 5 | import android.support.annotation.ColorRes; 6 | import android.support.annotation.DimenRes; 7 | import android.support.annotation.DrawableRes; 8 | import android.support.annotation.NonNull; 9 | import android.support.v4.app.Fragment; 10 | import android.util.TypedValue; 11 | import android.view.View; 12 | 13 | /** 14 | *
Email:1006368252@qq.com 15 | *
QQ:1006368252 16 | * create time: 2019/1/2 11:44 17 | * 18 | * @author jsc 19 | */ 20 | public class CompatResourceUtils { 21 | 22 | //color 23 | public static int getColor(@NonNull Context context, @ColorRes int resId){ 24 | int color; 25 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M){ 26 | color = context.getResources().getColor(resId, context.getTheme()); 27 | } else { 28 | color = context.getResources().getColor(resId); 29 | } 30 | return color; 31 | } 32 | 33 | //drawable-xxhdpi 34 | public static Drawable getDrawable(@NonNull Context context, @DrawableRes int resId){ 35 | Drawable drawable; 36 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M){ 37 | drawable = context.getResources().getDrawable(resId, context.getTheme()); 38 | } else { 39 | drawable = context.getResources().getDrawable(resId); 40 | } 41 | return drawable; 42 | } 43 | 44 | //dimension 45 | public static int getDimensionPixelSize(@NonNull Context context, @DimenRes int id){ 46 | return context.getResources().getDimensionPixelSize(id); 47 | } 48 | 49 | public static int getDimensionPixelSize(@NonNull View view, @DimenRes int id){ 50 | return view.getResources().getDimensionPixelSize(id); 51 | } 52 | 53 | public static int getDimensionPixelSize(@NonNull Fragment fragment, @DimenRes int id){ 54 | return fragment.getResources().getDimensionPixelSize(id); 55 | } 56 | 57 | public static int dp2Px(@NonNull Context context, float dp){ 58 | return (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics()) + .5f); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/utils/ConnectivityHelper.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter.utils; 2 | 3 | import android.content.Context; 4 | import android.net.ConnectivityManager; 5 | import android.net.NetworkInfo; 6 | 7 | import java.util.Objects; 8 | 9 | /** 10 | * 11 | * ConnectivityHelper 网络工具 12 | * 13 | * 14 | */ 15 | public class ConnectivityHelper { 16 | 17 | public static boolean isNetworkAvailable(Context context) { 18 | ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 19 | Objects.requireNonNull(cm); 20 | NetworkInfo networkInfo = cm.getActiveNetworkInfo(); 21 | return networkInfo != null && networkInfo.isAvailable(); 22 | } 23 | 24 | /** 25 | * 判断网络是否可用 26 | * 27 | * @param context context 28 | * @return boolean 29 | */ 30 | public static boolean isConnectivityAvailable(Context context) { 31 | // 判断网络是否可用 32 | ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 33 | Objects.requireNonNull(cm); 34 | NetworkInfo info = cm.getActiveNetworkInfo(); 35 | if (info == null || !info.isConnected()) { 36 | return false; 37 | } 38 | return info.isAvailable() || info.isRoaming(); 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/utils/WindowUtils.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter.utils; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.drawable.Drawable; 6 | import android.support.annotation.NonNull; 7 | import android.util.TypedValue; 8 | 9 | /** 10 | *
Email:1006368252@qq.com 11 | *
QQ:1006368252 12 | * create time: 2019/1/2 11:45 13 | * 14 | * @author jsc 15 | */ 16 | public final class WindowUtils { 17 | 18 | /** 19 | * Get status bar height. 20 | * 21 | * @param context context 22 | * @return the height of status bar 23 | */ 24 | public static int getStatusBarHeight(@NonNull Context context) { 25 | int statusBarHeight = 0; 26 | int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); 27 | if (resourceId > 0) { 28 | statusBarHeight = CompatResourceUtils.getDimensionPixelSize(context, resourceId); 29 | } 30 | return statusBarHeight; 31 | } 32 | 33 | /** 34 | * Get action bar height. 35 | * 36 | * @param context context 37 | * @return the height of action bar 38 | */ 39 | public static int getActionBarSize(@NonNull Context context) { 40 | TypedValue typedValue = new TypedValue(); 41 | int[] attribute = new int[]{android.R.attr.actionBarSize}; 42 | TypedArray array = context.obtainStyledAttributes(typedValue.resourceId, attribute); 43 | int actionBarSize = array.getDimensionPixelSize(0, 0); 44 | array.recycle(); 45 | return actionBarSize; 46 | } 47 | 48 | /** 49 | * Get system selectable item background borderless. 50 | * @param context context 51 | * @return selectable item background borderless 52 | */ 53 | public static Drawable getSelectableItemBackgroundBorderless(Context context){ 54 | TypedValue typedValue = new TypedValue(); 55 | context.getTheme().resolveAttribute(android.R.attr.selectableItemBackgroundBorderless, typedValue, true); 56 | int[] attribute = new int[]{android.R.attr.selectableItemBackgroundBorderless}; 57 | TypedArray typedArray = context.obtainStyledAttributes(typedValue.resourceId, attribute); 58 | Drawable drawable = typedArray.getDrawable(0); 59 | typedArray.recycle(); 60 | return drawable; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/widgets/FiveTwoImageView.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter.widgets; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.AppCompatImageView; 5 | import android.util.AttributeSet; 6 | 7 | public class FiveTwoImageView extends AppCompatImageView { 8 | public FiveTwoImageView(Context context) { 9 | super(context); 10 | } 11 | 12 | public FiveTwoImageView(Context context, AttributeSet attrs) { 13 | super(context, attrs); 14 | } 15 | 16 | public FiveTwoImageView(Context context, AttributeSet attrs, int defStyleAttr) { 17 | super(context, attrs, defStyleAttr); 18 | } 19 | 20 | @Override 21 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 22 | setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec)); 23 | int width = getMeasuredWidth(); 24 | heightMeasureSpec = MeasureSpec.makeMeasureSpec(width * 2 / 5, MeasureSpec.EXACTLY); 25 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/jsc/exam/com/adapter/widgets/SquareImageView.java: -------------------------------------------------------------------------------- 1 | package jsc.exam.com.adapter.widgets; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.AppCompatImageView; 5 | import android.util.AttributeSet; 6 | 7 | public class SquareImageView extends AppCompatImageView { 8 | public SquareImageView(Context context) { 9 | super(context); 10 | } 11 | 12 | public SquareImageView(Context context, AttributeSet attrs) { 13 | super(context, attrs); 14 | } 15 | 16 | public SquareImageView(Context context, AttributeSet attrs, int defStyleAttr) { 17 | super(context, attrs, defStyleAttr); 18 | } 19 | 20 | @Override 21 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 22 | super.onMeasure(widthMeasureSpec, widthMeasureSpec); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ripple_round_corner_white_r4.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/btn_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinRoom/SimpleAdapterDemo/739e75fc2bcaccdd5d323e717a1021cf4d907b63/app/src/main/res/drawable-xxhdpi/btn_background.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_chevron_left_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinRoom/SimpleAdapterDemo/739e75fc2bcaccdd5d323e717a1021cf4d907b63/app/src/main/res/drawable-xxhdpi/ic_chevron_left_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ico_checkable_nor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinRoom/SimpleAdapterDemo/739e75fc2bcaccdd5d323e717a1021cf4d907b63/app/src/main/res/drawable-xxhdpi/ico_checkable_nor.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ico_checkable_press.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinRoom/SimpleAdapterDemo/739e75fc2bcaccdd5d323e717a1021cf4d907b63/app/src/main/res/drawable-xxhdpi/ico_checkable_press.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/kit_ic_assignment_blue_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinRoom/SimpleAdapterDemo/739e75fc2bcaccdd5d323e717a1021cf4d907b63/app/src/main/res/drawable-xxhdpi/kit_ic_assignment_blue_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/kit_ic_chevron_right_gray_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinRoom/SimpleAdapterDemo/739e75fc2bcaccdd5d323e717a1021cf4d907b63/app/src/main/res/drawable-xxhdpi/kit_ic_chevron_right_gray_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/picture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinRoom/SimpleAdapterDemo/739e75fc2bcaccdd5d323e717a1021cf4d907b63/app/src/main/res/drawable-xxhdpi/picture.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/button_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/head.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinRoom/SimpleAdapterDemo/739e75fc2bcaccdd5d323e717a1021cf4d907b63/app/src/main/res/drawable/head.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ico_checkable_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/red_dot_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ripple_round_corner_white_r4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/simple_adapter_qr_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinRoom/SimpleAdapterDemo/739e75fc2bcaccdd5d323e717a1021cf4d907b63/app/src/main/res/drawable/simple_adapter_qr_code.png -------------------------------------------------------------------------------- /app/src/main/res/layout/checkable_list_item_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 17 | 18 | 26 | 27 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_about.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 17 | 18 | 22 | 23 | 31 | 32 | 40 | 41 | 49 | 50 | 51 | 52 | 57 | 58 |