Repository: monkeywiiu/Discover Branch: master Commit: 7835a194633b Files: 303 Total size: 770.0 KB Directory structure: gitextract_y2efyqy7/ ├── .gitignore ├── .idea/ │ ├── compiler.xml │ ├── copyright/ │ │ └── profiles_settings.xml │ ├── inspectionProfiles/ │ │ └── Project_Default.xml │ ├── misc.xml │ ├── modules.xml │ ├── runConfigurations.xml │ └── vcs.xml ├── LICENSE ├── README.md ├── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── example/ │ │ └── discover/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── assets/ │ │ │ └── litepal.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── discover/ │ │ │ ├── AuthorHomeActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── ResultActivity.java │ │ │ ├── SearchActivity.java │ │ │ ├── TestActivity.java │ │ │ ├── VideoDetailActivity.java │ │ │ ├── ViewBigImageActivity.java │ │ │ ├── adapter/ │ │ │ │ ├── AuthorPopAdapter.java │ │ │ │ ├── CategoryPopAdapter.java │ │ │ │ ├── FollowRecyclerAdapter.java │ │ │ │ ├── ItemHelper.java │ │ │ │ ├── LabelChooseAdapter.java │ │ │ │ ├── LikeVideoRecyclerAdapter.java │ │ │ │ ├── MyFragmentPagerAdapter.java │ │ │ │ ├── PopReplyAdapter.java │ │ │ │ ├── ReplyAdapter.java │ │ │ │ ├── ResultAdapter.java │ │ │ │ ├── SearchRecyclerAdapter.java │ │ │ │ ├── SearchTagAdapter.java │ │ │ │ ├── SelectTypeRecyclerAdapter.java │ │ │ │ ├── VideoRecyclerAdapter.java │ │ │ │ └── WelfareAdapter.java │ │ │ ├── app/ │ │ │ │ ├── Constant.java │ │ │ │ └── DiscoverApplication.java │ │ │ ├── base/ │ │ │ │ ├── BaseFragment.java │ │ │ │ └── baseadapter/ │ │ │ │ ├── BaseRecyclerAdapter.java │ │ │ │ ├── BaseViewHolder.java │ │ │ │ ├── OnItemClickListener.java │ │ │ │ └── OnItemLongClickListener.java │ │ │ ├── bean/ │ │ │ │ ├── AuthorDetailBean.java │ │ │ │ ├── DetailBean/ │ │ │ │ │ ├── ACacheFindList.java │ │ │ │ │ ├── Author.java │ │ │ │ │ ├── CategoryInfo.java │ │ │ │ │ ├── Cover.java │ │ │ │ │ ├── Data.java │ │ │ │ │ ├── FindCategory.java │ │ │ │ │ ├── Footer.java │ │ │ │ │ ├── Header.java │ │ │ │ │ ├── ItemList.java │ │ │ │ │ ├── PlayInfo.java │ │ │ │ │ ├── Replies.java │ │ │ │ │ ├── ReplyList.java │ │ │ │ │ ├── SectionList.java │ │ │ │ │ ├── Tags.java │ │ │ │ │ ├── UrlList.java │ │ │ │ │ ├── User.java │ │ │ │ │ └── WebUrl.java │ │ │ │ ├── GankBean.java │ │ │ │ ├── HotEyeBean.java │ │ │ │ ├── LitePalBean/ │ │ │ │ │ ├── Follow.java │ │ │ │ │ ├── LabelType.java │ │ │ │ │ ├── LikeVideo.java │ │ │ │ │ └── SearchTag.java │ │ │ │ ├── ResultBean.java │ │ │ │ └── TestBean.java │ │ │ ├── http/ │ │ │ │ ├── HttpClient.java │ │ │ │ ├── RequestListener.java │ │ │ │ └── cahe/ │ │ │ │ └── ACache.java │ │ │ ├── model/ │ │ │ │ ├── AuthorVideoModel.java │ │ │ │ ├── GankModel.java │ │ │ │ ├── HotVideoModel.java │ │ │ │ ├── ReplyModel.java │ │ │ │ └── SearchModel.java │ │ │ ├── ui/ │ │ │ │ ├── DiscoverFragment.java │ │ │ │ ├── Personal/ │ │ │ │ │ ├── PersonalFragment.java │ │ │ │ │ └── child/ │ │ │ │ │ ├── FollowFragment.java │ │ │ │ │ └── LikeFragment.java │ │ │ │ ├── RecyclerViewNoBugLinearLayoutManager.java │ │ │ │ ├── Search/ │ │ │ │ │ ├── Author/ │ │ │ │ │ │ └── ItemFragment.java │ │ │ │ │ └── SearchFragment.java │ │ │ │ ├── Video/ │ │ │ │ │ └── VideoFragment.java │ │ │ │ └── Welfare/ │ │ │ │ └── WelFareFragment.java │ │ │ ├── utils/ │ │ │ │ ├── BindingUtil.java │ │ │ │ ├── DebugUtil.java │ │ │ │ ├── DensityUtil.java │ │ │ │ ├── IntentManager.java │ │ │ │ ├── LitePalUtil.java │ │ │ │ ├── ShareUtil.java │ │ │ │ └── TimeUtils.java │ │ │ └── view/ │ │ │ ├── CustomView/ │ │ │ │ ├── CategoryPopupWindow.java │ │ │ │ ├── CircleImageView.java │ │ │ │ ├── DragFrameLayout.java │ │ │ │ ├── FollowPopupWindow.java │ │ │ │ ├── HackyViewPager.java │ │ │ │ ├── LabelView.java │ │ │ │ └── ReplyPopupWindow.java │ │ │ └── test.java │ │ └── res/ │ │ ├── anim/ │ │ │ ├── fade_in_bottom.xml │ │ │ ├── fade_in_lt.xml │ │ │ ├── fade_in_rt.xml │ │ │ ├── fade_out_lb.xml │ │ │ ├── fade_out_rb.xml │ │ │ └── fade_out_top.xml │ │ ├── drawable/ │ │ │ ├── bg_save_big_image.xml │ │ │ ├── corner_view.xml │ │ │ ├── ic_arrow_back_white_24px.xml │ │ │ ├── ic_clear_black_24px.xml │ │ │ ├── ic_heart_full_24dp_pink.xml │ │ │ ├── ic_heart_hollow_24dp.xml │ │ │ ├── item_figure.xml │ │ │ ├── item_home.xml │ │ │ ├── item_search.xml │ │ │ └── item_smile.xml │ │ ├── layout/ │ │ │ ├── activity_author_home.xml │ │ │ ├── activity_main.xml │ │ │ ├── activity_result.xml │ │ │ ├── activity_search.xml │ │ │ ├── activity_test.xml │ │ │ ├── activity_video_detail.xml │ │ │ ├── activity_view_big_image.xml │ │ │ ├── author_card.xml │ │ │ ├── bottom_bar.xml │ │ │ ├── category_card.xml │ │ │ ├── category_popup_window.xml │ │ │ ├── follow_popup.xml │ │ │ ├── footer_item_video.xml │ │ │ ├── fragment_base.xml │ │ │ ├── fragment_discover.xml │ │ │ ├── fragment_follow.xml │ │ │ ├── fragment_personal.xml │ │ │ ├── fragment_personal_like.xml │ │ │ ├── fragment_search.xml │ │ │ ├── fragment_video.xml │ │ │ ├── fragment_welfare.xml │ │ │ ├── item_follow.xml │ │ │ ├── item_movie_detail_header.xml │ │ │ ├── item_reply.xml │ │ │ ├── item_welfare.xml │ │ │ ├── label_view.xml │ │ │ ├── like_video_card.xml │ │ │ ├── null_layout.xml │ │ │ ├── recommend_author.xml │ │ │ ├── recommend_category.xml │ │ │ ├── reply_popup_window.xml │ │ │ ├── search_tag.xml │ │ │ ├── select_label_view.xml │ │ │ ├── tag_header_new.xml │ │ │ ├── tag_header_reco.xml │ │ │ ├── test.xml │ │ │ ├── test_cardview.xml │ │ │ ├── video_card.xml │ │ │ └── viewpager_very_image.xml │ │ ├── values/ │ │ │ ├── attrs.xml │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── values-v21/ │ │ ├── dimens.xml │ │ └── styles.xml │ └── test/ │ └── java/ │ └── com/ │ └── example/ │ └── discover/ │ └── ExampleUnitTest.java ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── librarys/ │ ├── http/ │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src/ │ │ ├── androidTest/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── http/ │ │ │ └── ExampleInstrumentedTest.java │ │ ├── main/ │ │ │ ├── AndroidManifest.xml │ │ │ ├── java/ │ │ │ │ └── com/ │ │ │ │ └── example/ │ │ │ │ └── http/ │ │ │ │ └── HttpUtils.java │ │ │ └── res/ │ │ │ └── values/ │ │ │ └── strings.xml │ │ └── test/ │ │ └── java/ │ │ └── com/ │ │ └── example/ │ │ └── http/ │ │ └── ExampleUnitTest.java │ ├── jiaozivideoplayer/ │ │ ├── .idea/ │ │ │ ├── compiler.xml │ │ │ ├── copyright/ │ │ │ │ └── profiles_settings.xml │ │ │ ├── gradle.xml │ │ │ ├── misc.xml │ │ │ ├── modules.xml │ │ │ ├── runConfigurations.xml │ │ │ └── workspace.xml │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src/ │ │ ├── androidTest/ │ │ │ └── java/ │ │ │ └── cn/ │ │ │ └── jzvd/ │ │ │ └── ApplicationTest.java │ │ ├── main/ │ │ │ ├── AndroidManifest.xml │ │ │ ├── java/ │ │ │ │ └── cn/ │ │ │ │ └── jzvd/ │ │ │ │ ├── JZMediaInterface.java │ │ │ │ ├── JZMediaManager.java │ │ │ │ ├── JZMediaSystem.java │ │ │ │ ├── JZResizeTextureView.java │ │ │ │ ├── JZUserAction.java │ │ │ │ ├── JZUserActionStandard.java │ │ │ │ ├── JZUtils.java │ │ │ │ ├── JZVideoPlayer.java │ │ │ │ ├── JZVideoPlayerManager.java │ │ │ │ └── JZVideoPlayerStandard.java │ │ │ └── res/ │ │ │ ├── anim/ │ │ │ │ ├── quit_fullscreen.xml │ │ │ │ └── start_fullscreen.xml │ │ │ ├── drawable/ │ │ │ │ ├── jz_bottom_progress.xml │ │ │ │ ├── jz_bottom_seek_progress.xml │ │ │ │ ├── jz_bottom_seek_thumb.xml │ │ │ │ ├── jz_click_back_selector.xml │ │ │ │ ├── jz_click_back_tiny_selector.xml │ │ │ │ ├── jz_click_pause_selector.xml │ │ │ │ ├── jz_click_play_selector.xml │ │ │ │ ├── jz_click_replay_selector.xml │ │ │ │ ├── jz_click_share_selector.xml │ │ │ │ ├── jz_dialog_progress.xml │ │ │ │ ├── jz_dialog_progress_bg.xml │ │ │ │ ├── jz_loading.xml │ │ │ │ ├── jz_seek_thumb_normal.xml │ │ │ │ ├── jz_seek_thumb_pressed.xml │ │ │ │ ├── jz_volume_progress_bg.xml │ │ │ │ └── retry_bg.xml │ │ │ ├── layout/ │ │ │ │ ├── jz_dialog_brightness.xml │ │ │ │ ├── jz_dialog_progress.xml │ │ │ │ ├── jz_dialog_volume.xml │ │ │ │ ├── jz_layout_clarity.xml │ │ │ │ ├── jz_layout_clarity_item.xml │ │ │ │ └── jz_layout_standard.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ ├── values-es/ │ │ │ │ └── strings.xml │ │ │ ├── values-pt/ │ │ │ │ └── strings.xml │ │ │ ├── values-tr/ │ │ │ │ └── strings.xml │ │ │ └── values-zh/ │ │ │ └── strings.xml │ │ └── test/ │ │ └── java/ │ │ └── cn/ │ │ └── jzvd/ │ │ └── ExampleUnitTest.java │ ├── xrecyclerview/ │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src/ │ │ ├── androidTest/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── jcodecraeer/ │ │ │ └── xrecyclerview/ │ │ │ └── ApplicationTest.java │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── jcodecraeer/ │ │ │ └── xrecyclerview/ │ │ │ ├── AppBarStateChangeListener.java │ │ │ ├── ArrowRefreshHeader.java │ │ │ ├── BaseRefreshHeader.java │ │ │ ├── CustomFooterViewCallBack.java │ │ │ ├── ItemTouchHelperAdapter.java │ │ │ ├── JellyView.java │ │ │ ├── LoadingMoreFooter.java │ │ │ ├── ProgressStyle.java │ │ │ ├── SimpleItemTouchHelperCallback.java │ │ │ ├── SimpleViewSwitcher.java │ │ │ ├── XRecyclerView.java │ │ │ └── progressindicator/ │ │ │ ├── AVLoadingIndicatorView.java │ │ │ └── indicator/ │ │ │ ├── BallBeatIndicator.java │ │ │ ├── BallClipRotateIndicator.java │ │ │ ├── BallClipRotateMultipleIndicator.java │ │ │ ├── BallClipRotatePulseIndicator.java │ │ │ ├── BallGridBeatIndicator.java │ │ │ ├── BallGridPulseIndicator.java │ │ │ ├── BallPulseIndicator.java │ │ │ ├── BallPulseRiseIndicator.java │ │ │ ├── BallPulseSyncIndicator.java │ │ │ ├── BallRotateIndicator.java │ │ │ ├── BallScaleIndicator.java │ │ │ ├── BallScaleMultipleIndicator.java │ │ │ ├── BallScaleRippleIndicator.java │ │ │ ├── BallScaleRippleMultipleIndicator.java │ │ │ ├── BallSpinFadeLoaderIndicator.java │ │ │ ├── BallTrianglePathIndicator.java │ │ │ ├── BallZigZagDeflectIndicator.java │ │ │ ├── BallZigZagIndicator.java │ │ │ ├── BaseIndicatorController.java │ │ │ ├── CubeTransitionIndicator.java │ │ │ ├── LineScaleIndicator.java │ │ │ ├── LineScalePartyIndicator.java │ │ │ ├── LineScalePulseOutIndicator.java │ │ │ ├── LineScalePulseOutRapidIndicator.java │ │ │ ├── LineSpinFadeLoaderIndicator.java │ │ │ ├── PacmanIndicator.java │ │ │ ├── SemiCircleSpinIndicator.java │ │ │ ├── SquareSpinIndicator.java │ │ │ └── TriangleSkewSpinIndicator.java │ │ └── res/ │ │ ├── drawable/ │ │ │ └── progressloading.xml │ │ ├── drawable-hdpi/ │ │ │ └── progressbar.xml │ │ ├── layout/ │ │ │ ├── listview_footer.xml │ │ │ ├── listview_header.xml │ │ │ └── pull_to_refresh_head.xml │ │ ├── values/ │ │ │ ├── attrs.xml │ │ │ ├── dimens.xml │ │ │ └── strings.xml │ │ └── values-zh/ │ │ └── strings.xml │ └── zmenu/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── example/ │ │ └── zmenu/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── zmenu/ │ │ │ ├── FloatButton.java │ │ │ ├── PUtils.java │ │ │ ├── SnakeButtonLayout.java │ │ │ └── ViewController.java │ │ └── res/ │ │ └── values/ │ │ ├── colors.xml │ │ └── strings.xml │ └── test/ │ └── java/ │ └── com/ │ └── example/ │ └── zmenu/ │ └── ExampleUnitTest.java └── settings.gradle ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Built application files *.apk *.ap_ # Files for the ART/Dalvik VM *.dex # Java class files *.class # Generated files bin/ gen/ out/ # Gradle files .gradle/ build/ # Local configuration file (sdk path, etc) local.properties # Proguard folder generated by Eclipse proguard/ # Log Files *.log # Android Studio Navigation editor temp files .navigation/ # Android Studio captures folder captures/ # Intellij *.iml .idea/workspace.xml .idea/tasks.xml .idea/gradle.xml .idea/dictionaries .idea/libraries # Keystore files *.jks # External native build folder generated in Android Studio 2.2 and later .externalNativeBuild # Google Services (e.g. APIs or Firebase) google-services.json # Freeline freeline.py freeline/ freeline_project_description.json ================================================ FILE: .idea/compiler.xml ================================================ ================================================ FILE: .idea/copyright/profiles_settings.xml ================================================ ================================================ FILE: .idea/inspectionProfiles/Project_Default.xml ================================================ ================================================ FILE: .idea/misc.xml ================================================ 1.8 ================================================ FILE: .idea/modules.xml ================================================ ================================================ FILE: .idea/runConfigurations.xml ================================================ ================================================ FILE: .idea/vcs.xml ================================================ ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: README.md ================================================ # Discover 一款模仿Tumblr UI,使用开眼api开发的符合Material Desgin阅读类的开源项目。项目采取的是MVVM-DataBinding + Rxjava2 + Retrofit架构开发。 # 截图 # Thanks [JiaoZiVideoPlayer](https://github.com/lipangit/JiaoZiVideoPlayer) [开眼视频](http://www.kaiyanapp.com/) # 声明 大部分api 数据都是来自开眼视频,数据接口均属于非正常渠道获取,请勿用于商业用途,原作公司拥有所有权利。 ================================================ FILE: app/.gitignore ================================================ /build ================================================ FILE: app/build.gradle ================================================ apply plugin: 'com.android.application' android { compileSdkVersion 26 buildToolsVersion '26.0.2' defaultConfig { applicationId "com.example.discover" minSdkVersion 19 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" renderscriptTargetApi 19 renderscriptSupportModeEnabled true } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } dataBinding { enabled = true } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile project(':librarys:http') compile project(':librarys:jiaozivideoplayer') compile project(':librarys:xrecyclerview') compile project(':librarys:zmenu') compile 'com.android.support:appcompat-v7:26.1.0' compile 'com.android.support.constraint:constraint-layout:1.0.2' compile 'com.github.bumptech.glide:glide:3.7.0' compile 'org.litepal.android:core:1.6.1' compile 'com.android.support:cardview-v7:26.1.0' compile 'com.trello.rxlifecycle2:rxlifecycle:2.2.1' compile 'com.trello.rxlifecycle2:rxlifecycle-components:2.2.1' compile 'com.jakewharton.rxbinding2:rxbinding-design:2.0.0' compile 'com.jakewharton.rxbinding2:rxbinding-support-v4:2.0.0' compile 'com.jakewharton.rxbinding2:rxbinding-appcompat-v7:2.0.0' compile 'com.jakewharton.rxbinding2:rxbinding-recyclerview-v7:2.0.0' compile 'com.github.mmin18:realtimeblurview:1.1.0' compile 'com.wang.avi:library:2.1.3' compile 'com.hyman:flowlayout-lib:1.1.2' testCompile 'junit:junit:4.12' implementation 'com.github.chrisbanes:PhotoView:2.1.3' debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5' releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5' testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5' } ================================================ FILE: app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in G:\Android\sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: app/src/androidTest/java/com/example/discover/ExampleInstrumentedTest.java ================================================ package com.example.discover; import android.content.Context; import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.*; /** * Instrumentation test, which will execute on an Android device. * * @see Testing documentation */ @RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest { @Test public void useAppContext() throws Exception { // Context of the app under test. Context appContext = InstrumentationRegistry.getTargetContext(); assertEquals("com.example.discover", appContext.getPackageName()); } } ================================================ FILE: app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: app/src/main/assets/litepal.xml ================================================ ================================================ FILE: app/src/main/java/com/example/discover/AuthorHomeActivity.java ================================================ package com.example.discover; import android.databinding.DataBindingUtil; import android.graphics.Color; import android.support.design.widget.AppBarLayout; import android.support.design.widget.TabLayout; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Toast; import com.bumptech.glide.Glide; import com.example.discover.adapter.MyFragmentPagerAdapter; import com.example.discover.databinding.ActivityAuthorHomeBinding; import com.example.discover.ui.DiscoverFragment; import com.example.discover.ui.Search.Author.ItemFragment; import com.example.discover.utils.DebugUtil; import com.example.discover.utils.LitePalUtil; import com.jakewharton.rxbinding2.view.RxView; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import cn.jzvd.JZVideoPlayer; import io.reactivex.functions.Consumer; public class AuthorHomeActivity extends AppCompatActivity { private ActivityAuthorHomeBinding binding; private int authorId; private List fragmentList; private List titleList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = DataBindingUtil.setContentView(this, R.layout.activity_author_home); init(); initFragmentList(); loadViewPager(); } private void init() { authorId = getIntent().getIntExtra("AuthorId", 0); boolean isFollowing = getIntent().getBooleanExtra("Following", false); final String authorName = getIntent().getStringExtra("AuthorName"); final String authorDesc = getIntent().getStringExtra("AuthorDesc"); final String authorIcon = getIntent().getStringExtra("AuthorIcon"); final String authorBack = getIntent().getStringExtra("AuthorBack"); final int color = getIntent().getIntExtra("Color", 0); //填充基本数据 binding.tvName.setText(authorName); binding.toolbarId.setText(authorName); binding.tvDesc.setText(authorDesc); Glide.with(this).load(authorIcon).into(binding.ivHead); Glide.with(this).load(authorBack).into(binding.ivBackground); binding.blurView.setOverlayColor(color); binding.tabItem.setBackgroundColor(color); binding.supView.setBackgroundColor(color); binding.ivHead.setBorderColor(color); binding.llText.setBackgroundColor(color); if (isFollowing) { binding.attention.setVisibility(View.GONE); } //渐变 binding.appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { @Override public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { DebugUtil.debug("appbartest",appBarLayout.getY() + "//" + appBarLayout.getTotalScrollRange() + "//" + verticalOffset); float offsetAlpha = (appBarLayout.getY() / appBarLayout.getTotalScrollRange()); binding.blurView.setAlpha( 2 * (offsetAlpha * -1)); binding.ivHead.setAlpha(1 - 3 * (offsetAlpha * - 1)); } }); //点击事件 binding.ivBack.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onBackPressed(); } }); RxView.clicks(binding.attention) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(new Consumer() { @Override public void accept(Object o) throws Exception { //点击关注 binding.attention.setVisibility(View.GONE); LitePalUtil.addToFollow(authorId, authorName, authorDesc, authorIcon, color, authorBack); Toast.makeText(AuthorHomeActivity.this, "你关注了作者", Toast.LENGTH_SHORT).show(); //待完善 } }); } private void initFragmentList() { fragmentList = new ArrayList<>(); fragmentList.add(ItemFragment.newInstance("date", authorId)); //按日期排序 fragmentList.add(ItemFragment.newInstance("shareCount", authorId)); //按时间排序 titleList = new ArrayList<>(); titleList.add("按时间"); titleList.add("按热度"); } private void loadViewPager() { MyFragmentPagerAdapter adapter = new MyFragmentPagerAdapter(getSupportFragmentManager(), fragmentList, titleList); binding.vpContent.setAdapter(adapter); binding.vpContent.setOffscreenPageLimit(2); binding.tabItem.setTabMode(TabLayout.MODE_FIXED); binding.tabItem.setupWithViewPager(binding.vpContent); } @Override protected void onDestroy() { JZVideoPlayer.releaseAllVideos(); super.onDestroy(); } @Override public void onBackPressed() { //全屏播放时退出全屏 if (JZVideoPlayer.backPress()) { return; } System.gc(); super.onBackPressed(); } } ================================================ FILE: app/src/main/java/com/example/discover/MainActivity.java ================================================ package com.example.discover; import android.databinding.DataBindingUtil; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.design.widget.Snackbar; import android.support.v4.app.Fragment; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.widget.ImageView; import android.widget.Toast; import com.example.discover.adapter.MyFragmentPagerAdapter; import com.example.discover.databinding.ActivityMainBinding; import com.example.discover.ui.DiscoverFragment; import com.example.discover.ui.Personal.PersonalFragment; import com.example.discover.ui.Search.SearchFragment; import com.example.discover.ui.Video.VideoFragment; import com.example.discover.ui.Welfare.WelFareFragment; import com.example.zmenu.PUtils; import com.example.zmenu.SnakeButtonLayout; import com.jakewharton.rxbinding2.view.RxView; import org.litepal.tablemanager.Connector; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import cn.jzvd.JZVideoPlayer; import io.reactivex.functions.Consumer; public class MainActivity extends AppCompatActivity { private ActivityMainBinding mBinding; private ViewPager mViewPager; private ImageView mBottomItem1, mBottomItem2, mBottomItem3, mBottomItem4; private List fragmentList; private List imageList;//XMenu的图片 private List colorList;//XMenu的颜色 private static boolean isExit = false; private static Handler mHandler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message message) { isExit = false; return true; } }); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //初始化XMenu(自己做的一个自定义控件 https://github.com/monkeywiiu/Xmenu) initXMenu(); mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main); initBinding(); initFragmentList(); loadViewPager(); initBottomBar(); //创建litepal数据库 Connector.getDatabase(); } public void initXMenu(){ initXMenuResource(); //设置图片和颜色 if (imageList != null && colorList != null){ PUtils.getInstance().setImagesAndColors(imageList, colorList); } //设置xMenu可见 PUtils.getInstance().setVisible(true); //设置悬浮按钮的margin PUtils.getInstance().setMargin((int) getResources().getDimension(R.dimen.xMenuMarginRight), (int) getResources().getDimension(R.dimen.xMenuMarginBottom)); } public void initXMenuResource() { imageList = new ArrayList<>(); colorList = new ArrayList<>(); imageList.add(R.drawable.image1); imageList.add(R.drawable.image2); imageList.add(R.drawable.image3); imageList.add(R.drawable.image4); imageList.add(R.drawable.image5); imageList.add(R.drawable.image6); colorList.add(R.color.background1); colorList.add(R.color.background2); colorList.add(R.color.background3); colorList.add(R.color.background4); colorList.add(R.color.background5); colorList.add(R.color.background6); } public void initBinding() { mViewPager = mBinding.mainViewpager; mBottomItem1 = mBinding.bottomBar.one; mBottomItem2 = mBinding.bottomBar.two; mBottomItem3 = mBinding.bottomBar.three; mBottomItem4 = mBinding.bottomBar.four; mBinding.snakeButton.setClickable(true); mBinding.snakeButton.setOnTopViewClickListener(new SnakeButtonLayout.onTopViewClickListener() { @Override public void onclick() { Toast.makeText(MainActivity.this, "click", Toast.LENGTH_SHORT).show(); } }); } public void initFragmentList() { fragmentList = new ArrayList<>(); fragmentList.add(new VideoFragment()); //开眼视频页面 fragmentList.add(new SearchFragment()); fragmentList.add(new WelFareFragment()); fragmentList.add(new PersonalFragment()); } public void loadViewPager(){ MyFragmentPagerAdapter adapter = new MyFragmentPagerAdapter(getSupportFragmentManager(), fragmentList); mViewPager.setAdapter(adapter); mViewPager.setOffscreenPageLimit(3); mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { if (position == 0) { mBottomItem1.setSelected(true); mBottomItem2.setSelected(false); mBottomItem3.setSelected(false); mBottomItem4.setSelected(false); } else if (position == 1) { mBottomItem2.setSelected(true); mBottomItem1.setSelected(false); mBottomItem3.setSelected(false); mBottomItem4.setSelected(false); } else if (position == 2) { mBottomItem3.setSelected(true); mBottomItem1.setSelected(false); mBottomItem2.setSelected(false); mBottomItem4.setSelected(false); } else if (position == 3) { mBottomItem4.setSelected(true); mBottomItem1.setSelected(false); mBottomItem2.setSelected(false); mBottomItem3.setSelected(false); } } @Override public void onPageScrollStateChanged(int state) { } }); } public void initBottomBar() { //设置bottom点击选中事件 mBottomItem1.setSelected(true); mBottomItem1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mBottomItem1.setSelected(true); mBottomItem2.setSelected(false); mBottomItem3.setSelected(false); mBottomItem4.setSelected(false); mViewPager.setCurrentItem(0); } }); mBottomItem2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mBottomItem2.setSelected(true); mBottomItem1.setSelected(false); mBottomItem3.setSelected(false); mBottomItem4.setSelected(false); mViewPager.setCurrentItem(1); } }); mBottomItem3.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mBottomItem3.setSelected(true); mBottomItem1.setSelected(false); mBottomItem2.setSelected(false); mBottomItem4.setSelected(false); mViewPager.setCurrentItem(2); } }); mBottomItem4.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mBottomItem4.setSelected(true); mBottomItem1.setSelected(false); mBottomItem2.setSelected(false); mBottomItem3.setSelected(false); mViewPager.setCurrentItem(3); } }); } @Override public void onBackPressed() { //全屏播放时退出全屏 if (JZVideoPlayer.backPress()) { return; } super.onBackPressed(); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { if (!JZVideoPlayer.backPress()) { exit(); } return true; } return super.onKeyDown(keyCode, event); } //双击退出 private void exit() { if (!isExit) { isExit = true; Snackbar snackbar = Snackbar.make(mViewPager, "再按一次后退键退出程序", Snackbar.LENGTH_SHORT); snackbar.getView().setBackgroundResource(R.color.colorAccent); snackbar.show(); // 利用handler延迟发送更改状态信息 mHandler.sendEmptyMessageDelayed(0, 2000); } else { this.finish(); } } } ================================================ FILE: app/src/main/java/com/example/discover/ResultActivity.java ================================================ package com.example.discover; import android.content.Intent; import android.os.Handler; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.util.Pair; import android.view.MenuItem; import android.widget.ImageButton; import android.widget.TextView; import com.example.discover.adapter.ResultAdapter; import com.example.discover.bean.DetailBean.ItemList; import com.example.discover.bean.ResultBean; import com.example.discover.http.RequestListener; import com.example.discover.model.SearchModel; import com.example.discover.utils.DebugUtil; import com.jakewharton.rxbinding2.support.v7.widget.RxRecyclerView; import com.jakewharton.rxbinding2.view.RxView; import com.trello.rxlifecycle2.components.support.RxAppCompatActivity; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import io.reactivex.functions.Consumer; public class ResultActivity extends RxAppCompatActivity { private String keyword; private int start = 1; private boolean loading = false; private ResultAdapter adapter; private List resultList = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_result); keyword = getIntent().getStringExtra(SearchActivity.KEYWORD); init(); initRecyclerView(); showResult(); } public void init() { //设置toolbar Toolbar toolbar = findViewById(R.id.toolbar); TextView titleView = findViewById(R.id.title); setSupportActionBar(toolbar); ActionBar ab = getSupportActionBar(); if (ab != null) ab.setDisplayHomeAsUpEnabled(true); titleView.setText(keyword); ImageButton searchBtn = findViewById(R.id.search_btn); RxView.clicks(searchBtn) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(new Consumer() { @Override public void accept(Object o) throws Exception { Intent intent = new Intent(ResultActivity.this, SearchActivity.class); startActivity(intent); } }); } public void initRecyclerView() { RecyclerView resultRecyclerView = findViewById(R.id.rv_result); final LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); resultRecyclerView.setLayoutManager(layoutManager); adapter = new ResultAdapter(this, resultList); resultRecyclerView.setAdapter(adapter); //上拉加载 resultRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); int lastVisibleItem = layoutManager.findLastVisibleItemPosition(); int totalItemCount = layoutManager.getItemCount(); DebugUtil.debug("resultTest", lastVisibleItem + " " + totalItemCount); if (lastVisibleItem == totalItemCount - 5 && !loading) { loading = true; new Handler().postDelayed(new Runnable() { @Override public void run() { showResult(); } }, 1000); } } }); } public void showResult() { SearchModel.showResult(this, keyword, start, new RequestListener() { @Override public void onSuccess(Object object) { ResultBean resultBean = (ResultBean) object; DebugUtil.debug("resultTest", "size" + resultBean.getItemList().size() +"start" +start); resultList.addAll(resultBean.getItemList()); adapter.notifyDataSetChanged(); loading = false; start += resultBean.getItemList().size(); } @Override public void onFailed(Throwable t) { DebugUtil.debug("resultsss", "" + "failed"); } @Override public void onCompleted() { } }); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { finish(); return true; } return super.onOptionsItemSelected(item); } } ================================================ FILE: app/src/main/java/com/example/discover/SearchActivity.java ================================================ package com.example.discover; import android.content.Intent; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.view.KeyEvent; import android.view.MenuItem; import android.view.View; import android.widget.EditText; import android.widget.ImageButton; import android.widget.Toast; import com.example.discover.adapter.SearchTagAdapter; import com.example.discover.bean.DetailBean.Data; import com.example.discover.bean.LitePalBean.SearchTag; import com.example.discover.http.RequestListener; import com.example.discover.model.SearchModel; import com.example.discover.utils.DebugUtil; import com.jakewharton.rxbinding2.view.RxView; import com.trello.rxlifecycle2.components.support.RxAppCompatActivity; import org.litepal.crud.DataSupport; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import io.reactivex.functions.Consumer; public class SearchActivity extends RxAppCompatActivity { public static String KEYWORD = "keyword"; private RecyclerView mTagRecyclerView; private EditText searchEdit; private SearchTagAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_search); initRecyclerView(); init(); loadTrendingTag(); onKeyListener(); } private void init() { List tagList = new ArrayList<>(); searchEdit = findViewById(R.id.search_edit); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); ActionBar ab = getSupportActionBar(); if (ab != null) ab.setDisplayHomeAsUpEnabled(true); ImageButton clearButton = findViewById(R.id.clear_btn); final EditText searchEdit = findViewById(R.id.search_edit); RxView.clicks(clearButton) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(new Consumer() { @Override public void accept(Object o) throws Exception { searchEdit.setText(""); } }); //获取5个最新的搜索记录; if (DataSupport.count(SearchTag.class) > 0) { tagList.add("new"); List list = DataSupport.limit(5).order("id desc").find(SearchTag.class); if (list != null) { for (SearchTag tag : list) { tagList.add(tag.getTag()); } //只保留5个tag DataSupport.deleteAll(SearchTag.class); for (int i = tagList.size() - 1; i > 0; i--) { SearchTag searchTag = new SearchTag(); searchTag.setTag(tagList.get(i)); searchTag.save(); } } } setAdapter(tagList); } private void initRecyclerView() { LinearLayoutManager manager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); mTagRecyclerView = findViewById(R.id.rv_hot_tag); mTagRecyclerView.setLayoutManager(manager); } private void setAdapter(List list) { adapter = new SearchTagAdapter(this); DebugUtil.debug("trend", list.size() + ""); adapter.setItemClickListener(new SearchTagAdapter.onItemClickListener() { @Override public void onItemClick(String s) { toResultActivity(s); } }); mTagRecyclerView.setAdapter(adapter); adapter.addAll(list); adapter.notifyDataSetChanged(); } private void loadTrendingTag() { SearchModel.showTrendingTag(this, new RequestListener() { @Override public void onSuccess(Object object) { List list = (List) object; List tagList2 = new ArrayList<>(); tagList2.add("recommend"); tagList2.addAll(list); adapter.addAll(tagList2); adapter.notifyDataSetChanged(); } @Override public void onFailed(Throwable t) { t.printStackTrace(); DebugUtil.debug("trend", "failed"); } @Override public void onCompleted() { } }); } private void onKeyListener() { searchEdit.setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() != KeyEvent.ACTION_DOWN) return true; if (keyCode == KeyEvent.KEYCODE_ENTER) { if (searchEdit.getText().toString().isEmpty()) { Toast.makeText(SearchActivity.this, "搜索不能为空", Toast.LENGTH_SHORT).show(); } else { search(searchEdit.getText().toString()); } } else if (keyCode == KeyEvent.KEYCODE_BACK) { finish(); } return false; } }); } private void search(String key) { DataSupport.deleteAll(SearchTag.class, "tag = ?", key); SearchTag tag = new SearchTag(); tag.setTag(key); tag.save(); toResultActivity(key); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { finish(); return true; } return super.onOptionsItemSelected(item); } public void toResultActivity(String key) { Intent intent = new Intent(this, ResultActivity.class); intent.putExtra(KEYWORD, key); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); finish(); } } ================================================ FILE: app/src/main/java/com/example/discover/TestActivity.java ================================================ package com.example.discover; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import android.widget.TextView; /** * Created by monkeyWiiu on 2018/1/8. */ public class TestActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); } } ================================================ FILE: app/src/main/java/com/example/discover/VideoDetailActivity.java ================================================ package com.example.discover; import android.databinding.DataBindingUtil; import android.os.Handler; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageButton; import android.widget.ImageView; import com.bumptech.glide.Glide; import com.example.discover.adapter.ReplyAdapter; import com.example.discover.app.Constant; import com.example.discover.app.DiscoverApplication; import com.example.discover.bean.DetailBean.ItemList; import com.example.discover.bean.DetailBean.Replies; import com.example.discover.bean.DetailBean.ReplyList; import com.example.discover.databinding.ItemMovieDetailHeaderBinding; import com.example.discover.http.RequestListener; import com.example.discover.model.ReplyModel; import com.example.discover.utils.DebugUtil; import com.example.discover.utils.IntentManager; import com.example.discover.utils.LitePalUtil; import com.jakewharton.rxbinding2.view.RxView; import com.squareup.leakcanary.RefWatcher; import com.trello.rxlifecycle2.components.support.RxAppCompatActivity; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import cn.jzvd.JZVideoPlayer; import cn.jzvd.JZVideoPlayerStandard; import io.reactivex.functions.Consumer; public class VideoDetailActivity extends RxAppCompatActivity { private ItemList item; private ItemMovieDetailHeaderBinding headerBinding; private ReplyAdapter replyAdapter; private LinearLayoutManager linearLayoutManager; private List replyLists = new ArrayList<>(); private boolean firstRequest = true; private boolean loading = false; private int lastSequence; private RecyclerView replies; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_video_detail); init(); initJZPlayer(); loadReply(); } public void init() { item = (ItemList) getIntent().getSerializableExtra("item"); replies = findViewById(R.id.rv_replies); linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL,false); replies.setLayoutManager(linearLayoutManager); View view =DataBindingUtil.inflate(LayoutInflater.from(this), R.layout.item_movie_detail_header, replies, false).getRoot(); headerBinding = DataBindingUtil.getBinding(view); headerBinding.setItem(item); RxView.clicks(headerBinding.authorContent) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(new Consumer() { @Override public void accept(Object o) throws Exception { JZVideoPlayer.releaseAllVideos(); IntentManager.fromDetailtoAuthor(headerBinding.authorContent.getContext(), item); } }); replyAdapter = new ReplyAdapter(replyLists, view); replies.setAdapter(replyAdapter); //上拉加载 replies.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); int lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition(); int totalItemCount = linearLayoutManager.getItemCount(); if (lastVisibleItem == totalItemCount - 5 && !loading) { loading = true; new Handler().postDelayed(new Runnable() { @Override public void run() { loadReply(); } }, 1000); } } }); //点击收藏 headerBinding.collect.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (item.getTag() == null) { headerBinding.collect.setImageDrawable(getResources().getDrawable(R.drawable.ic_heart_full_24dp_pink)); //入库 LitePalUtil.addVideoToFavor(item.getData().getId(), item.getData().getTitle(), item.getData().getDescription(), item.getData().getPlayUrl(), item.getData().getCover().getDetail(),item.getData().getAuthor().getName(), item.getData().getAuthor().getId(),item.getData().getAuthor().getIcon(),item.getData().getAuthor().getDescription(), (int) Constant.LabelMap.get(item.getData().getCategory()), item.getData().getCategory(), 0); item.setTag("true"); } else if ("true".equals(item.getTag())){ headerBinding.collect.setImageDrawable(getResources().getDrawable(R.drawable.ic_heart_hollow_24dp)); //出库 LitePalUtil.deleteVideoFromFavor(item.getData().getId()); item.setTag(null); } } }); } public void initJZPlayer() { JZVideoPlayerStandard videoPlayerStandard = findViewById(R.id.jz_player); Glide.with(this).load(item.getData().getCover().getDetail()) .crossFade(800) .placeholder(R.drawable.cross_image) .error(R.drawable.cross_image) .into(videoPlayerStandard.thumbImageView); videoPlayerStandard.setUp(item.getData().getPlayUrl(), JZVideoPlayer.SCREEN_WINDOW_NORMAL, ""); videoPlayerStandard.backButton.setVisibility(View.VISIBLE); videoPlayerStandard.backButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onBackPressed(); } }); } public void loadReply() { ReplyModel.showReplies(this, firstRequest, lastSequence, item.getData().getId(), new RequestListener() { @Override public void onSuccess(Object object) { Replies reply = (Replies) object; DebugUtil.debug("replylistss", reply.getReplyList().size() + ""); if (reply.getReplyList().size() > 0) { replyLists.addAll(reply.getReplyList()); replyAdapter.notifyDataSetChanged(); lastSequence = reply.getReplyList().get(reply.getReplyList().size() - 1).getSequence(); firstRequest = false; loading =false; } } @Override public void onFailed(Throwable t) { } @Override public void onCompleted() { } }); } @Override protected void onDestroy() { DebugUtil.debug("desss", "1"); // setContentView(R.layout.null_layout); RefWatcher refWatcher = DiscoverApplication.getRefWatcher(this); refWatcher.watch(this); super.onDestroy(); } @Override public void onBackPressed() { //全屏播放时退出全屏 if (JZVideoPlayer.backPress()) { return; } toFinish(); super.onBackPressed(); } public void toFinish() { DebugUtil.debug("ffff", "111"); replyLists = null; replyAdapter = null; System.gc(); } } ================================================ FILE: app/src/main/java/com/example/discover/ViewBigImageActivity.java ================================================ package com.example.discover; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.support.v4.app.ActivityCompat; import android.support.v4.app.FragmentActivity; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.drawable.GlideDrawable; import com.bumptech.glide.request.FutureTarget; import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.target.Target; import com.example.discover.utils.DebugUtil; import com.github.chrisbanes.photoview.OnOutsidePhotoTapListener; import com.github.chrisbanes.photoview.OnPhotoTapListener; import com.github.chrisbanes.photoview.PhotoView; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.List; import java.util.concurrent.ExecutionException; /** * 查看大图,拖拽退出 * Created by monkeyWiiu on 2018/2/3. */ public class ViewBigImageActivity extends FragmentActivity implements OnPageChangeListener, OnPhotoTapListener, OnOutsidePhotoTapListener { private static String[] PERMISSIONS_STORAGE = { "android.permission.READ_EXTERNAL_STORAGE", "android.permission.WRITE_EXTERNAL_STORAGE" }; // 保存图片 private TextView tv_save_big_image; // 接收传过来的uri地址 List imageuri; // 接收穿过来当前选择的图片的数量 int code; // 用于判断是头像还是文章图片 1:头像 2:文章大图 int selet; // 用于管理图片的滑动 ViewPager very_image_viewpager; // 当前页数 private int page; /** * 显示当前图片的页数 */ TextView very_image_viewpager_text; /** * 用于判断是否是加载本地图片 */ private boolean isLocal; ViewPagerAdapter adapter; /** * 本应用图片的id */ private int imageId; /** * 是否是本应用中的图片 */ private boolean isApp; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_view_big_image); verifyStoragePermissions(this); getView(); } public static void verifyStoragePermissions(Activity activity) { try { int permission = ActivityCompat.checkSelfPermission(activity, "android.permission.WRITE_EXTERNAL_STORAGE"); if (permission != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE, 1); } } catch (Exception e) { e.printStackTrace(); } } /** * 保存图片至相册 */ public static void saveImageToGallery(Context context, Bitmap bmp) { // 首先保存图片 File appDir = new File(Environment.getExternalStorageDirectory(), "云阅相册"); if (!appDir.exists()) { appDir.mkdirs(); } String fileName = System.currentTimeMillis() + ".jpg"; File file = new File(appDir, fileName); try { FileOutputStream fos = new FileOutputStream(file); bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos); fos.flush(); fos.close(); } catch (IOException e) { e.printStackTrace(); } // 其次把文件插入到系统图库 try { MediaStore.Images.Media.insertImage(context.getContentResolver(), file.getAbsolutePath(), fileName, null); } catch (FileNotFoundException e) { e.printStackTrace(); } // 最后通知图库更新 context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + file.getAbsoluteFile()))); } /** * Glide 获得图片缓存路径 */ private String getImagePath(String imgUrl) { String path = null; FutureTarget future = Glide.with(ViewBigImageActivity.this) .load(imgUrl) .downloadOnly(500, 500); try { File cacheFile = future.get(); path = cacheFile.getAbsolutePath(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } return path; } /* * 接收控件 */ private void getView() { /************************* 接收控件 ***********************/ very_image_viewpager_text = (TextView) findViewById(R.id.very_image_viewpager_text); tv_save_big_image = (TextView) findViewById(R.id.tv_save_big_image); very_image_viewpager = (ViewPager) findViewById(R.id.very_image_viewpager); tv_save_big_image.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(ViewBigImageActivity.this, "开始下载图片", Toast.LENGTH_SHORT).show(); if (isApp) {// 本地图片 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), imageId); if (bitmap != null) { saveImageToGallery(ViewBigImageActivity.this, bitmap); Toast.makeText(ViewBigImageActivity.this, "保存成功", Toast.LENGTH_SHORT).show(); // Toast.makeText(ViewBigImageActivity.this, "保存成功", Toast.LENGTH_SHORT).show(); } } else {// 网络图片 final BitmapFactory.Options bmOptions = new BitmapFactory.Options(); new Thread(new Runnable() { @Override public void run() { // 子线程获得图片路径 final String imagePath = getImagePath(imageuri.get(page)); Log.d("imagePathand", imagePath + ".." + imageuri.get(page)); // 主线程更新 ViewBigImageActivity.this.runOnUiThread(new Runnable() { @Override public void run() { if (imagePath != null) { Bitmap bitmap = BitmapFactory.decodeFile(imagePath, bmOptions); if (bitmap != null) { saveImageToGallery(ViewBigImageActivity.this, bitmap); Toast.makeText(ViewBigImageActivity.this, "已保存至"+Environment.getExternalStorageDirectory().getAbsolutePath()+"/云阅相册", Toast.LENGTH_SHORT).show(); // Toast.makeText(ViewBigImageActivity.this, "保存成功", Toast.LENGTH_SHORT).show(); } } } }); } }).start(); } } }); /************************* 接收传值 ***********************/ Bundle bundle = getIntent().getExtras(); code = bundle.getInt("code"); selet = bundle.getInt("selet"); isLocal = bundle.getBoolean("isLocal", false); imageuri = bundle.getStringArrayList("imageuri"); /**是否是本应用中的图片*/ isApp = bundle.getBoolean("isApp", false); /**本应用图片的id*/ imageId = bundle.getInt("id", 0); /** * 给viewpager设置适配器 */ if (isApp) { MyPageAdapter myPageAdapter = new MyPageAdapter(); very_image_viewpager.setAdapter(myPageAdapter); very_image_viewpager.setEnabled(false); } else { adapter = new ViewPagerAdapter(); very_image_viewpager.setAdapter(adapter); very_image_viewpager.setCurrentItem(code); page = code; very_image_viewpager.setOnPageChangeListener(this); very_image_viewpager.setEnabled(false); // 设定当前的页数和总页数 if (selet == 2) { very_image_viewpager_text.setText((code + 1) + " / " + imageuri.size()); } } } /** * 本应用图片适配器 */ class MyPageAdapter extends PagerAdapter { @Override public int getCount() { return 1; } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public Object instantiateItem(ViewGroup container, int position) { View view = getLayoutInflater().inflate(R.layout.viewpager_very_image, container, false); PhotoView zoom_image_view = view.findViewById(R.id.zoom_image_view); ProgressBar spinner = (ProgressBar) view.findViewById(R.id.loading); spinner.setVisibility(View.GONE); if (imageId != 0) { zoom_image_view.setImageResource(imageId); } zoom_image_view.setOnPhotoTapListener(ViewBigImageActivity.this); container.addView(view, 0); return view; } @Override public void destroyItem(ViewGroup container, int position, Object object) { View view = (View) object; container.removeView(view); } } /** * ViewPager的适配器 * * @author guolin */ class ViewPagerAdapter extends PagerAdapter { LayoutInflater inflater; ViewPagerAdapter() { inflater = getLayoutInflater(); } @Override public Object instantiateItem(ViewGroup container, int position) { View view = inflater.inflate(R.layout.viewpager_very_image, container, false); final PhotoView zoom_image_view = (PhotoView) view.findViewById(R.id.zoom_image_view); final ProgressBar spinner = (ProgressBar) view.findViewById(R.id.loading); // 保存网络图片的路径 String adapter_image_Entity = (String) getItem(position); //TODO String imageUrl; if (isLocal) { imageUrl = "file://" + adapter_image_Entity; tv_save_big_image.setVisibility(View.GONE); } else { imageUrl = adapter_image_Entity; } spinner.setVisibility(View.VISIBLE); spinner.setClickable(false); Glide.with(ViewBigImageActivity.this).load(imageUrl) .crossFade(700) .listener(new RequestListener() { @Override public boolean onException(Exception e, String model, Target target, boolean isFirstResource) { Toast.makeText(getApplicationContext(), "资源加载异常", Toast.LENGTH_SHORT).show(); spinner.setVisibility(View.GONE); return false; } //这个用于监听图片是否加载完成 @Override public boolean onResourceReady(GlideDrawable resource, String model, Target target, boolean isFromMemoryCache, boolean isFirstResource) { // Toast.makeText(getApplicationContext(), "图片加载完成", Toast.LENGTH_SHORT).show(); spinner.setVisibility(View.GONE); /**这里应该是加载成功后图片的高*/ int height = zoom_image_view.getHeight(); int wHeight = getWindowManager().getDefaultDisplay().getHeight(); if (height > wHeight) { zoom_image_view.setScaleType(ImageView.ScaleType.CENTER_CROP); } else { zoom_image_view.setScaleType(ImageView.ScaleType.FIT_CENTER); } return false; } }).into(zoom_image_view); zoom_image_view.setOnPhotoTapListener(ViewBigImageActivity.this); container.addView(view, 0); return view; } @Override public int getCount() { if (imageuri == null || imageuri.size() == 0) { return 0; } return imageuri.size(); } @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } @Override public void destroyItem(ViewGroup container, int position, Object object) { View view = (View) object; container.removeView(view); } Object getItem(int position) { return imageuri.get(position); } } /** * 下面是对Viewpager的监听 */ @Override public void onPageScrollStateChanged(int arg0) { } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { } /** * 本方法主要监听viewpager滑动的时候的操作 */ @Override public void onPageSelected(int arg0) { // 每当页数发生改变时重新设定一遍当前的页数和总页数 very_image_viewpager_text.setText((arg0 + 1) + " / " + imageuri.size()); page = arg0; } @Override public void onPhotoTap(ImageView view, float x, float y) { DebugUtil.debug("232323", "11"); onBackPressed(); } @Override public void onOutsidePhotoTap(ImageView imageView) { } @Override public void onBackPressed() { System.gc(); super.onBackPressed(); } } ================================================ FILE: app/src/main/java/com/example/discover/adapter/AuthorPopAdapter.java ================================================ package com.example.discover.adapter; import android.content.Context; import android.content.Intent; import android.view.ViewGroup; import android.widget.Toast; import com.example.discover.AuthorHomeActivity; import com.example.discover.R; import com.example.discover.app.Constant; import com.example.discover.base.baseadapter.BaseRecyclerAdapter; import com.example.discover.base.baseadapter.BaseViewHolder; import com.example.discover.bean.DetailBean.ItemList; import com.example.discover.databinding.AuthorCardBinding; import com.example.discover.utils.IntentManager; import com.jakewharton.rxbinding2.view.RxView; import java.util.concurrent.TimeUnit; import io.reactivex.functions.Consumer; /** * Created by monkeyWiiu on 2018/1/18. */ public class AuthorPopAdapter extends BaseRecyclerAdapter { public AuthorPopAdapter(Context context) { super(context); } @Override public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new AuthorCardHolder(parent, R.layout.author_card); } public class AuthorCardHolder extends BaseViewHolder { public AuthorCardHolder(ViewGroup parent, int layoutId) { super(parent, layoutId); } @Override public void fillHolder(final ItemList object, int position) { RxView.clicks(itemViewBinding.cvEnter) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(new Consumer() { @Override public void accept(Object o) throws Exception { //toAuthorHomeActivity(object); IntentManager.toAuthorHomeActivity(mContext, object); } }); setBackGroundColor(itemViewBinding, object); itemViewBinding.setItemList(object); } } @Override public int getItemCount() { return mData.size(); } public void setBackGroundColor(AuthorCardBinding binding, ItemList object) { if (object.getData().getItemList().size() > 0) { int color; color = (Integer) Constant.LabelMap.get(object.getData().getItemList().get(0).getData().getCategory()); binding.cvAuthor.setCardBackgroundColor(color); binding.cvImage.setCardBackgroundColor(color); binding.civAvatar.setBorderColor(color); } } } ================================================ FILE: app/src/main/java/com/example/discover/adapter/CategoryPopAdapter.java ================================================ package com.example.discover.adapter; import android.app.Activity; import android.app.ActivityOptions; import android.content.Context; import android.content.Intent; import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityOptionsCompat; import android.util.Pair; import android.view.View; import android.view.ViewGroup; import com.example.discover.R; import com.example.discover.VideoDetailActivity; import com.example.discover.base.baseadapter.BaseRecyclerAdapter; import com.example.discover.base.baseadapter.BaseViewHolder; import com.example.discover.bean.DetailBean.ItemList; import com.example.discover.databinding.CategoryCardBinding; import com.example.discover.utils.IntentManager; import com.jakewharton.rxbinding2.view.RxView; import java.util.concurrent.TimeUnit; import io.reactivex.functions.Consumer; /** * Created by monkeyWiiu on 2018/1/18. */ public class CategoryPopAdapter extends BaseRecyclerAdapter { public CategoryPopAdapter(Context context ) { super(context); } @Override public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new CateGoryCardHolder(parent, R.layout.category_card); } public class CateGoryCardHolder extends BaseViewHolder { public CateGoryCardHolder(ViewGroup parent, int layoutId) { super(parent, layoutId); } @Override public void fillHolder(final ItemList object, int position) { //itemViewBinding.tvText.setText(object.getData().getTitle()); itemViewBinding.setItemList(object); RxView.clicks(itemViewBinding.videoAlbum) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(new Consumer() { @Override public void accept(Object o) throws Exception { IntentManager.toVideoDetailActivity((Activity) mContext, object, itemViewBinding.videoAlbum); } }); } } @Override public int getItemCount() { return mData.size(); } /*private void toVideoDetailActivity(ItemList item, View view) { Intent intent = new Intent(mContext, VideoDetailActivity.class); intent.putExtra("item", item); ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation( mContext, Pair.create(view, mContext.getString(R.string.transition_shot)), Pair.create(view, mContext.getString(R.string.transition_shot_background)) ); mContext.startActivity(intent, options.toBundle()); }*/ } ================================================ FILE: app/src/main/java/com/example/discover/adapter/FollowRecyclerAdapter.java ================================================ package com.example.discover.adapter; import android.content.Context; import android.content.Intent; import android.view.View; import android.view.ViewGroup; import com.example.discover.AuthorHomeActivity; import com.example.discover.R; import com.example.discover.app.Constant; import com.example.discover.base.BaseFragment; import com.example.discover.base.baseadapter.BaseRecyclerAdapter; import com.example.discover.base.baseadapter.BaseViewHolder; import com.example.discover.bean.DetailBean.ItemList; import com.example.discover.bean.LitePalBean.Follow; import com.example.discover.databinding.FooterItemVideoBinding; import com.example.discover.databinding.ItemFollowBinding; import com.example.discover.utils.DebugUtil; import com.example.discover.view.CustomView.FollowPopupWindow; import org.litepal.crud.DataSupport; /** * Created by monkeyWiiu on 2018/1/26. */ public class FollowRecyclerAdapter extends BaseRecyclerAdapter { private final static int TYPE_CONTENT = 2; private final static int TYPE_FOOTER = 3; private FooterItemVideoBinding mFooterBinding; private final static int LOAD_MORE = 1; private final static int NO_MORE = 0; private final static int STATE_NORMAL = -1; private int mState = STATE_NORMAL; public FollowRecyclerAdapter(Context context) { super(context); } @Override public int getItemViewType(int position) { if (position + 1 == getItemCount()) { return TYPE_FOOTER; } else { return TYPE_CONTENT; } } @Override public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == TYPE_CONTENT) { return new FollowHolder(parent, R.layout.item_follow); } else { return new FooterHolder(parent, R.layout.footer_item_video); } } public class FollowHolder extends BaseViewHolder { public FollowHolder(ViewGroup parent, int layoutId) { super(parent, layoutId); } @Override public void fillHolder(final Follow object, final int position) { itemViewBinding.setFollow(object); itemViewBinding.selector.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { FollowPopupWindow window = new FollowPopupWindow(v.getContext()); window.showPopupWindow(itemViewBinding.selector); window.setPopItemClickListener(new FollowPopupWindow.PopItemClickListener() { @Override public void ItemClick() { DataSupport.deleteAll(Follow.class, "authorId = ?", String.valueOf(object.getAuthorId())); delete(position); } }); } }); itemViewBinding.followItem.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { toAuthorHomeActivity(object); } }); } } private void toAuthorHomeActivity(Follow follow) { Intent intent = new Intent(mContext, AuthorHomeActivity.class); intent.putExtra("AuthorId", follow.getAuthorId()); intent.putExtra("AuthorName", follow.getAuthorName()); intent.putExtra("AuthorIcon", follow.getIconUrl()); intent.putExtra("AuthorDesc", follow.getAuthorDesc()); intent.putExtra("Color", follow.getBackgroundColor()); intent.putExtra("AuthorBack", follow.getBackgroundImage()); intent.putExtra("Following", true); mContext.startActivity(intent); } public class FooterHolder extends BaseViewHolder { public FooterHolder(ViewGroup parent, int layoutId) { super(parent, layoutId); } @Override public void fillHolder(Object object, int position) { mFooterBinding = itemViewBinding; //itemViewBinding.loading.show(); } } public void updateStateLoad(boolean loading) { if (loading) { this.mState = LOAD_MORE; }else { this.mState = NO_MORE; } } public boolean isLoading() { if (this.mState == LOAD_MORE) { return true; } else return false; } public void hideLoading() { mFooterBinding.loading.hide(); } } ================================================ FILE: app/src/main/java/com/example/discover/adapter/ItemHelper.java ================================================ package com.example.discover.adapter; /** * Created by monkeyWiiu on 2018/1/14. */ public interface ItemHelper { void onItemMove(int fromPosition, int toPosition); void onItemDismiss(int position); } ================================================ FILE: app/src/main/java/com/example/discover/adapter/LabelChooseAdapter.java ================================================ package com.example.discover.adapter; import android.content.Context; import android.support.v7.widget.CardView; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.example.discover.R; import com.example.discover.app.Constant; import com.example.discover.bean.LitePalBean.LabelType; import com.example.discover.view.CustomView.LabelView; import org.litepal.crud.DataSupport; import org.w3c.dom.Text; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.zip.Inflater; /** * Created by monkeyWiiu on 2018/1/13. */ public class LabelChooseAdapter extends RecyclerView.Adapter { private List savedList; private HashMap mMap; private List mKeyList; private Context mContext; private ItemClickListener mListener; public interface ItemClickListener { void itemClick(String labelType); } public void setItemClickListener(ItemClickListener listener) { this.mListener = listener; } public LabelChooseAdapter(List list, HashMap map, Context context) { this.mKeyList = list; this.mMap = map; this.mContext = context; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(mContext).inflate(R.layout.label_view, parent, false); MyViewHolder viewHolder = new MyViewHolder(view); return viewHolder; } @Override public void onBindViewHolder(MyViewHolder holder, final int position) { holder.labelView.setCardBackgroundColor((int)mMap.get(mKeyList.get(position))); holder.textLabel.setText(mKeyList.get(position)); holder.labelView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { /*savedList = DataSupport.findAll(LabelType.class); for (LabelType label : savedList) { if (mKeyList.get(position).equals(label.getType())) { return; } } LabelType label = new LabelType(); label.setType(mKeyList.get(position)); label.save();*/ mListener.itemClick(mKeyList.get(position)); } }); } @Override public int getItemCount() { return mMap.size(); } public class MyViewHolder extends RecyclerView.ViewHolder { private TextView textLabel; private CardView labelView; private MyViewHolder(View itemView) { super(itemView); textLabel = itemView.findViewById(R.id.tv_label); labelView = itemView.findViewById(R.id.cv_choose_label); } } } ================================================ FILE: app/src/main/java/com/example/discover/adapter/LikeVideoRecyclerAdapter.java ================================================ package com.example.discover.adapter; import android.content.Context; import android.view.View; import android.view.ViewGroup; import com.bumptech.glide.Glide; import com.example.discover.R; import com.example.discover.base.baseadapter.BaseRecyclerAdapter; import com.example.discover.base.baseadapter.BaseViewHolder; import com.example.discover.bean.LitePalBean.LikeVideo; import com.example.discover.databinding.FooterItemVideoBinding; import com.example.discover.databinding.LikeVideoCardBinding; import com.example.discover.utils.DebugUtil; import com.example.discover.utils.IntentManager; import com.example.discover.utils.ShareUtil; import cn.jzvd.JZVideoPlayer; /** * Created by monkeyWiiu on 2018/1/5. */ public class LikeVideoRecyclerAdapter extends BaseRecyclerAdapter { private final static int TYPE_CONTENT = 2; private final static int TYPE_FOOTER = 3; private final static int LOAD_MORE = 1; private final static int NO_MORE = 0; private final static int STATE_NORMAL = -1; private int mState = STATE_NORMAL; private FooterItemVideoBinding mFooterBinding; public MyDeleteClickListener deleteListener; public interface MyDeleteClickListener { void onDelete(int position, int id); } public void setOnClickListener(MyDeleteClickListener listener){ this.deleteListener = listener; } public LikeVideoRecyclerAdapter(Context context) { super(context); } @Override public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == TYPE_CONTENT) { return new LikeVideoHolder(parent, R.layout.like_video_card); } else { return new FooterHolder(parent, R.layout.footer_item_video); } } @Override public int getItemViewType(int position) { if (position + 1 == getItemCount()) { return TYPE_FOOTER; } else { return TYPE_CONTENT; } } public class LikeVideoHolder extends BaseViewHolder { public LikeVideoHolder(ViewGroup parent, int layoutId) { super(parent, layoutId); } @Override public void fillHolder(LikeVideo likeVideo, int position) { if (likeVideo != null) { itemViewBinding.tvDesc.setText(likeVideo.getDescription()); itemViewBinding.jzVideoPlayer.setUp(likeVideo.getPlayUrl(), JZVideoPlayer.SCREEN_WINDOW_NORMAL, likeVideo.getTitle()); itemViewBinding.tvLabel.setText(likeVideo.getLabelText()); itemViewBinding.cvLabel.setCardBackgroundColor(likeVideo.getLabelColor()); Glide.with(mContext).load(likeVideo.getImageUrl()) .crossFade(800) .placeholder(R.drawable.cross_image) .error(R.drawable.cross_image) .into(itemViewBinding.jzVideoPlayer.thumbImageView); /*if (likeVideo.getSize() > 0) { itemViewBinding.tvVideoSize.setText("视频大小" + likeVideo.getSize() + "MB"); }*/ Glide.with(mContext).load(likeVideo.getAuthorIcon()) .error(R.drawable.cross_image) .into(itemViewBinding.headIcon); } //设置点击事件 setOnClick(itemViewBinding, likeVideo, position, likeVideo.getId()); } } public class FooterHolder extends BaseViewHolder { public FooterHolder(ViewGroup parent, int layoutId) { super(parent, layoutId); } @Override public void fillHolder(Object object, int position) { mFooterBinding = itemViewBinding; DebugUtil.debug("loading11", "yun"); //itemViewBinding.loading.show(); } } public void setOnClick(LikeVideoCardBinding binding, final LikeVideo likeVideo, final int position, final int videoId) { //点击分享 final String shareText = likeVideo.getTitle() + likeVideo.getPlayUrl() + mContext.getString(R.string.share_from); binding.ivShare.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ShareUtil.share(mContext, shareText); } }); //点击删除item binding.ivClose.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { deleteListener.onDelete(position, videoId); } }); //主页 binding.headIcon.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { IntentManager.fromPersonalToAuthor(mContext, likeVideo); } }); //点击下载 } public void updateStateLoad(boolean loading) { if (loading) { this.mState = LOAD_MORE; }else { this.mState = NO_MORE; } } public boolean isLoading() { if (this.mState == LOAD_MORE) { return true; } else return false; } public void hideLoading() { mFooterBinding.loading.hide(); } } ================================================ FILE: app/src/main/java/com/example/discover/adapter/MyFragmentPagerAdapter.java ================================================ package com.example.discover.adapter; import android.content.Context; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import java.util.List; /** * Created by Administrator on 2017/12/5 0005. */ public class MyFragmentPagerAdapter extends FragmentPagerAdapter { private List mFragmentList; private List mTitleList; public MyFragmentPagerAdapter(FragmentManager fm) { super(fm); } public MyFragmentPagerAdapter(FragmentManager fm, List list) { super(fm); mFragmentList = list; } public MyFragmentPagerAdapter(FragmentManager fm, List list, List titleList) { super(fm); mFragmentList = list; mTitleList = titleList; } @Override public Fragment getItem(int position) { return mFragmentList.get(position); } @Override public int getCount() { return mFragmentList.size(); } @Override public CharSequence getPageTitle(int position) { if (mTitleList != null) { return mTitleList.get(position); } else return ""; } } ================================================ FILE: app/src/main/java/com/example/discover/adapter/PopReplyAdapter.java ================================================ package com.example.discover.adapter; import android.databinding.DataBindingUtil; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.ViewGroup; import com.example.discover.R; import com.example.discover.bean.DetailBean.ReplyList; import com.example.discover.databinding.ItemReplyBinding; import java.util.List; /** * Created by monkeyWiiu on 2018/2/1. */ public class PopReplyAdapter extends RecyclerView.Adapter { private List datas; public PopReplyAdapter(List datas) { this.datas = datas; } @Override public Holder onCreateViewHolder(ViewGroup parent, int viewType) { return new Holder(parent, R.layout.item_reply); } @Override public void onBindViewHolder(Holder holder, int position) { holder.replyBinding.setReply(datas.get(position)); holder.replyBinding.executePendingBindings(); } @Override public int getItemCount() { return datas.size(); } public class Holder extends RecyclerView.ViewHolder { public ItemReplyBinding replyBinding; public Holder(ViewGroup parent, int layoutId) { super(DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),layoutId, parent, false).getRoot()); replyBinding = DataBindingUtil.getBinding(itemView); } } } ================================================ FILE: app/src/main/java/com/example/discover/adapter/ReplyAdapter.java ================================================ package com.example.discover.adapter; import android.databinding.DataBindingUtil; import android.support.v7.widget.RecyclerView; import android.text.format.DateUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.bumptech.glide.Glide; import com.example.discover.R; import com.example.discover.bean.DetailBean.ReplyList; import com.example.discover.databinding.ItemReplyBinding; import java.util.List; /** * Created by monkeyWiiu on 2018/1/30. */ public class ReplyAdapter extends RecyclerView.Adapter { private final static int HEADER = 0; private final static int REPLY = 1; private View description; private List datas; public ReplyAdapter(List data, View description) { datas = data; this.description = description; } @Override public int getItemViewType(int position) { if (position == 0) { return HEADER; } else return REPLY; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case HEADER: return new SimpleViewHolder(description); case REPLY: return new Holder(parent, R.layout.item_reply); default: return null; } } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (getItemViewType(position) == REPLY) { Holder replyHolder = (Holder)holder; replyHolder.replyBinding.setReply(datas.get(position -1)); replyHolder.replyBinding.executePendingBindings(); } } @Override public int getItemCount() { int count = 1; if (datas.size() > 0) count += datas.size(); return count; } public class Holder extends RecyclerView.ViewHolder { public ItemReplyBinding replyBinding; public Holder(ViewGroup parent, int layoutId) { super(DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),layoutId, parent, false).getRoot()); replyBinding = DataBindingUtil.getBinding(itemView); } } static class SimpleViewHolder extends RecyclerView.ViewHolder { public SimpleViewHolder(View itemView) { super(itemView); } } } ================================================ FILE: app/src/main/java/com/example/discover/adapter/ResultAdapter.java ================================================ package com.example.discover.adapter; import android.app.Activity; import android.app.ActivityOptions; import android.content.Context; import android.content.Intent; import android.databinding.DataBindingUtil; import android.support.v7.widget.RecyclerView; import android.util.Pair; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.RelativeLayout; import android.widget.TextView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.example.discover.R; import com.example.discover.VideoDetailActivity; import com.example.discover.bean.DetailBean.ItemList; import com.example.discover.databinding.CategoryCardBinding; import com.example.discover.utils.DebugUtil; import com.example.discover.utils.DensityUtil; import com.example.discover.utils.IntentManager; import com.jakewharton.rxbinding2.view.RxView; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.zip.Inflater; import io.reactivex.functions.Consumer; /** * Created by monkeyWiiu on 2018/1/29. */ public class ResultAdapter extends RecyclerView.Adapter { private List lists ; private Activity mContext; public ResultAdapter(Activity context, List lists) { this.mContext = context; this.lists = lists; } @Override public Holder onCreateViewHolder(ViewGroup parent, int viewType) { return new Holder(parent, R.layout.category_card); } @Override public void onBindViewHolder(final Holder holder, final int position) { holder.itemViewBinding.setItemList(lists.get(position)); //当数据改变时,binding会在下一帧去改变数据,如果我们需要立即改变,就去调用executePendingBindings方法。 holder.itemViewBinding.executePendingBindings(); RxView.clicks(holder.itemViewBinding.videoAlbum) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(new Consumer() { @Override public void accept(Object o) throws Exception { IntentManager.toVideoDetailActivity(mContext, lists.get(position), holder.itemViewBinding.videoAlbum); } }); } @Override public int getItemCount() { return lists.size(); } public class Holder extends RecyclerView.ViewHolder { private CategoryCardBinding itemViewBinding; private Holder(ViewGroup parent, int layoutId) { super(DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),layoutId, parent, false).getRoot()); itemViewBinding = DataBindingUtil.getBinding(itemView); RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, DensityUtil.dip2px(200)); itemViewBinding.videoAlbum.setLayoutParams(layoutParams); DebugUtil.debug("rerere", "bbb"); } } } ================================================ FILE: app/src/main/java/com/example/discover/adapter/SearchRecyclerAdapter.java ================================================ package com.example.discover.adapter; import android.content.Context; import android.view.ViewGroup; import com.example.discover.R; import com.example.discover.base.baseadapter.BaseRecyclerAdapter; import com.example.discover.base.baseadapter.BaseViewHolder; import com.example.discover.bean.DetailBean.ItemList; import com.example.discover.bean.DetailBean.SectionList; import com.example.discover.databinding.RecommendAuthorBinding; import com.example.discover.databinding.RecommendCategoryBinding; import com.example.discover.utils.DebugUtil; import java.util.List; /** * Created by monkeyWiiu on 2018/1/18. */ public class SearchRecyclerAdapter extends BaseRecyclerAdapter { private static int TYPE_AUTHOR = 0; private static int TYPE_CATEGORY = 1; public SearchRecyclerAdapter(Context context) { super(context); } @Override public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == TYPE_AUTHOR) { return new AuthorBindingHolder(parent, R.layout.recommend_author); } else if (viewType == TYPE_CATEGORY) { return new CategoryBindingHolder(parent, R.layout.recommend_category); } else { return null; } } @Override public int getItemViewType(int position) { if (position == 0) { return TYPE_AUTHOR; } else { return TYPE_CATEGORY; } } public class AuthorBindingHolder extends BaseViewHolder, RecommendAuthorBinding>{ public AuthorBindingHolder(ViewGroup parent, int layoutId) { super(parent, layoutId); } @Override public void fillHolder(List object, int position) { DebugUtil.debug("objjt", object.size() + ""); itemViewBinding.setData(object); } } public class CategoryBindingHolder extends BaseViewHolder { private CategoryBindingHolder(ViewGroup parent, int layoutId) { super(parent, layoutId); } @Override public void fillHolder(SectionList object, int position) { if (object.getItemList().size() > 0) { itemViewBinding.tvCategory.setText(object.getItemList().get(0).getData().getCategory()); } itemViewBinding.setData(object.getItemList()); } } @Override public int getItemCount() { return mData.size(); } } ================================================ FILE: app/src/main/java/com/example/discover/adapter/SearchTagAdapter.java ================================================ package com.example.discover.adapter; import android.content.Context; import android.content.Intent; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; import com.example.discover.R; import com.example.discover.ResultActivity; import com.example.discover.SearchActivity; import com.example.discover.base.baseadapter.BaseRecyclerAdapter; import com.example.discover.base.baseadapter.BaseViewHolder; import com.example.discover.bean.DetailBean.Data; import com.example.discover.bean.LitePalBean.SearchTag; import com.example.discover.databinding.SearchTagBinding; import com.example.discover.databinding.TagHeaderNewBinding; import com.example.discover.databinding.TagHeaderRecoBinding; import com.example.discover.utils.DebugUtil; import com.zhy.view.flowlayout.TagFlowLayout; import org.litepal.crud.DataSupport; import java.util.List; /** * Created by monkeyWiiu on 2018/1/28. */ public class SearchTagAdapter extends BaseRecyclerAdapter { private static int HEADER_ONE = 0; private static int HEADER_TWO = 1; private static int TAG = 3; private onItemClickListener itemClickListener; public interface onItemClickListener { void onItemClick(String s); } public void setItemClickListener(onItemClickListener listener) { this.itemClickListener = listener; } public SearchTagAdapter(Context context) { super(context); } @Override public int getItemViewType(int position) { if ("new".equals(mData.get(position))) { return HEADER_ONE; } else if ("recommend".equals(mData.get(position))) { return HEADER_TWO; }else { return TAG; } } @Override public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == HEADER_ONE) { return new HeaderOneHolder(parent, R.layout.tag_header_new); } else if (viewType == TAG) { return new SearchTagHolder(parent, R.layout.search_tag); } else if (viewType == HEADER_TWO) { return new HeaderTwoHolder(parent, R.layout.tag_header_reco); } return null; } public class HeaderOneHolder extends BaseViewHolder { private HeaderOneHolder(ViewGroup parent, int layoutId) { super(parent, layoutId); } @Override public void fillHolder(Object object, int position) { } } public class HeaderTwoHolder extends BaseViewHolder { private HeaderTwoHolder(ViewGroup parent, int layoutId) { super(parent, layoutId); } @Override public void fillHolder(Object object, int position) { } } public class SearchTagHolder extends BaseViewHolder { private SearchTagHolder(ViewGroup parent, int layoutId) { super(parent, layoutId); } @Override public void fillHolder(final String object, final int position) { itemViewBinding.tvTag.setText(object); if (position < DataSupport.count(SearchTag.class) + 1) { DebugUtil.debug("tagposition", position + "//" + object); itemViewBinding.delete.setVisibility(View.VISIBLE); itemViewBinding.delete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { delete(position); DataSupport.deleteAll(SearchTag.class, "tag = ?", object); if (DataSupport.count(SearchTag.class) == 0) { delete(0); } } }); } else { itemViewBinding.delete.setVisibility(View.GONE); } itemViewBinding.itemTag.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { itemClickListener.onItemClick(object); } }); } } @Override public int getItemCount() { return mData.size(); } } ================================================ FILE: app/src/main/java/com/example/discover/adapter/SelectTypeRecyclerAdapter.java ================================================ package com.example.discover.adapter; import android.content.Context; import android.support.v7.widget.CardView; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.example.discover.R; import com.example.discover.app.Constant; import com.example.discover.view.CustomView.LabelView; import java.util.List; /** * Created by monkeyWiiu on 2018/1/13. */ public class SelectTypeRecyclerAdapter extends RecyclerView.Adapter { private List mLabelList; private Context mContext; private ItemClickListener mListener; public interface ItemClickListener { void onLongItemLClick(int position); } public void setItemCLickListener(ItemClickListener listener) { this.mListener = listener; } public SelectTypeRecyclerAdapter(List list, Context context) { this.mLabelList = list; mContext = context; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(mContext).inflate(R.layout.select_label_view, parent, false); MyViewHolder viewHolder = new MyViewHolder(view); return viewHolder; } @Override public void onBindViewHolder(MyViewHolder holder, final int position) { holder.labelView.setCardBackgroundColor((int) Constant.LabelMap.get(mLabelList.get(position))); holder.textLabel.setText(mLabelList.get(position)); holder.labelView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { mListener.onLongItemLClick(position); return false; } }); } @Override public int getItemCount() { return mLabelList.size(); } /** * 拖拽移位 * */ /*@Override public void onItemMove(int fromPosition, int toPosition) { String prev = mLabelList.remove(fromPosition); mLabelList.add(toPosition > fromPosition ? toPosition - 1 : toPosition, prev); notifyItemMoved(fromPosition, toPosition); } @Override public void onItemDismiss(int position) { }*/ public class MyViewHolder extends RecyclerView.ViewHolder { private TextView textLabel; private CardView labelView; public MyViewHolder(View itemView) { super(itemView); textLabel = itemView.findViewById(R.id.tv_label); labelView = itemView.findViewById(R.id.cv_select_label); } } } ================================================ FILE: app/src/main/java/com/example/discover/adapter/VideoRecyclerAdapter.java ================================================ package com.example.discover.adapter; import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import com.bumptech.glide.Glide; import com.example.discover.R; import com.example.discover.app.Constant; import com.example.discover.base.baseadapter.BaseRecyclerAdapter; import com.example.discover.base.baseadapter.BaseViewHolder; import com.example.discover.bean.DetailBean.ItemList; import com.example.discover.databinding.FooterItemVideoBinding; import com.example.discover.databinding.VideoCardBinding; import com.example.discover.model.HotVideoModel; import com.example.discover.utils.DebugUtil; import com.example.discover.utils.DensityUtil; import com.example.discover.utils.IntentManager; import com.example.discover.utils.LitePalUtil; import com.example.discover.utils.ShareUtil; import com.example.discover.view.CustomView.ReplyPopupWindow; import com.jakewharton.rxbinding2.view.RxView; import java.util.LinkedHashMap; import java.util.concurrent.TimeUnit; import cn.jzvd.JZVideoPlayer; import cn.jzvd.JZVideoPlayerStandard; import io.reactivex.functions.Consumer; /** * Created by Administrator on 2017/12/14 0014. */ public class VideoRecyclerAdapter extends BaseRecyclerAdapter { private boolean isAuthor = false; private int LOAD_MORE = 1; private final static int NO_MORE = 0; private final static int STATE_NORMAL = -1; private final static int TYPE_FOOTER = 3; private final static int TYPE_CONTENT = 2; private int mState = STATE_NORMAL; private int width = DensityUtil.getScreenWidth(mContext);//屏宽 private FooterItemVideoBinding mFooterBinding; public VideoRecyclerAdapter(Context context) { super(context); } public void setAuthor(boolean isAuthor) { this.isAuthor = isAuthor; } @Override public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == TYPE_CONTENT) { return new VideoHolder(parent, R.layout.video_card); }else { return new FooterHolder(parent, R.layout.footer_item_video); } } @Override public int getItemViewType(int position) { if (position + 1 == getItemCount()) { DebugUtil.debug("footer", "true"); return TYPE_FOOTER; } else { return TYPE_CONTENT; } } public void updateStateLoad(boolean loading) { if (loading) { this.mState = LOAD_MORE; }else { this.mState = NO_MORE; } } public boolean isLoading() { if (this.mState == LOAD_MORE) { return true; } else return false; } public void hideLoading() { mFooterBinding.loading.hide(); } public class VideoHolder extends BaseViewHolder { private VideoHolder(ViewGroup parent, int layoutId) { super(parent, layoutId); } @Override public void fillHolder(final ItemList list, final int position) { //填充基础数据 //int videoSize = 0; itemViewBinding.videoTitle.setText(list.getData().getTitle()); itemViewBinding.videoDesc.setText(list.getData().getDescription()); if (list.getData().getCover() != null) { Glide.with(mContext).load(list.getData().getCover().getDetail()) .crossFade(800) .placeholder(R.drawable.cross_image) .error(R.drawable.cross_image) .into(itemViewBinding.jzVideoPlayer.thumbImageView); } if (!isAuthor && list.getData().getAuthor() != null) { Glide.with(mContext).load(list.getData().getAuthor().getIcon()) .error(R.drawable.cross_image) .into(itemViewBinding.headIcon); } else { itemViewBinding.headIcon.setVisibility(View.GONE); } itemViewBinding.tvLabel.setText(list.getData().getCategory()); itemViewBinding.cvLabel.setCardBackgroundColor((int)Constant.LabelMap.get(list.getData().getCategory())); //填充播放链接,playinfo有时候没有,playurl常有 if (list.getData().getPlayinfo().size() > 0) { //设置窗口比列 int x = list.getData().getPlayinfo().get(0).getWidth();//获取视频的width int y = list.getData().getPlayinfo().get(0).getHeight();//获取视频的height int height = width * y / x; //根据视频比列获得视频控件的高 LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, height); itemViewBinding.jzVideoPlayer.setLayoutParams(layoutParams); //videoSize = list.getData().getPlayinfo().get(0).getUrlList().get(2).getSize()/1024/1024; //itemViewBinding.tvVideoSize.setText("视频大小约" + videoSize+ "MB"); if (list.getData().getPlayinfo().size() == 1) { //标清||高清 itemViewBinding.jzVideoPlayer.setUp(list.getData().getPlayinfo().get(0).getUrlList().get(2).getUrl(), JZVideoPlayer.SCREEN_WINDOW_NORMAL, ""); } else if (list.getData().getPlayinfo().size() > 1) { //标清&&高清 LinkedHashMap map = new LinkedHashMap(); Object[] objects = new Object[1]; for (int i = 0; i < list.getData().getPlayinfo().size(); i ++) { map.put(list.getData().getPlayinfo().get(i).getName(), list.getData().getPlayinfo().get(i).getUrlList().get(2).getUrl()); } objects[0] = map; itemViewBinding.jzVideoPlayer.setUp(objects , 0, JZVideoPlayerStandard.SCREEN_WINDOW_NORMAL, ""); } } else { //防止playinfo没有数据时播放地址无效 if (list.getData().getPlayUrl() != null) { itemViewBinding.jzVideoPlayer.setUp(list.getData().getPlayUrl(), JZVideoPlayer.SCREEN_WINDOW_NORMAL, ""); } } if ("true".equals(list.getTag())) { itemViewBinding.ivCollect.setImageDrawable(mContext.getResources().getDrawable(R.drawable.collected)); } else if (list.getTag() == null) { itemViewBinding.ivCollect.setImageDrawable(mContext.getResources().getDrawable(R.drawable.collect)); } //设置点击事件 setOnClick(list, itemViewBinding, position, 0); } } public class FooterHolder extends BaseViewHolder { public FooterHolder(ViewGroup parent, int layoutId) { super(parent, layoutId); } @Override public void fillHolder(Object object, int position) { DebugUtil.debug("loadingm", "11"); mFooterBinding = itemViewBinding; itemViewBinding.loading.show(); } } private void setOnClick(final ItemList list, final VideoCardBinding binding, final int position, final int vSize) { boolean isCollect = false; final String shareText = list.getData().getTitle() + list.getData().getWebUrl().getForWeibo() + mContext.getString(R.string.share_from); //点击分享 RXVIEW binding.ivShare.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ShareUtil.share(mContext, shareText); } }); //展开评论 RxView.clicks(binding.ivComment) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(new Consumer() { @Override public void accept(Object o) throws Exception { ReplyPopupWindow replyPopupWindow = new ReplyPopupWindow(mContext, list.getData().getId()); replyPopupWindow.showPopupWindow(binding.ivComment); } }); //点击收藏 binding.ivCollect.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { binding.ivCollect.setImageDrawable(mContext.getResources().getDrawable(R.drawable.collect)); if (list.getTag() == null) { binding.ivCollect.setImageDrawable(mContext.getResources().getDrawable(R.drawable.collected)); //存入数据库 LitePalUtil.addVideoToFavor(list.getData().getId(), list.getData().getTitle(), list.getData().getDescription(), list.getData().getPlayUrl(), list.getData().getCover().getDetail(), list.getData().getAuthor().getName(), list.getData().getAuthor().getId(), list.getData().getAuthor().getIcon(), list.getData().getAuthor().getDescription(), (int)Constant.LabelMap.get(list.getData().getCategory()), list.getData().getCategory(), vSize); list.setTag("true"); } else if ("true".equals(list.getTag())) { binding.ivCollect.setImageDrawable(mContext.getResources().getDrawable(R.drawable.collect)); LitePalUtil.deleteVideoFromFavor(list.getData().getId()); list.setTag(null); } } }); //跳转主页 RxView.clicks(binding.headIcon) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(new Consumer() { @Override public void accept(Object o) throws Exception { IntentManager.fromDetailtoAuthor(mContext, list); } }); } } ================================================ FILE: app/src/main/java/com/example/discover/adapter/WelfareAdapter.java ================================================ package com.example.discover.adapter; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGridLayoutManager; import android.view.View; import android.view.ViewGroup; import com.example.discover.R; import com.example.discover.base.baseadapter.BaseRecyclerAdapter; import com.example.discover.base.baseadapter.BaseViewHolder; import com.example.discover.bean.GankBean; import com.example.discover.databinding.FooterItemVideoBinding; import com.example.discover.databinding.ItemWelfareBinding; import com.example.discover.utils.DebugUtil; /** * Created by monkeyWiiu on 2018/2/3. */ public class WelfareAdapter extends BaseRecyclerAdapter { private int LOAD_MORE = 1; private final static int TYPE_FOOTER = 3; private final static int TYPE_CONTENT = 2; private final static int STATE_NORMAL = -1; private final static int NO_MORE = 0; private int mState = STATE_NORMAL; private FooterItemVideoBinding mFooterBinding; public WelfareAdapter(Context context) { super(context); } @Override public int getItemViewType(int position) { if (position + 1 == getItemCount()) { DebugUtil.debug("footer", "true"); return TYPE_FOOTER; } else { return TYPE_CONTENT; } } @Override public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == TYPE_CONTENT) { return new ContentHolder(parent, R.layout.item_welfare); }else { return new FooterHolder(parent, R.layout.footer_item_video); } } public class ContentHolder extends BaseViewHolder { public ContentHolder(ViewGroup parent, int layoutId) { super(parent, layoutId); } @Override public void fillHolder(final GankBean.ResultBean object, final int position) { itemViewBinding.setData(object); itemViewBinding.executePendingBindings(); itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (listener != null) { listener.onClick(itemViewBinding.ivWelfare, object, position); } } }); } } public class FooterHolder extends BaseViewHolder { public FooterHolder(ViewGroup parent, int layoutId) { super(parent, layoutId); } @Override public void fillHolder(Object object, int position) { DebugUtil.debug("loadingm", "11"); mFooterBinding = itemViewBinding; itemViewBinding.loading.show(); } } public boolean isLoading() { if (this.mState == LOAD_MORE) { return true; } else return false; } public void hideLoading() { mFooterBinding.loading.hide(); } public void updateStateLoad(boolean loading) { if (loading) { this.mState = LOAD_MORE; }else { this.mState = NO_MORE; } } @Override public void onViewAttachedToWindow(BaseViewHolder holder) { super.onViewAttachedToWindow(holder); if (isStaggeredGridLayout(holder)) { handleLayoutIfStaggeredGridLayout(holder, holder.getLayoutPosition()); } } private boolean isStaggeredGridLayout(RecyclerView.ViewHolder holder) { ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams(); if (layoutParams != null && layoutParams instanceof StaggeredGridLayoutManager.LayoutParams) { return true; } return false; } protected void handleLayoutIfStaggeredGridLayout(RecyclerView.ViewHolder holder, int position) { if (isFooter(position)) { StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) holder.itemView.getLayoutParams(); p.setFullSpan(true); } } public boolean isFooter(int position) { if (position + 1 == getItemCount()) { DebugUtil.debug("footer", "true"); return true; } else return false; } } ================================================ FILE: app/src/main/java/com/example/discover/app/Constant.java ================================================ package com.example.discover.app; import com.example.discover.R; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; /** * Created by Administrator on 2017/12/12 0012. */ public class Constant { public static final String EYE_VIDEO = "eye_video"; public static final String EYE_FIND = "eye_find"; public static final String GANK_WELFARE = "gank_welfare"; public static final HashMap LabelMap = new HashMap() {{ put("萌宠", DiscoverApplication.getDiscoverApplication().getBaseContext().getResources().getColor(R.color.colorLabelCre)); put("搞笑", DiscoverApplication.getDiscoverApplication().getBaseContext().getResources().getColor(R.color.colorLabelMusic)); put("游戏", DiscoverApplication.getDiscoverApplication().getBaseContext().getResources().getColor(R.color.colorLabelTravel)); put("科普", DiscoverApplication.getDiscoverApplication().getBaseContext().getResources().getColor(R.color.colorLabelScience)); put("集锦", DiscoverApplication.getDiscoverApplication().getBaseContext().getResources().getColor(R.color.colorLabelFunny)); put("生活", DiscoverApplication.getDiscoverApplication().getBaseContext().getResources().getColor(R.color.colorLabelFashion)); put("综艺", DiscoverApplication.getDiscoverApplication().getBaseContext().getResources().getColor(R.color.colorLabelSport)); put("开胃", DiscoverApplication.getDiscoverApplication().getBaseContext().getResources().getColor(R.color.colorLabelAnim)); put("预告", DiscoverApplication.getDiscoverApplication().getBaseContext().getResources().getColor(R.color.colorLabelAd)); put("广告", DiscoverApplication.getDiscoverApplication().getBaseContext().getResources().getColor(R.color.colorLabelAppetizing)); put("记录", DiscoverApplication.getDiscoverApplication().getBaseContext().getResources().getColor(R.color.colorLabelLife)); put("时尚", DiscoverApplication.getDiscoverApplication().getBaseContext().getResources().getColor(R.color.colorLabelDrama)); put("创意", DiscoverApplication.getDiscoverApplication().getBaseContext().getResources().getColor(R.color.colorLabelNotice)); put("运动", DiscoverApplication.getDiscoverApplication().getBaseContext().getResources().getColor(R.color.colorLabelVariety)); put("旅行", DiscoverApplication.getDiscoverApplication().getBaseContext().getResources().getColor(R.color.colorLabelRecord)); put("剧情", DiscoverApplication.getDiscoverApplication().getBaseContext().getResources().getColor(R.color.colorLabelGame)); put("动画", DiscoverApplication.getDiscoverApplication().getBaseContext().getResources().getColor(R.color.colorLabelPet)); put("音乐", DiscoverApplication.getDiscoverApplication().getBaseContext().getResources().getColor(R.color.colorLabelVariety)); }}; public static final List videoTypeList = new ArrayList() {{ add("萌宠"); add("搞笑"); add("游戏"); add("科普"); add("集锦"); add("生活"); add("综艺"); add("开胃"); add("预告"); add("广告"); add("记录"); add("时尚"); add("创意"); add("运动"); add("旅行"); add("剧情"); add("动画"); add("音乐"); }}; } ================================================ FILE: app/src/main/java/com/example/discover/app/DiscoverApplication.java ================================================ package com.example.discover.app; import android.app.Application; import android.content.Context; import com.example.discover.utils.DebugUtil; import com.example.http.HttpUtils; import com.squareup.haha.perflib.Instance; import com.squareup.leakcanary.LeakCanary; import com.squareup.leakcanary.RefWatcher; import org.litepal.LitePal; /** * Created by Administrator on 2017/12/9 0009. */ public class DiscoverApplication extends Application { private static DiscoverApplication discoverApplication; private RefWatcher refWatcher; public static DiscoverApplication getDiscoverApplication() { return discoverApplication; } @Override public void onCreate() { super.onCreate(); LitePal.initialize(this); discoverApplication = this; HttpUtils.getInstance().init(this, DebugUtil.DEBUG); refWatcher = LeakCanary.install(this); } public static RefWatcher getRefWatcher(Context context) { DiscoverApplication application = (DiscoverApplication) context.getApplicationContext(); return application.refWatcher; } } ================================================ FILE: app/src/main/java/com/example/discover/base/BaseFragment.java ================================================ package com.example.discover.base; import android.databinding.DataBindingUtil; import android.databinding.ViewDataBinding; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.RelativeLayout; import com.example.discover.R; import com.jakewharton.rxbinding2.view.RxView; import com.trello.rxlifecycle2.components.support.RxFragment; import com.wang.avi.AVLoadingIndicatorView; import java.util.concurrent.TimeUnit; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.functions.Consumer; /** * Created by Administrator on 2017/12/5 0005. */ public abstract class BaseFragment extends RxFragment { public SV bindingView; public RelativeLayout container; public AVLoadingIndicatorView avLoading; private RelativeLayout rlLoading; private RelativeLayout rlError; public boolean isVisibile = false; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View ll = inflater.inflate(R.layout.fragment_base, null); bindingView = DataBindingUtil.inflate(getActivity().getLayoutInflater(), setContentView(), null, false); RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT); bindingView.getRoot().setLayoutParams(params); container = ll.findViewById(R.id.container); container.addView(bindingView.getRoot()); return ll; } @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); if (getUserVisibleHint()) { isVisibile = true; onVisible(); } else { isVisibile = false; } } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); avLoading = (AVLoadingIndicatorView) getView(R.id.av_loading); rlLoading = (RelativeLayout) getView(R.id.rl_loading); rlError = (RelativeLayout) getView(R.id.rl_error); showLoading(); RxView.clicks(rlError) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(new Consumer() { @Override public void accept(Object o) throws Exception { Refresh(); } }); } public View getView(int id) { return getView().findViewById(id); } public void onVisible() { loadData(); } public void onInvisible(){} protected void loadData(){}; public abstract int setContentView(); @Override public void onDestroy() { super.onDestroy(); } /** * 加载中的状态 */ protected void showLoading() { if (rlLoading.getVisibility() == View.GONE) { rlLoading.setVisibility(View.VISIBLE); } if (rlError.getVisibility() == View.VISIBLE) { rlError.setVisibility(View.GONE); } } /** * 加载完成的状态 */ protected void showContentView() { if (rlError.getVisibility() == View.VISIBLE) { rlLoading.setVisibility(View.GONE); } if (rlLoading.getVisibility() == View.VISIBLE) { rlLoading.setVisibility(View.GONE); } } /** * 加载失败 */ protected void Error() { if (rlError.getVisibility() == View.GONE) { rlError.setVisibility(View.VISIBLE); } } /** * 加载失败重新加载 */ protected void Refresh() { } /* //显示loading public void showLoading() { avLoading.show(); } //隐藏loading public void stopLoading() { avLoading.hide(); } */ } ================================================ FILE: app/src/main/java/com/example/discover/base/baseadapter/BaseRecyclerAdapter.java ================================================ package com.example.discover.base.baseadapter; import android.content.Context; import android.support.v7.widget.RecyclerView; import com.example.discover.utils.DebugUtil; import java.util.ArrayList; import java.util.List; /** * Created by Administrator on 2017/12/13 0013. */ public abstract class BaseRecyclerAdapter extends RecyclerView.Adapter { protected OnItemClickListener listener; protected OnItemLongClickListener onItemLongClickListener; public List mData = new ArrayList<>(); public Context mContext; public BaseRecyclerAdapter(Context context) { mContext = context; } @Override public void onBindViewHolder(BaseViewHolder holder, int position) { DebugUtil.debug("position11", position + ""); if (position == mData.size()) { holder.baseFillHolder(null, position); return; } holder.baseFillHolder(mData.get(position), position); } @Override public int getItemCount() { //考虑有footer的情况 return mData.size() + 1; } public void addAll(List data) { this.mData.addAll(data); DebugUtil.debug("listSize", data.size() + ""); } public void add(T data) { this.mData.add(data); } public void clear() { this.mData.clear(); } public void delete(int position) { if (this.mData != null && this.mData.size() > position) { this.mData.remove(position); } notifyItemRemoved(position); notifyItemRangeChanged(position, mData.size() - position); } public void setOnItemClickListener(OnItemClickListener listener) { this.listener = listener; } public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) { this.onItemLongClickListener = onItemLongClickListener; } } ================================================ FILE: app/src/main/java/com/example/discover/base/baseadapter/BaseViewHolder.java ================================================ package com.example.discover.base.baseadapter; import android.databinding.DataBindingUtil; import android.databinding.ViewDataBinding; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.ViewGroup; /** * Created by Administrator on 2017/12/13 0013. */ public abstract class BaseViewHolder extends RecyclerView.ViewHolder { public H itemViewBinding; public BaseViewHolder(ViewGroup parent, int layoutId) { super(DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),layoutId, parent, false).getRoot()); itemViewBinding = DataBindingUtil.getBinding(itemView); } public abstract void fillHolder(T object, int position); /** * 当数据改变时,binding会在下一帧去改变数据,如果我们需要立即改变,就去调用executePendingBindings方法。 */ public void baseFillHolder(T object, int position) { fillHolder(object, position); itemViewBinding.executePendingBindings(); } } ================================================ FILE: app/src/main/java/com/example/discover/base/baseadapter/OnItemClickListener.java ================================================ package com.example.discover.base.baseadapter; import android.view.View; /** * Created by jingbin on 2016/3/2. */ public interface OnItemClickListener { public void onClick(View view, T t, int position); } ================================================ FILE: app/src/main/java/com/example/discover/base/baseadapter/OnItemLongClickListener.java ================================================ package com.example.discover.base.baseadapter; /** * Created by jingbin on 16/7/4. */ public interface OnItemLongClickListener { public void onLongClick(T t, int position); } ================================================ FILE: app/src/main/java/com/example/discover/bean/AuthorDetailBean.java ================================================ package com.example.discover.bean; import com.example.discover.bean.DetailBean.ItemList; import java.io.Serializable; import java.util.List; /** * Created by monkeyWiiu on 2018/1/25. */ public class AuthorDetailBean implements Serializable { private List itemList; public List getItemList() { return itemList; } public void setItemList(List itemList) { this.itemList = itemList; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/DetailBean/ACacheFindList.java ================================================ package com.example.discover.bean.DetailBean; import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * Created by monkeyWiiu on 2018/1/18. */ public class ACacheFindList implements Serializable { private List scrollCardSection = new ArrayList<>() ; private List videoSection = new ArrayList<>() ; private List authorSection = new ArrayList<>() ; public List getScrollCardSection() { return scrollCardSection; } public void setScrollCardSection(List scrollCardSection) { this.scrollCardSection = scrollCardSection; } public List getVideoSection() { return videoSection; } public void setVideoSection(List videoSection) { this.videoSection = videoSection; } public List getAuthorSection() { return authorSection; } public void setAuthorSection(List authorSection) { this.authorSection = authorSection; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/DetailBean/Author.java ================================================ package com.example.discover.bean.DetailBean; import java.io.Serializable; /** * Created by monkeyWiiu on 2018/1/17. */ public class Author implements Serializable { public int id; public String icon; public String name; public String description; public int videoNum; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getIcon() { return icon; } public void setIcon(String icon) { this.icon = icon; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public int getVideoNum() { return videoNum; } public void setVideoNum(int videoNum) { this.videoNum = videoNum; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/DetailBean/CategoryInfo.java ================================================ package com.example.discover.bean.DetailBean; import java.io.Serializable; /** * Created by monkeyWiiu on 2018/1/17. */ public class CategoryInfo implements Serializable { public String dataType; public int id; public String name; public String description; public String headerImage; public String getDataType() { return dataType; } public void setDataType(String dataType) { this.dataType = dataType; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getHeaderImage() { return headerImage; } public void setHeaderImage(String headerImage) { this.headerImage = headerImage; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/DetailBean/Cover.java ================================================ package com.example.discover.bean.DetailBean; import java.io.Serializable; /** * Created by monkeyWiiu on 2018/1/17. */ public class Cover implements Serializable { public String feed; public String detail; public String blurred; public String getFeed() { return feed; } public void setFeed(String feed) { this.feed = feed; } public String getDetail() { return detail; } public void setDetail(String detail) { this.detail = detail; } public String getBlurred() { return blurred; } public void setBlurred(String blurred) { this.blurred = blurred; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/DetailBean/Data.java ================================================ package com.example.discover.bean.DetailBean; import java.io.Serializable; import java.util.List; /** * Created by monkeyWiiu on 2018/1/17. */ public class Data implements Serializable { public String dataType; public int id; public String title; public String text; public String description; public String image; public String actionUrl; public boolean shade; public Cover cover; public String playUrl; public String category; public long duration; public Header header; public List itemList; public Author author; public String icon; public List tags; public List playInfo; public WebUrl webUrl; public int getId() { return id; } public String getActionUrl() { return actionUrl; } public String getDescription() { return description; } public String getTitle() { return title; } public String getIcon() { return icon; } public List getItemList() { return itemList; } public String getPlayUrl() { return playUrl; } public Author getAuthor() { return author; } public Cover getCover() { return cover; } public Header getHeader() { return header; } public long getDuration() { return duration; } public String getCategory() { return category; } public String getDataType() { return dataType; } public String getImage() { return image; } public String getText() { return text; } public List getPlayinfo() { return playInfo; } public WebUrl getWebUrl() { return webUrl; } public List getTags() { return tags; } public void setId(int id) { this.id = id; } public void setActionUrl(String actionUrl) { this.actionUrl = actionUrl; } public void setDescription(String description) { this.description = description; } public void setTitle(String title) { this.title = title; } public void setIcon(String icon) { this.icon = icon; } public void setItemList(List itemList) { this.itemList = itemList; } public void setPlayUrl(String playUrl) { this.playUrl = playUrl; } public void setAuthor(Author author) { this.author = author; } public void setCategory(String category) { this.category = category; } public void setCover(Cover cover) { this.cover = cover; } public void setDataType(String dataType) { this.dataType = dataType; } public void setDuration(long duration) { this.duration = duration; } public void setHeader(Header header) { this.header = header; } public void setImage(String image) { this.image = image; } public void setShade(boolean shade) { this.shade = shade; } public void setText(String text) { this.text = text; } public void setPlayinfo(List list) { this.playInfo = list; } public void setWebUrl(WebUrl webUrl) { this.webUrl = webUrl; } public void setTags(List tags) { this.tags = tags; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/DetailBean/FindCategory.java ================================================ package com.example.discover.bean.DetailBean; import java.io.Serializable; import java.util.List; /** * Created by monkeyWiiu on 2018/1/17. */ public class FindCategory implements Serializable{ public CategoryInfo categoryInfo; public List sectionList; public CategoryInfo getCategoryInfo() { return categoryInfo; } public void setCategoryInfo(CategoryInfo categoryInfo) { this.categoryInfo = categoryInfo; } public List getSectionList() { return sectionList; } public void setSectionList(List sectionList) { this.sectionList = sectionList; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/DetailBean/Footer.java ================================================ package com.example.discover.bean.DetailBean; import java.io.Serializable; /** * Created by monkeyWiiu on 2018/1/17. */ public class Footer implements Serializable { public String type; public Data data; public String getType() { return type; } public void setType(String type) { this.type = type; } public Data getData() { return data; } public void setData(Data data) { this.data = data; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/DetailBean/Header.java ================================================ package com.example.discover.bean.DetailBean; import java.io.Serializable; /** * Created by monkeyWiiu on 2018/1/17. */ public class Header implements Serializable { public int id; public String icon; public String title; public String subTitle; public String description; public String actionUrl; public Data data; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getIcon() { return icon; } public void setIcon(String icon) { this.icon = icon; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getSubTitle() { return subTitle; } public void setSubTitle(String subTitle) { this.subTitle = subTitle; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getActionUrl() { return actionUrl; } public void setActionUrl(String actionUrl) { this.actionUrl = actionUrl; } public Data getData() { return data; } public void setData(Data data) { this.data = data; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/DetailBean/ItemList.java ================================================ package com.example.discover.bean.DetailBean; import java.io.Serializable; /** * Created by monkeyWiiu on 2018/1/17. */ public class ItemList implements Serializable{ private String type; private Data data; private String tag; public String getType() { return type; } public void setType(String type) { this.type = type; } public Data getData() { return data; } public void setData(Data data) { this.data = data; } public String getTag() { return tag; } public void setTag(String tag) { this.tag = tag; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/DetailBean/PlayInfo.java ================================================ package com.example.discover.bean.DetailBean; import java.io.Serializable; import java.util.List; /** * Created by monkeyWiiu on 2018/1/23. */ public class PlayInfo implements Serializable { /** * height : 720 * width : 1280 * urlList : [{"name":"aliyun","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=aliyun","size":14871277},{"name":"qcloud","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=qcloud","size":14871277},{"name":"ucloud","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=ucloud","size":14871277}] * name : 高清 * type : high * url : http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=aliyun */ private int height; private int width; private String name; private String type; private String url; private List urlList; public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } public int getWidth() { return width; } public void setWidth(int width) { this.width = width; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public List getUrlList() { return urlList; } public void setUrlList(List urlList) { this.urlList = urlList; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/DetailBean/Replies.java ================================================ package com.example.discover.bean.DetailBean; import java.io.Serializable; import java.util.List; /** * @author zsj */ public class Replies implements Serializable{ private List replyList; public List getReplyList() { return replyList; } public void setReplyList(List replyList) { this.replyList = replyList; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/DetailBean/ReplyList.java ================================================ package com.example.discover.bean.DetailBean; import java.io.Serializable; /** * @author zsj */ public class ReplyList implements Serializable { public long id; public int videoId; public String videoTitle; public int sequence; public String message; public long createTime; public User user; public int likeCount; public long getId() { return id; } public void setId(long id) { this.id = id; } public int getVideoId() { return videoId; } public void setVideoId(int videoId) { this.videoId = videoId; } public int getLikeCount() { return likeCount; } public void setLikeCount(int likeCount) { this.likeCount = likeCount; } public int getSequence() { return sequence; } public void setSequence(int sequence) { this.sequence = sequence; } public long getCreateTime() { return createTime; } public void setCreateTime(long createTime) { this.createTime = createTime; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String getVideoTitle() { return videoTitle; } public void setVideoTitle(String videoTitle) { this.videoTitle = videoTitle; } public void setUser(User user) { this.user = user; } public User getUser() { return user; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/DetailBean/SectionList.java ================================================ package com.example.discover.bean.DetailBean; import java.io.Serializable; import java.util.List; /** * Created by monkeyWiiu on 2018/1/17. */ public class SectionList implements Serializable { public int id; public String type; public Header header; public List itemList; public Footer footer; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getType() { return type; } public void setType(String type) { this.type = type; } public Header getHeader() { return header; } public void setHeader(Header header) { this.header = header; } public List getItemList() { return itemList; } public void setItemList(List itemList) { this.itemList = itemList; } public Footer getFooter() { return footer; } public void setFooter(Footer footer) { this.footer = footer; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/DetailBean/Tags.java ================================================ package com.example.discover.bean.DetailBean; import java.io.Serializable; /** * Created by monkeyWiiu on 2018/1/19. */ public class Tags implements Serializable { private String name; private String headerImage; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getHeaderImage() { return headerImage; } public void setHeaderImage(String headerImage) { this.headerImage = headerImage; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/DetailBean/UrlList.java ================================================ package com.example.discover.bean.DetailBean; import java.io.Serializable; /** * Created by monkeyWiiu on 2018/1/23. */ public class UrlList implements Serializable { /** * name : aliyun * url : http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=aliyun * size : 14871277 */ private String name; private String url; private int size; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/DetailBean/User.java ================================================ package com.example.discover.bean.DetailBean; import java.io.Serializable; /** * @author zsj */ public class User implements Serializable { public int uid; public String nickname; public String avatar; public int getUid() { return uid; } public void setUid(int uid) { this.uid = uid; } public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } public String getAvatar() { return avatar; } public void setAvatar(String avatar) { this.avatar = avatar; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/DetailBean/WebUrl.java ================================================ package com.example.discover.bean.DetailBean; import java.io.Serializable; /** * Created by monkeyWiiu on 2018/1/23. */ public class WebUrl implements Serializable { private String raw; private String forWeibo; public String getRaw() { return raw; } public void setRaw(String raw) { this.raw = raw; } public String getForWeibo() { return forWeibo; } public void setForWeibo(String forWeibo) { this.forWeibo = forWeibo; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/GankBean.java ================================================ package com.example.discover.bean; import java.io.Serializable; import java.util.List; /** * Created by monkeyWiiu on 2018/2/3. */ public class GankBean implements Serializable { private boolean error; /** * _id : 5832662b421aa929b0f34e99 * createdAt : 2016-11-21T11:12:43.567Z * desc : 深入Android渲染机制 * publishedAt : 2016-11-24T11:40:53.615Z * source : web * type : Android * url : http://blog.csdn.net/ccj659/article/details/53219288 * used : true * who : Chauncey */ private List results; public static class ResultBean implements Serializable { private String _id; private String createdAt; private String desc; private String publishedAt; private String source; private String type; private String url; private boolean used; private String who; private List images; public String get_id() { return _id; } public String getCreatedAt() { return createdAt; } public String getDesc() { return desc; } public String getPublishedAt() { return publishedAt; } public String getSource() { return source; } public String getType() { return type; } public String getUrl() { return url; } public boolean isUsed() { return used; } public String getWho() { return who; } @Override public String toString() { return "ResultsBean{" + "who='" + who + '\'' + ", used=" + used + ", url='" + url + '\'' + ", type='" + type + '\'' + ", source='" + source + '\'' + ", publishedAt='" + publishedAt + '\'' + ", desc='" + desc + '\'' + ", createdAt='" + createdAt + '\'' + ", _id='" + _id + '\'' + '}'; } public List getImages() { return images; } } public boolean isError() { return error; } public List getResults() { return results; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/HotEyeBean.java ================================================ package com.example.discover.bean; import com.example.discover.bean.DetailBean.ItemList; import java.io.Serializable; import java.util.List; /** * Created by Administrator on 2017/12/9 0009. */ public class HotEyeBean implements Serializable { private List itemList; public List getItemList() { return itemList; } public void setItemList(List itemList) { this.itemList = itemList; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/LitePalBean/Follow.java ================================================ package com.example.discover.bean.LitePalBean; import org.litepal.crud.DataSupport; /** * Created by monkeyWiiu on 2018/1/25. */ public class Follow extends DataSupport { private int id; public int authorId; public String authorName; public String authorDesc; public String iconUrl; private int backgroundColor; private String backgroundImage; public int getId() { return id; } public void setId(int id) { this.id = id; } public int getAuthorId() { return authorId; } public void setAuthorId(int authorId) { this.authorId = authorId; } public String getAuthorName() { return authorName; } public void setAuthorName(String authorName) { this.authorName = authorName; } public String getAuthorDesc() { return authorDesc; } public void setAuthorDesc(String authorDesc) { this.authorDesc = authorDesc; } public String getIconUrl() { return iconUrl; } public void setIconUrl(String iconUrl) { this.iconUrl = iconUrl; } public int getBackgroundColor() { return backgroundColor; } public void setBackgroundColor(int backgroundColor) { this.backgroundColor = backgroundColor; } public String getBackgroundImage() { return backgroundImage; } public void setBackgroundImage(String backgroundImage) { this.backgroundImage = backgroundImage; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/LitePalBean/LabelType.java ================================================ package com.example.discover.bean.LitePalBean; import org.litepal.crud.DataSupport; /** * Created by monkeyWiiu on 2018/1/13. */ public class LabelType extends DataSupport { private String type; public String getType() { return type; } public void setType(String type) { this.type = type; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/LitePalBean/LikeVideo.java ================================================ package com.example.discover.bean.LitePalBean; import org.litepal.crud.DataSupport; /** * Created by monkeyWiiu on 2017/12/31. * id : 不变,与表中数据绑定 */ public class LikeVideo extends DataSupport { private int id; private int videoId; private String title; private String description; private String playUrl; private String imageUrl; private String authorName; private int authorId; private String authorIcon; private String authorDesc; private int labelColor; private String labelText; private int size; public int getId() { return id; } public void setId(int id) { this.id = id; } public int getVideoId() { return videoId; } public void setVideoId(int videoId) { this.videoId = videoId; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getPlayUrl() { return playUrl; } public void setPlayUrl(String playUrl) { this.playUrl = playUrl; } public String getImageUrl() { return imageUrl; } public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; } public String getAuthorName() { return authorName; } public void setAuthorName(String auhtorName) { this.authorName = auhtorName; } public int getAuthorId() { return authorId; } public void setAuthorId(int auhtorId) { this.authorId = auhtorId; } public String getAuthorDesc() { return authorDesc; } public void setAuthorDesc(String authorDesc) { this.authorDesc = authorDesc; } public String getAuthorIcon() { return authorIcon; } public void setAuthorIcon(String authorIcon) { this.authorIcon = authorIcon; } public int getLabelColor() { return labelColor; } public void setLabelColor(int labelColor) { this.labelColor = labelColor; } public String getLabelText() { return labelText; } public void setLabelText(String labelText) { this.labelText = labelText; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/LitePalBean/SearchTag.java ================================================ package com.example.discover.bean.LitePalBean; import org.litepal.crud.DataSupport; /** * Created by monkeyWiiu on 2018/1/28. */ public class SearchTag extends DataSupport { private String tag; public String getTag() { return tag; } public void setTag(String tag) { this.tag = tag; } } ================================================ FILE: app/src/main/java/com/example/discover/bean/ResultBean.java ================================================ package com.example.discover.bean; import com.example.discover.SearchActivity; import com.example.discover.bean.DetailBean.ItemList; import java.io.Serializable; import java.util.List; /** * Created by monkeyWiiu on 2018/1/29. */ public class ResultBean implements Serializable { private List itemList; public List getItemList() { return itemList; } public void setItemList(List itemList) { } } ================================================ FILE: app/src/main/java/com/example/discover/bean/TestBean.java ================================================ package com.example.discover.bean; import java.util.List; /** * Created by Administrator on 2017/12/14 0014. */ public class TestBean { /** * itemList : [{"type":"video","data":{"dataType":"VideoBeanForClient","id":66374,"title":"太阳死亡后会变成什么,膨胀的红色巨人","slogan":null,"description":"有一天我们的太阳也会死亡吗?答案是的,但是我们不必担心,因为人类可能无法活到太阳死亡的那一天,或者在此之前,我们已经离开太阳系。","provider":{"name":"PGC","alias":"PGC","icon":""},"category":"科普","author":{"id":2098,"icon":"http://img.kaiyanapp.com/608dafdede807bd3748b582a32dc0a33.png?imageMogr2/quality/60/format/jpg","name":"火星人俱乐部","description":"科普趣味生活,亲子科学实验;北大老师陪你趣学科学;","link":"","latestReleaseTime":1513237731000,"videoNum":62,"adTrack":null,"follow":{"itemType":"author","itemId":2098,"followed":false},"shield":{"itemType":"author","itemId":2098,"shielded":false},"approvedNotReadyVideoCount":0,"ifPgc":true},"cover":{"feed":"http://img.kaiyanapp.com/9f4a7de9c2244499a95de914f22d76b4.png?imageMogr2/quality/60/format/jpg","detail":"http://img.kaiyanapp.com/9f4a7de9c2244499a95de914f22d76b4.png?imageMogr2/quality/60/format/jpg","blurred":"http://img.kaiyanapp.com/1661e0b22a0768be62510bcc934b2ac6.jpeg?imageMogr2/quality/60/format/jpg","sharing":null,"homepage":null},"playUrl":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=default&source=aliyun","thumbPlayUrl":null,"duration":137,"webUrl":{"raw":"http://www.eyepetizer.net/detail.html?vid=66374","forWeibo":"http://www.eyepetizer.net/detail.html?vid=66374"},"releaseTime":1513237731000,"library":"DEFAULT","playInfo":[{"height":720,"width":1280,"urlList":[{"name":"aliyun","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=aliyun","size":14871277},{"name":"qcloud","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=qcloud","size":14871277},{"name":"ucloud","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=ucloud","size":14871277}],"name":"高清","type":"high","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=aliyun"}],"consumption":{"collectionCount":0,"shareCount":2,"replyCount":0},"campaign":null,"waterMarks":null,"adTrack":null,"tags":[{"id":484,"name":"干货","actionUrl":"eyepetizer://tag/484/?title=%E5%B9%B2%E8%B4%A7","adTrack":null,"desc":null,"bgPicture":"http://img.kaiyanapp.com/27856a0c2855246c31c19f7a8fd814ce.jpeg?imageMogr2/quality/60/format/jpg","headerImage":"http://img.kaiyanapp.com/27856a0c2855246c31c19f7a8fd814ce.jpeg?imageMogr2/quality/60/format/jpg","tagRecType":"NORMAL"},{"id":546,"name":"宇宙","actionUrl":"eyepetizer://tag/546/?title=%E5%AE%87%E5%AE%99","adTrack":null,"desc":null,"bgPicture":"http://img.kaiyanapp.com/7052c0f6e4267111b023d2541b1a7f07.jpeg?imageMogr2/quality/60/format/jpg","headerImage":"http://img.kaiyanapp.com/7052c0f6e4267111b023d2541b1a7f07.jpeg?imageMogr2/quality/60/format/jpg","tagRecType":"NORMAL"},{"id":44,"name":"科普","actionUrl":"eyepetizer://tag/44/?title=%E7%A7%91%E6%99%AE","adTrack":null,"desc":null,"bgPicture":"http://img.kaiyanapp.com/f2e7359e81e217782f32cc3d482b3284.jpeg?imageMogr2/quality/60/format/jpg","headerImage":"http://img.kaiyanapp.com/f2e7359e81e217782f32cc3d482b3284.jpeg?imageMogr2/quality/60/format/jpg","tagRecType":"NORMAL"}],"type":"NORMAL","titlePgc":"太阳死亡后会变成什么,膨胀的红色巨人","descriptionPgc":"有一天我们的太阳也会死亡吗?答案是的,但是我们不必担心,因为人类可能无法活到太阳死亡的那一天,或者在此之前,我们已经离开太阳系。","remark":"太阳死亡后会变成什么?","idx":0,"shareAdTrack":null,"favoriteAdTrack":null,"webAdTrack":null,"date":1513237731000,"promotion":null,"label":null,"labelList":[],"descriptionEditor":"","collected":false,"played":false,"subtitles":[],"lastViewTime":null,"playlists":null,"src":null},"tag":null,"id":0,"adIndex":-1},{"type":"video","data":{"dataType":"VideoBeanForClient","id":66371,"title":"Coronation Street 宣传广告:从今以后","slogan":null,"description":"由 ITV Coronation Street 带来的广告,展示了从以前到现在的工作场景,希望能够一直陪伴着他们所爱的人。","provider":{"name":"定制来源","alias":"CustomSrc","icon":""},"category":"广告","author":{"id":938,"icon":"http://img.kaiyanapp.com/e44ed5fcfa424ba35761ce5f1339bc16.jpeg?imageMogr2/quality/60/format/jpg","name":"欧美广告精选","description":"持续推送新奇、有趣、大开眼界的欧美创意广告","link":"","latestReleaseTime":1513237624000,"videoNum":194,"adTrack":null,"follow":{"itemType":"author","itemId":938,"followed":false},"shield":{"itemType":"author","itemId":938,"shielded":false},"approvedNotReadyVideoCount":0,"ifPgc":true},"cover":{"feed":"http://img.kaiyanapp.com/3c7f944f41df332164c73454abc51725.png?imageMogr2/quality/60/format/jpg","detail":"http://img.kaiyanapp.com/3c7f944f41df332164c73454abc51725.png?imageMogr2/quality/60/format/jpg","blurred":"http://img.kaiyanapp.com/d772b37fa86071c42ac9154e7fb21d4c.png?imageMogr2/quality/60/format/jpg","sharing":null,"homepage":null},"playUrl":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66371&editionType=default&source=aliyun","thumbPlayUrl":null,"duration":72,"webUrl":{"raw":"http://www.eyepetizer.net/detail.html?vid=66371","forWeibo":"http://www.eyepetizer.net/detail.html?vid=66371"},"releaseTime":1513237624000,"library":"DEFAULT","playInfo":[{"height":720,"width":1280,"urlList":[{"name":"aliyun","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66371&editionType=high&source=aliyun","size":10993795},{"name":"qcloud","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66371&editionType=high&source=qcloud","size":10993795},{"name":"ucloud","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66371&editionType=high&source=ucloud","size":10993795}],"name":"高清","type":"high","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66371&editionType=high&source=aliyun"}],"consumption":{"collectionCount":2,"shareCount":2,"replyCount":0},"campaign":null,"waterMarks":null,"adTrack":null,"tags":[{"id":711,"name":"欧美","actionUrl":"eyepetizer://tag/711/?title=%E6%AC%A7%E7%BE%8E","adTrack":null,"desc":null,"bgPicture":"http://img.kaiyanapp.com/0cb9ec0ade8d938be0452e8ca2d621d0.jpeg?imageMogr2/quality/60/format/jpg","headerImage":"http://img.kaiyanapp.com/0cb9ec0ade8d938be0452e8ca2d621d0.jpeg?imageMogr2/quality/60/format/jpg","tagRecType":"NORMAL"},{"id":136,"name":"温情","actionUrl":"eyepetizer://tag/136/?title=%E6%B8%A9%E6%83%85","adTrack":null,"desc":null,"bgPicture":"http://img.kaiyanapp.com/0bc1dc78c631eae017ee69418303adc5.jpeg?imageMogr2/quality/100","headerImage":"http://img.kaiyanapp.com/0bc1dc78c631eae017ee69418303adc5.jpeg?imageMogr2/quality/100","tagRecType":"NORMAL"},{"id":16,"name":"广告","actionUrl":"eyepetizer://tag/16/?title=%E5%B9%BF%E5%91%8A","adTrack":null,"desc":null,"bgPicture":"http://img.kaiyanapp.com/e41e74fe73882b552de00d95d56748d2.jpeg?imageMogr2/quality/60","headerImage":"http://img.kaiyanapp.com/3054658dbd559ac42c4c282e9cab7a32.jpeg?imageMogr2/quality/100","tagRecType":"NORMAL"},{"id":2,"name":"创意","actionUrl":"eyepetizer://tag/2/?title=%E5%88%9B%E6%84%8F","adTrack":null,"desc":"创意十足的style","bgPicture":"http://img.kaiyanapp.com/e6eee049dd13fe8ce0712a6f2648d7e2.jpeg?imageMogr2/quality/100","headerImage":"http://img.kaiyanapp.com/fdefdb34cbe3d2ac9964d306febe9025.jpeg?imageMogr2/quality/100","tagRecType":"NORMAL"}],"type":"NORMAL","titlePgc":"Coronation Street 宣传广告:从今以后","descriptionPgc":"由 ITV Coronation Street 带来的广告,展示了从以前到现在的工作场景,希望能够一直陪伴着他们所爱的人。","remark":null,"idx":0,"shareAdTrack":null,"favoriteAdTrack":null,"webAdTrack":null,"date":1513237624000,"promotion":null,"label":null,"labelList":[],"descriptionEditor":"","collected":false,"played":false,"subtitles":[],"lastViewTime":null,"playlists":null,"src":null},"tag":null,"id":0,"adIndex":-1}] * count : 2 * total : 0 * nextPageUrl : http://baobab.kaiyanapp.com/api/v4/discovery/hot?start=42&num=2 * adExist : false */ private int count; private int total; private String nextPageUrl; private boolean adExist; private List itemList; public int getCount() { return count; } public void setCount(int count) { this.count = count; } public int getTotal() { return total; } public void setTotal(int total) { this.total = total; } public String getNextPageUrl() { return nextPageUrl; } public void setNextPageUrl(String nextPageUrl) { this.nextPageUrl = nextPageUrl; } public boolean isAdExist() { return adExist; } public void setAdExist(boolean adExist) { this.adExist = adExist; } public List getItemList() { return itemList; } public void setItemList(List itemList) { this.itemList = itemList; } public static class ItemListBean { /** * type : video * data : {"dataType":"VideoBeanForClient","id":66374,"title":"太阳死亡后会变成什么,膨胀的红色巨人","slogan":null,"description":"有一天我们的太阳也会死亡吗?答案是的,但是我们不必担心,因为人类可能无法活到太阳死亡的那一天,或者在此之前,我们已经离开太阳系。","provider":{"name":"PGC","alias":"PGC","icon":""},"category":"科普","author":{"id":2098,"icon":"http://img.kaiyanapp.com/608dafdede807bd3748b582a32dc0a33.png?imageMogr2/quality/60/format/jpg","name":"火星人俱乐部","description":"科普趣味生活,亲子科学实验;北大老师陪你趣学科学;","link":"","latestReleaseTime":1513237731000,"videoNum":62,"adTrack":null,"follow":{"itemType":"author","itemId":2098,"followed":false},"shield":{"itemType":"author","itemId":2098,"shielded":false},"approvedNotReadyVideoCount":0,"ifPgc":true},"cover":{"feed":"http://img.kaiyanapp.com/9f4a7de9c2244499a95de914f22d76b4.png?imageMogr2/quality/60/format/jpg","detail":"http://img.kaiyanapp.com/9f4a7de9c2244499a95de914f22d76b4.png?imageMogr2/quality/60/format/jpg","blurred":"http://img.kaiyanapp.com/1661e0b22a0768be62510bcc934b2ac6.jpeg?imageMogr2/quality/60/format/jpg","sharing":null,"homepage":null},"playUrl":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=default&source=aliyun","thumbPlayUrl":null,"duration":137,"webUrl":{"raw":"http://www.eyepetizer.net/detail.html?vid=66374","forWeibo":"http://www.eyepetizer.net/detail.html?vid=66374"},"releaseTime":1513237731000,"library":"DEFAULT","playInfo":[{"height":720,"width":1280,"urlList":[{"name":"aliyun","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=aliyun","size":14871277},{"name":"qcloud","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=qcloud","size":14871277},{"name":"ucloud","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=ucloud","size":14871277}],"name":"高清","type":"high","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=aliyun"}],"consumption":{"collectionCount":0,"shareCount":2,"replyCount":0},"campaign":null,"waterMarks":null,"adTrack":null,"tags":[{"id":484,"name":"干货","actionUrl":"eyepetizer://tag/484/?title=%E5%B9%B2%E8%B4%A7","adTrack":null,"desc":null,"bgPicture":"http://img.kaiyanapp.com/27856a0c2855246c31c19f7a8fd814ce.jpeg?imageMogr2/quality/60/format/jpg","headerImage":"http://img.kaiyanapp.com/27856a0c2855246c31c19f7a8fd814ce.jpeg?imageMogr2/quality/60/format/jpg","tagRecType":"NORMAL"},{"id":546,"name":"宇宙","actionUrl":"eyepetizer://tag/546/?title=%E5%AE%87%E5%AE%99","adTrack":null,"desc":null,"bgPicture":"http://img.kaiyanapp.com/7052c0f6e4267111b023d2541b1a7f07.jpeg?imageMogr2/quality/60/format/jpg","headerImage":"http://img.kaiyanapp.com/7052c0f6e4267111b023d2541b1a7f07.jpeg?imageMogr2/quality/60/format/jpg","tagRecType":"NORMAL"},{"id":44,"name":"科普","actionUrl":"eyepetizer://tag/44/?title=%E7%A7%91%E6%99%AE","adTrack":null,"desc":null,"bgPicture":"http://img.kaiyanapp.com/f2e7359e81e217782f32cc3d482b3284.jpeg?imageMogr2/quality/60/format/jpg","headerImage":"http://img.kaiyanapp.com/f2e7359e81e217782f32cc3d482b3284.jpeg?imageMogr2/quality/60/format/jpg","tagRecType":"NORMAL"}],"type":"NORMAL","titlePgc":"太阳死亡后会变成什么,膨胀的红色巨人","descriptionPgc":"有一天我们的太阳也会死亡吗?答案是的,但是我们不必担心,因为人类可能无法活到太阳死亡的那一天,或者在此之前,我们已经离开太阳系。","remark":"太阳死亡后会变成什么?","idx":0,"shareAdTrack":null,"favoriteAdTrack":null,"webAdTrack":null,"date":1513237731000,"promotion":null,"label":null,"labelList":[],"descriptionEditor":"","collected":false,"played":false,"subtitles":[],"lastViewTime":null,"playlists":null,"src":null} * tag : null * id : 0 * adIndex : -1 */ private String type; private DataBean data; private Object tag; private int id; private int adIndex; public String getType() { return type; } public void setType(String type) { this.type = type; } public DataBean getData() { return data; } public void setData(DataBean data) { this.data = data; } public Object getTag() { return tag; } public void setTag(Object tag) { this.tag = tag; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getAdIndex() { return adIndex; } public void setAdIndex(int adIndex) { this.adIndex = adIndex; } public static class DataBean { /** * dataType : VideoBeanForClient * id : 66374 * title : 太阳死亡后会变成什么,膨胀的红色巨人 * slogan : null * description : 有一天我们的太阳也会死亡吗?答案是的,但是我们不必担心,因为人类可能无法活到太阳死亡的那一天,或者在此之前,我们已经离开太阳系。 * provider : {"name":"PGC","alias":"PGC","icon":""} * category : 科普 * author : {"id":2098,"icon":"http://img.kaiyanapp.com/608dafdede807bd3748b582a32dc0a33.png?imageMogr2/quality/60/format/jpg","name":"火星人俱乐部","description":"科普趣味生活,亲子科学实验;北大老师陪你趣学科学;","link":"","latestReleaseTime":1513237731000,"videoNum":62,"adTrack":null,"follow":{"itemType":"author","itemId":2098,"followed":false},"shield":{"itemType":"author","itemId":2098,"shielded":false},"approvedNotReadyVideoCount":0,"ifPgc":true} * cover : {"feed":"http://img.kaiyanapp.com/9f4a7de9c2244499a95de914f22d76b4.png?imageMogr2/quality/60/format/jpg","detail":"http://img.kaiyanapp.com/9f4a7de9c2244499a95de914f22d76b4.png?imageMogr2/quality/60/format/jpg","blurred":"http://img.kaiyanapp.com/1661e0b22a0768be62510bcc934b2ac6.jpeg?imageMogr2/quality/60/format/jpg","sharing":null,"homepage":null} * playUrl : http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=default&source=aliyun * thumbPlayUrl : null * duration : 137 * webUrl : {"raw":"http://www.eyepetizer.net/detail.html?vid=66374","forWeibo":"http://www.eyepetizer.net/detail.html?vid=66374"} * releaseTime : 1513237731000 * library : DEFAULT * playInfo : [{"height":720,"width":1280,"urlList":[{"name":"aliyun","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=aliyun","size":14871277},{"name":"qcloud","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=qcloud","size":14871277},{"name":"ucloud","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=ucloud","size":14871277}],"name":"高清","type":"high","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=aliyun"}] * consumption : {"collectionCount":0,"shareCount":2,"replyCount":0} * campaign : null * waterMarks : null * adTrack : null * tags : [{"id":484,"name":"干货","actionUrl":"eyepetizer://tag/484/?title=%E5%B9%B2%E8%B4%A7","adTrack":null,"desc":null,"bgPicture":"http://img.kaiyanapp.com/27856a0c2855246c31c19f7a8fd814ce.jpeg?imageMogr2/quality/60/format/jpg","headerImage":"http://img.kaiyanapp.com/27856a0c2855246c31c19f7a8fd814ce.jpeg?imageMogr2/quality/60/format/jpg","tagRecType":"NORMAL"},{"id":546,"name":"宇宙","actionUrl":"eyepetizer://tag/546/?title=%E5%AE%87%E5%AE%99","adTrack":null,"desc":null,"bgPicture":"http://img.kaiyanapp.com/7052c0f6e4267111b023d2541b1a7f07.jpeg?imageMogr2/quality/60/format/jpg","headerImage":"http://img.kaiyanapp.com/7052c0f6e4267111b023d2541b1a7f07.jpeg?imageMogr2/quality/60/format/jpg","tagRecType":"NORMAL"},{"id":44,"name":"科普","actionUrl":"eyepetizer://tag/44/?title=%E7%A7%91%E6%99%AE","adTrack":null,"desc":null,"bgPicture":"http://img.kaiyanapp.com/f2e7359e81e217782f32cc3d482b3284.jpeg?imageMogr2/quality/60/format/jpg","headerImage":"http://img.kaiyanapp.com/f2e7359e81e217782f32cc3d482b3284.jpeg?imageMogr2/quality/60/format/jpg","tagRecType":"NORMAL"}] * type : NORMAL * titlePgc : 太阳死亡后会变成什么,膨胀的红色巨人 * descriptionPgc : 有一天我们的太阳也会死亡吗?答案是的,但是我们不必担心,因为人类可能无法活到太阳死亡的那一天,或者在此之前,我们已经离开太阳系。 * remark : 太阳死亡后会变成什么? * idx : 0 * shareAdTrack : null * favoriteAdTrack : null * webAdTrack : null * date : 1513237731000 * promotion : null * label : null * labelList : [] * descriptionEditor : * collected : false * played : false * subtitles : [] * lastViewTime : null * playlists : null * src : null */ private String dataType; private int id; private String title; private Object slogan; private String description; private ProviderBean provider; private String category; private AuthorBean author; private CoverBean cover; private String playUrl; private Object thumbPlayUrl; private int duration; private WebUrlBean webUrl; private long releaseTime; private String library; private ConsumptionBean consumption; private Object campaign; private Object waterMarks; private Object adTrack; private String type; private String titlePgc; private String descriptionPgc; private String remark; private int idx; private Object shareAdTrack; private Object favoriteAdTrack; private Object webAdTrack; private long date; private Object promotion; private Object label; private String descriptionEditor; private boolean collected; private boolean played; private Object lastViewTime; private Object playlists; private Object src; private List playInfo; private List tags; private List labelList; private List subtitles; public String getDataType() { return dataType; } public void setDataType(String dataType) { this.dataType = dataType; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public Object getSlogan() { return slogan; } public void setSlogan(Object slogan) { this.slogan = slogan; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public ProviderBean getProvider() { return provider; } public void setProvider(ProviderBean provider) { this.provider = provider; } public String getCategory() { return category; } public void setCategory(String category) { this.category = category; } public AuthorBean getAuthor() { return author; } public void setAuthor(AuthorBean author) { this.author = author; } public CoverBean getCover() { return cover; } public void setCover(CoverBean cover) { this.cover = cover; } public String getPlayUrl() { return playUrl; } public void setPlayUrl(String playUrl) { this.playUrl = playUrl; } public Object getThumbPlayUrl() { return thumbPlayUrl; } public void setThumbPlayUrl(Object thumbPlayUrl) { this.thumbPlayUrl = thumbPlayUrl; } public int getDuration() { return duration; } public void setDuration(int duration) { this.duration = duration; } public WebUrlBean getWebUrl() { return webUrl; } public void setWebUrl(WebUrlBean webUrl) { this.webUrl = webUrl; } public long getReleaseTime() { return releaseTime; } public void setReleaseTime(long releaseTime) { this.releaseTime = releaseTime; } public String getLibrary() { return library; } public void setLibrary(String library) { this.library = library; } public ConsumptionBean getConsumption() { return consumption; } public void setConsumption(ConsumptionBean consumption) { this.consumption = consumption; } public Object getCampaign() { return campaign; } public void setCampaign(Object campaign) { this.campaign = campaign; } public Object getWaterMarks() { return waterMarks; } public void setWaterMarks(Object waterMarks) { this.waterMarks = waterMarks; } public Object getAdTrack() { return adTrack; } public void setAdTrack(Object adTrack) { this.adTrack = adTrack; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getTitlePgc() { return titlePgc; } public void setTitlePgc(String titlePgc) { this.titlePgc = titlePgc; } public String getDescriptionPgc() { return descriptionPgc; } public void setDescriptionPgc(String descriptionPgc) { this.descriptionPgc = descriptionPgc; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } public int getIdx() { return idx; } public void setIdx(int idx) { this.idx = idx; } public Object getShareAdTrack() { return shareAdTrack; } public void setShareAdTrack(Object shareAdTrack) { this.shareAdTrack = shareAdTrack; } public Object getFavoriteAdTrack() { return favoriteAdTrack; } public void setFavoriteAdTrack(Object favoriteAdTrack) { this.favoriteAdTrack = favoriteAdTrack; } public Object getWebAdTrack() { return webAdTrack; } public void setWebAdTrack(Object webAdTrack) { this.webAdTrack = webAdTrack; } public long getDate() { return date; } public void setDate(long date) { this.date = date; } public Object getPromotion() { return promotion; } public void setPromotion(Object promotion) { this.promotion = promotion; } public Object getLabel() { return label; } public void setLabel(Object label) { this.label = label; } public String getDescriptionEditor() { return descriptionEditor; } public void setDescriptionEditor(String descriptionEditor) { this.descriptionEditor = descriptionEditor; } public boolean isCollected() { return collected; } public void setCollected(boolean collected) { this.collected = collected; } public boolean isPlayed() { return played; } public void setPlayed(boolean played) { this.played = played; } public Object getLastViewTime() { return lastViewTime; } public void setLastViewTime(Object lastViewTime) { this.lastViewTime = lastViewTime; } public Object getPlaylists() { return playlists; } public void setPlaylists(Object playlists) { this.playlists = playlists; } public Object getSrc() { return src; } public void setSrc(Object src) { this.src = src; } public List getPlayInfo() { return playInfo; } public void setPlayInfo(List playInfo) { this.playInfo = playInfo; } public List getTags() { return tags; } public void setTags(List tags) { this.tags = tags; } public List getLabelList() { return labelList; } public void setLabelList(List labelList) { this.labelList = labelList; } public List getSubtitles() { return subtitles; } public void setSubtitles(List subtitles) { this.subtitles = subtitles; } public static class ProviderBean { /** * name : PGC * alias : PGC * icon : */ private String name; private String alias; private String icon; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAlias() { return alias; } public void setAlias(String alias) { this.alias = alias; } public String getIcon() { return icon; } public void setIcon(String icon) { this.icon = icon; } } public static class AuthorBean { /** * id : 2098 * icon : http://img.kaiyanapp.com/608dafdede807bd3748b582a32dc0a33.png?imageMogr2/quality/60/format/jpg * name : 火星人俱乐部 * description : 科普趣味生活,亲子科学实验;北大老师陪你趣学科学; * link : * latestReleaseTime : 1513237731000 * videoNum : 62 * adTrack : null * follow : {"itemType":"author","itemId":2098,"followed":false} * shield : {"itemType":"author","itemId":2098,"shielded":false} * approvedNotReadyVideoCount : 0 * ifPgc : true */ private int id; private String icon; private String name; private String description; private String link; private long latestReleaseTime; private int videoNum; private Object adTrack; private FollowBean follow; private ShieldBean shield; private int approvedNotReadyVideoCount; private boolean ifPgc; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getIcon() { return icon; } public void setIcon(String icon) { this.icon = icon; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getLink() { return link; } public void setLink(String link) { this.link = link; } public long getLatestReleaseTime() { return latestReleaseTime; } public void setLatestReleaseTime(long latestReleaseTime) { this.latestReleaseTime = latestReleaseTime; } public int getVideoNum() { return videoNum; } public void setVideoNum(int videoNum) { this.videoNum = videoNum; } public Object getAdTrack() { return adTrack; } public void setAdTrack(Object adTrack) { this.adTrack = adTrack; } public FollowBean getFollow() { return follow; } public void setFollow(FollowBean follow) { this.follow = follow; } public ShieldBean getShield() { return shield; } public void setShield(ShieldBean shield) { this.shield = shield; } public int getApprovedNotReadyVideoCount() { return approvedNotReadyVideoCount; } public void setApprovedNotReadyVideoCount(int approvedNotReadyVideoCount) { this.approvedNotReadyVideoCount = approvedNotReadyVideoCount; } public boolean isIfPgc() { return ifPgc; } public void setIfPgc(boolean ifPgc) { this.ifPgc = ifPgc; } public static class FollowBean { /** * itemType : author * itemId : 2098 * followed : false */ private String itemType; private int itemId; private boolean followed; public String getItemType() { return itemType; } public void setItemType(String itemType) { this.itemType = itemType; } public int getItemId() { return itemId; } public void setItemId(int itemId) { this.itemId = itemId; } public boolean isFollowed() { return followed; } public void setFollowed(boolean followed) { this.followed = followed; } } public static class ShieldBean { /** * itemType : author * itemId : 2098 * shielded : false */ private String itemType; private int itemId; private boolean shielded; public String getItemType() { return itemType; } public void setItemType(String itemType) { this.itemType = itemType; } public int getItemId() { return itemId; } public void setItemId(int itemId) { this.itemId = itemId; } public boolean isShielded() { return shielded; } public void setShielded(boolean shielded) { this.shielded = shielded; } } } public static class CoverBean { /** * feed : http://img.kaiyanapp.com/9f4a7de9c2244499a95de914f22d76b4.png?imageMogr2/quality/60/format/jpg * detail : http://img.kaiyanapp.com/9f4a7de9c2244499a95de914f22d76b4.png?imageMogr2/quality/60/format/jpg * blurred : http://img.kaiyanapp.com/1661e0b22a0768be62510bcc934b2ac6.jpeg?imageMogr2/quality/60/format/jpg * sharing : null * homepage : null */ private String feed; private String detail; private String blurred; private Object sharing; private Object homepage; public String getFeed() { return feed; } public void setFeed(String feed) { this.feed = feed; } public String getDetail() { return detail; } public void setDetail(String detail) { this.detail = detail; } public String getBlurred() { return blurred; } public void setBlurred(String blurred) { this.blurred = blurred; } public Object getSharing() { return sharing; } public void setSharing(Object sharing) { this.sharing = sharing; } public Object getHomepage() { return homepage; } public void setHomepage(Object homepage) { this.homepage = homepage; } } public static class WebUrlBean { /** * raw : http://www.eyepetizer.net/detail.html?vid=66374 * forWeibo : http://www.eyepetizer.net/detail.html?vid=66374 */ private String raw; private String forWeibo; public String getRaw() { return raw; } public void setRaw(String raw) { this.raw = raw; } public String getForWeibo() { return forWeibo; } public void setForWeibo(String forWeibo) { this.forWeibo = forWeibo; } } public static class ConsumptionBean { /** * collectionCount : 0 * shareCount : 2 * replyCount : 0 */ private int collectionCount; private int shareCount; private int replyCount; public int getCollectionCount() { return collectionCount; } public void setCollectionCount(int collectionCount) { this.collectionCount = collectionCount; } public int getShareCount() { return shareCount; } public void setShareCount(int shareCount) { this.shareCount = shareCount; } public int getReplyCount() { return replyCount; } public void setReplyCount(int replyCount) { this.replyCount = replyCount; } } public static class PlayInfoBean { /** * height : 720 * width : 1280 * urlList : [{"name":"aliyun","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=aliyun","size":14871277},{"name":"qcloud","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=qcloud","size":14871277},{"name":"ucloud","url":"http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=ucloud","size":14871277}] * name : 高清 * type : high * url : http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=aliyun */ private int height; private int width; private String name; private String type; private String url; private List urlList; public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } public int getWidth() { return width; } public void setWidth(int width) { this.width = width; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public List getUrlList() { return urlList; } public void setUrlList(List urlList) { this.urlList = urlList; } public static class UrlListBean { /** * name : aliyun * url : http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66374&editionType=high&source=aliyun * size : 14871277 */ private String name; private String url; private int size; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } } } public static class TagsBean { /** * id : 484 * name : 干货 * actionUrl : eyepetizer://tag/484/?title=%E5%B9%B2%E8%B4%A7 * adTrack : null * desc : null * bgPicture : http://img.kaiyanapp.com/27856a0c2855246c31c19f7a8fd814ce.jpeg?imageMogr2/quality/60/format/jpg * headerImage : http://img.kaiyanapp.com/27856a0c2855246c31c19f7a8fd814ce.jpeg?imageMogr2/quality/60/format/jpg * tagRecType : NORMAL */ private int id; private String name; private String actionUrl; private Object adTrack; private Object desc; private String bgPicture; private String headerImage; private String tagRecType; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getActionUrl() { return actionUrl; } public void setActionUrl(String actionUrl) { this.actionUrl = actionUrl; } public Object getAdTrack() { return adTrack; } public void setAdTrack(Object adTrack) { this.adTrack = adTrack; } public Object getDesc() { return desc; } public void setDesc(Object desc) { this.desc = desc; } public String getBgPicture() { return bgPicture; } public void setBgPicture(String bgPicture) { this.bgPicture = bgPicture; } public String getHeaderImage() { return headerImage; } public void setHeaderImage(String headerImage) { this.headerImage = headerImage; } public String getTagRecType() { return tagRecType; } public void setTagRecType(String tagRecType) { this.tagRecType = tagRecType; } } } } } ================================================ FILE: app/src/main/java/com/example/discover/http/HttpClient.java ================================================ package com.example.discover.http; import com.example.discover.bean.AuthorDetailBean; import com.example.discover.bean.DetailBean.FindCategory; import com.example.discover.bean.DetailBean.ItemList; import com.example.discover.bean.DetailBean.Replies; import com.example.discover.bean.GankBean; import com.example.discover.bean.HotEyeBean; import com.example.discover.bean.ResultBean; import com.example.http.HttpUtils; import java.util.List; import io.reactivex.Flowable; import retrofit2.http.GET; import retrofit2.http.Path; import retrofit2.http.Query; /** * Created by Administrator on 2017/12/9 0009. */ public interface HttpClient { class Builder { public static HttpClient getEyeService() { return HttpUtils.getInstance().getEyeServer(HttpClient.class); } public static HttpClient getGankService() { return HttpUtils.getInstance().getGankServer(HttpClient.class); } } /** * * @param start 从多少开始,如从“0”开始 * @param num 一次请求的数目(从start开始计算) * @return */ @GET("v4/discovery/hot") Flowable getEyeHot(@Query("start") int start, @Query("num") int num); /** * * @param id = 2创意4开胃6旅行8预告10动画12剧情14广告18运动20音乐22记录24时尚26萌宠28搞笑30游戏32科普34集锦36生活38综艺 * @return */ @GET("v3/categories/detail") Flowable getEyeCateGory(@Query("id") int id); @GET("v3/pgc/videos") Flowable getAuthorRelated(@Query("start") int start, @Query("pgcId") int id, @Query("strategy") String strategy); @GET("v3/queries/hot") Flowable> getTrendingTag(); @GET("v1/search?num=10") Flowable getResult(@Query("query") String key, @Query("start") int start); @GET("v1/replies/video") Flowable fetchReplies(@Query("id") int id); @GET("v1/replies/video?num=10") Flowable fetchReplies(@Query("id") int id, @Query("lastId") int lastId); @GET("data/{type}/{number}/{page}") Flowable getGankData(@Path("type") String id, @Path("number") int number, @Path("page") int page); } ================================================ FILE: app/src/main/java/com/example/discover/http/RequestListener.java ================================================ package com.example.discover.http; import io.reactivex.disposables.Disposable; /** * Created by Administrator on 2017/12/12 0012. */ public interface RequestListener { void onSuccess(Object object); void onFailed(Throwable t); void onCompleted(); } ================================================ FILE: app/src/main/java/com/example/discover/http/cahe/ACache.java ================================================ /** * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.discover.http.cahe; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.PixelFormat; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import org.json.JSONArray; import org.json.JSONObject; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.RandomAccessFile; import java.io.Serializable; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; /** * @author Michael Yang(www.yangfuhai.com) update at 2013.08.07 */ public class ACache { public static final int TIME_HOUR = 60 * 60; public static final int TIME_DAY = TIME_HOUR * 24; private static final int MAX_SIZE = 1000 * 1000 * 50; // 50 mb private static final int MAX_COUNT = Integer.MAX_VALUE; // 不限制存放数据的数量 private static Map mInstanceMap = new HashMap(); private ACacheManager mCache; public static ACache get(Context ctx) { return get(ctx, "ACache"); } public static ACache get(Context ctx, String cacheName) { File f = new File(ctx.getCacheDir(), cacheName); return get(f, MAX_SIZE, MAX_COUNT); } public static ACache get(File cacheDir) { return get(cacheDir, MAX_SIZE, MAX_COUNT); } public static ACache get(Context ctx, long max_zise, int max_count) { File f = new File(ctx.getCacheDir(), "ACache"); return get(f, max_zise, max_count); } public static ACache get(File cacheDir, long max_zise, int max_count) { ACache manager = mInstanceMap.get(cacheDir.getAbsoluteFile() + myPid()); if (manager == null) { manager = new ACache(cacheDir, max_zise, max_count); mInstanceMap.put(cacheDir.getAbsolutePath() + myPid(), manager); } return manager; } private static String myPid() { return "_" + android.os.Process.myPid(); } private ACache(File cacheDir, long max_size, int max_count) { if (!cacheDir.exists() && !cacheDir.mkdirs()) { throw new RuntimeException("can't make dirs in " + cacheDir.getAbsolutePath()); } mCache = new ACacheManager(cacheDir, max_size, max_count); } // ======================================= // ============ String数据 读写 ============== // ======================================= /** * 保存 String数据 到 缓存中 * * @param key * 保存的key * @param value * 保存的String数据 */ public void put(String key, String value) { File file = mCache.newFile(key); BufferedWriter out = null; try { out = new BufferedWriter(new FileWriter(file), 1024); out.write(value); } catch (IOException e) { e.printStackTrace(); } finally { if (out != null) { try { out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); } } mCache.put(file); } } /** * 保存 String数据 到 缓存中 * * @param key * 保存的key * @param value * 保存的String数据 * @param saveTime * 保存的时间,单位:秒 */ public void put(String key, String value, int saveTime) { put(key, Utils.newStringWithDateInfo(saveTime, value)); } /** * 读取 String数据 * * @param key * @return String 数据 */ public String getAsString(String key) { File file = mCache.get(key); if (!file.exists()) return null; boolean removeFile = false; BufferedReader in = null; try { in = new BufferedReader(new FileReader(file)); String readString = ""; String currentLine; while ((currentLine = in.readLine()) != null) { readString += currentLine; } if (!Utils.isDue(readString)) { return Utils.clearDateInfo(readString); } else { removeFile = true; return null; } } catch (IOException e) { e.printStackTrace(); return null; } finally { if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } if (removeFile) remove(key); } } // ======================================= // ============= JSONObject 数据 读写 ============== // ======================================= /** * 保存 JSONObject数据 到 缓存中 * * @param key * 保存的key * @param value * 保存的JSON数据 */ public void put(String key, JSONObject value) { put(key, value.toString()); } /** * 保存 JSONObject数据 到 缓存中 * * @param key * 保存的key * @param value * 保存的JSONObject数据 * @param saveTime * 保存的时间,单位:秒 */ public void put(String key, JSONObject value, int saveTime) { put(key, value.toString(), saveTime); } /** * 读取JSONObject数据 * * @param key * @return JSONObject数据 */ public JSONObject getAsJSONObject(String key) { String JSONString = getAsString(key); try { JSONObject obj = new JSONObject(JSONString); return obj; } catch (Exception e) { e.printStackTrace(); return null; } } // ======================================= // ============ JSONArray 数据 读写 ============= // ======================================= /** * 保存 JSONArray数据 到 缓存中 * * @param key * 保存的key * @param value * 保存的JSONArray数据 */ public void put(String key, JSONArray value) { put(key, value.toString()); } /** * 保存 JSONArray数据 到 缓存中 * * @param key * 保存的key * @param value * 保存的JSONArray数据 * @param saveTime * 保存的时间,单位:秒 */ public void put(String key, JSONArray value, int saveTime) { put(key, value.toString(), saveTime); } /** * 读取JSONArray数据 * * @param key * @return JSONArray数据 */ public JSONArray getAsJSONArray(String key) { String JSONString = getAsString(key); try { JSONArray obj = new JSONArray(JSONString); return obj; } catch (Exception e) { e.printStackTrace(); return null; } } // ======================================= // ============== byte 数据 读写 ============= // ======================================= /** * 保存 byte数据 到 缓存中 * * @param key * 保存的key * @param value * 保存的数据 */ public void put(String key, byte[] value) { File file = mCache.newFile(key); FileOutputStream out = null; try { out = new FileOutputStream(file); out.write(value); } catch (Exception e) { e.printStackTrace(); } finally { if (out != null) { try { out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); } } mCache.put(file); } } /** * 保存 byte数据 到 缓存中 * * @param key * 保存的key * @param value * 保存的数据 * @param saveTime * 保存的时间,单位:秒 */ public void put(String key, byte[] value, int saveTime) { put(key, Utils.newByteArrayWithDateInfo(saveTime, value)); } /** * 获取 byte 数据 * * @param key * @return byte 数据 */ public byte[] getAsBinary(String key) { RandomAccessFile RAFile = null; boolean removeFile = false; try { File file = mCache.get(key); if (!file.exists()) return null; RAFile = new RandomAccessFile(file, "r"); byte[] byteArray = new byte[(int) RAFile.length()]; RAFile.read(byteArray); if (!Utils.isDue(byteArray)) { return Utils.clearDateInfo(byteArray); } else { removeFile = true; return null; } } catch (Exception e) { e.printStackTrace(); return null; } finally { if (RAFile != null) { try { RAFile.close(); } catch (IOException e) { e.printStackTrace(); } } if (removeFile) remove(key); } } // ======================================= // ============= 序列化 数据 读写 =============== // ======================================= /** * 保存 Serializable数据 到 缓存中 * * @param key * 保存的key * @param value * 保存的value */ public void put(String key, Serializable value) { put(key, value, -1); } /** * 保存 Serializable数据到 缓存中 * * @param key * 保存的key * @param value * 保存的value * @param saveTime * 保存的时间,单位:秒 */ public void put(String key, Serializable value, int saveTime) { ByteArrayOutputStream baos = null; ObjectOutputStream oos = null; try { baos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(baos); oos.writeObject(value); byte[] data = baos.toByteArray(); if (saveTime != -1) { put(key, data, saveTime); } else { put(key, data); } } catch (Exception e) { e.printStackTrace(); } finally { try { oos.close(); } catch (IOException e) { } } } /** * 读取 Serializable数据 * * @param key * @return Serializable 数据 */ public Object getAsObject(String key) { byte[] data = getAsBinary(key); if (data != null) { ByteArrayInputStream bais = null; ObjectInputStream ois = null; try { bais = new ByteArrayInputStream(data); ois = new ObjectInputStream(bais); Object reObject = ois.readObject(); return reObject; } catch (Exception e) { e.printStackTrace(); return null; } finally { try { if (bais != null) bais.close(); } catch (IOException e) { e.printStackTrace(); } try { if (ois != null) ois.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } // ======================================= // ============== bitmap 数据 读写 ============= // ======================================= /** * 保存 bitmap 到 缓存中 * * @param key * 保存的key * @param value * 保存的bitmap数据 */ public void put(String key, Bitmap value) { put(key, Utils.Bitmap2Bytes(value)); } /** * 保存 bitmap 到 缓存中 * * @param key * 保存的key * @param value * 保存的 bitmap 数据 * @param saveTime * 保存的时间,单位:秒 */ public void put(String key, Bitmap value, int saveTime) { put(key, Utils.Bitmap2Bytes(value), saveTime); } /** * 读取 bitmap 数据 * * @param key * @return bitmap 数据 */ public Bitmap getAsBitmap(String key) { if (getAsBinary(key) == null) { return null; } return Utils.Bytes2Bimap(getAsBinary(key)); } // ======================================= // ============= drawable 数据 读写 ============= // ======================================= /** * 保存 drawable 到 缓存中 * * @param key * 保存的key * @param value * 保存的drawable数据 */ public void put(String key, Drawable value) { put(key, Utils.drawable2Bitmap(value)); } /** * 保存 drawable 到 缓存中 * * @param key * 保存的key * @param value * 保存的 drawable 数据 * @param saveTime * 保存的时间,单位:秒 */ public void put(String key, Drawable value, int saveTime) { put(key, Utils.drawable2Bitmap(value), saveTime); } /** * 读取 Drawable 数据 * * @param key * @return Drawable 数据 */ public Drawable getAsDrawable(String key) { if (getAsBinary(key) == null) { return null; } return Utils.bitmap2Drawable(Utils.Bytes2Bimap(getAsBinary(key))); } /** * 获取缓存文件 * * @param key * @return value 缓存的文件 */ public File file(String key) { File f = mCache.newFile(key); if (f.exists()) return f; return null; } /** * 移除某个key * * @param key * @return 是否移除成功 */ public boolean remove(String key) { return mCache.remove(key); } /** * 清除所有数据 */ public void clear() { mCache.clear(); } /** * @title 缓存管理器 * @author 杨福海(michael) www.yangfuhai.com * @version 1.0 */ public class ACacheManager { private final AtomicLong cacheSize; private final AtomicInteger cacheCount; private final long sizeLimit; private final int countLimit; private final Map lastUsageDates = Collections .synchronizedMap(new HashMap()); protected File cacheDir; private ACacheManager(File cacheDir, long sizeLimit, int countLimit) { this.cacheDir = cacheDir; this.sizeLimit = sizeLimit; this.countLimit = countLimit; cacheSize = new AtomicLong(); cacheCount = new AtomicInteger(); calculateCacheSizeAndCacheCount(); } /** * 计算 cacheSize和cacheCount */ private void calculateCacheSizeAndCacheCount() { new Thread(new Runnable() { @Override public void run() { int size = 0; int count = 0; File[] cachedFiles = cacheDir.listFiles(); if (cachedFiles != null) { for (File cachedFile : cachedFiles) { size += calculateSize(cachedFile); count += 1; lastUsageDates.put(cachedFile, cachedFile.lastModified()); } cacheSize.set(size); cacheCount.set(count); } } }).start(); } private void put(File file) { int curCacheCount = cacheCount.get(); while (curCacheCount + 1 > countLimit) { long freedSize = removeNext(); cacheSize.addAndGet(-freedSize); curCacheCount = cacheCount.addAndGet(-1); } cacheCount.addAndGet(1); long valueSize = calculateSize(file); long curCacheSize = cacheSize.get(); while (curCacheSize + valueSize > sizeLimit) { long freedSize = removeNext(); curCacheSize = cacheSize.addAndGet(-freedSize); } cacheSize.addAndGet(valueSize); Long currentTime = System.currentTimeMillis(); file.setLastModified(currentTime); lastUsageDates.put(file, currentTime); } private File get(String key) { File file = newFile(key); Long currentTime = System.currentTimeMillis(); file.setLastModified(currentTime); lastUsageDates.put(file, currentTime); return file; } private File newFile(String key) { return new File(cacheDir, key.hashCode() + ""); } private boolean remove(String key) { File image = get(key); return image.delete(); } private void clear() { lastUsageDates.clear(); cacheSize.set(0); File[] files = cacheDir.listFiles(); if (files != null) { for (File f : files) { f.delete(); } } } /** * 移除旧的文件 * * @return */ private long removeNext() { if (lastUsageDates.isEmpty()) { return 0; } Long oldestUsage = null; File mostLongUsedFile = null; Set> entries = lastUsageDates.entrySet(); synchronized (lastUsageDates) { for (Entry entry : entries) { if (mostLongUsedFile == null) { mostLongUsedFile = entry.getKey(); oldestUsage = entry.getValue(); } else { Long lastValueUsage = entry.getValue(); if (lastValueUsage < oldestUsage) { oldestUsage = lastValueUsage; mostLongUsedFile = entry.getKey(); } } } } long fileSize = calculateSize(mostLongUsedFile); if (mostLongUsedFile.delete()) { lastUsageDates.remove(mostLongUsedFile); } return fileSize; } private long calculateSize(File file) { return file.length(); } } /** * @title 时间计算工具类 * @author 杨福海(michael) www.yangfuhai.com * @version 1.0 */ private static class Utils { /** * 判断缓存的String数据是否到期 * * @param str * @return true:到期了 false:还没有到期 */ private static boolean isDue(String str) { return isDue(str.getBytes()); } /** * 判断缓存的byte数据是否到期 * * @param data * @return true:到期了 false:还没有到期 */ private static boolean isDue(byte[] data) { String[] strs = getDateInfoFromDate(data); if (strs != null && strs.length == 2) { String saveTimeStr = strs[0]; while (saveTimeStr.startsWith("0")) { saveTimeStr = saveTimeStr .substring(1, saveTimeStr.length()); } long saveTime = Long.valueOf(saveTimeStr); long deleteAfter = Long.valueOf(strs[1]); if (System.currentTimeMillis() > saveTime + deleteAfter * 1000) { return true; } } return false; } private static String newStringWithDateInfo(int second, String strInfo) { return createDateInfo(second) + strInfo; } private static byte[] newByteArrayWithDateInfo(int second, byte[] data2) { byte[] data1 = createDateInfo(second).getBytes(); byte[] retdata = new byte[data1.length + data2.length]; System.arraycopy(data1, 0, retdata, 0, data1.length); System.arraycopy(data2, 0, retdata, data1.length, data2.length); return retdata; } private static String clearDateInfo(String strInfo) { if (strInfo != null && hasDateInfo(strInfo.getBytes())) { strInfo = strInfo.substring(strInfo.indexOf(mSeparator) + 1, strInfo.length()); } return strInfo; } private static byte[] clearDateInfo(byte[] data) { if (hasDateInfo(data)) { return copyOfRange(data, indexOf(data, mSeparator) + 1, data.length); } return data; } private static boolean hasDateInfo(byte[] data) { return data != null && data.length > 15 && data[13] == '-' && indexOf(data, mSeparator) > 14; } private static String[] getDateInfoFromDate(byte[] data) { if (hasDateInfo(data)) { String saveDate = new String(copyOfRange(data, 0, 13)); String deleteAfter = new String(copyOfRange(data, 14, indexOf(data, mSeparator))); return new String[] { saveDate, deleteAfter }; } return null; } private static int indexOf(byte[] data, char c) { for (int i = 0; i < data.length; i++) { if (data[i] == c) { return i; } } return -1; } private static byte[] copyOfRange(byte[] original, int from, int to) { int newLength = to - from; if (newLength < 0) throw new IllegalArgumentException(from + " > " + to); byte[] copy = new byte[newLength]; System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); return copy; } private static final char mSeparator = ' '; private static String createDateInfo(int second) { String currentTime = System.currentTimeMillis() + ""; while (currentTime.length() < 13) { currentTime = "0" + currentTime; } return currentTime + "-" + second + mSeparator; } /* * Bitmap → byte[] */ private static byte[] Bitmap2Bytes(Bitmap bm) { if (bm == null) { return null; } ByteArrayOutputStream baos = new ByteArrayOutputStream(); bm.compress(Bitmap.CompressFormat.PNG, 100, baos); return baos.toByteArray(); } /* * byte[] → Bitmap */ private static Bitmap Bytes2Bimap(byte[] b) { if (b.length == 0) { return null; } return BitmapFactory.decodeByteArray(b, 0, b.length); } /* * Drawable → Bitmap */ private static Bitmap drawable2Bitmap(Drawable drawable) { if (drawable == null) { return null; } // 取 drawable 的长宽 int w = drawable.getIntrinsicWidth(); int h = drawable.getIntrinsicHeight(); // 取 drawable 的颜色格式 Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; // 建立对应 bitmap Bitmap bitmap = Bitmap.createBitmap(w, h, config); // 建立对应 bitmap 的画布 Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, w, h); // 把 drawable 内容画到画布中 drawable.draw(canvas); return bitmap; } /* * Bitmap → Drawable */ @SuppressWarnings("deprecation") private static Drawable bitmap2Drawable(Bitmap bm) { if (bm == null) { return null; } return new BitmapDrawable(bm); } } } ================================================ FILE: app/src/main/java/com/example/discover/model/AuthorVideoModel.java ================================================ package com.example.discover.model; import com.example.discover.bean.AuthorDetailBean; import com.example.discover.bean.DetailBean.ItemList; import com.example.discover.http.HttpClient; import com.example.discover.http.RequestListener; import com.example.discover.ui.Search.Author.ItemFragment; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; import java.util.List; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; /** * Created by monkeyWiiu on 2018/1/25. */ public class AuthorVideoModel { public static void showVideo(ItemFragment context, int start, int id, String strategy, final RequestListener listener) { HttpClient.Builder.getEyeService().getAuthorRelated(start, id, strategy) .compose(context.bindToLifecycle()) .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber() { @Override public void onSubscribe(Subscription s) { s.request(Long.MAX_VALUE); } @Override public void onNext(AuthorDetailBean itemLists) { listener.onSuccess(itemLists); } @Override public void onError(Throwable t) { t.printStackTrace(); listener.onFailed(t); } @Override public void onComplete() { listener.onCompleted(); } }); } } ================================================ FILE: app/src/main/java/com/example/discover/model/GankModel.java ================================================ package com.example.discover.model; import com.example.discover.bean.GankBean; import com.example.discover.http.HttpClient; import com.example.discover.http.RequestListener; import com.example.discover.utils.DebugUtil; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; /** * Created by monkeyWiiu on 2018/2/3. */ public class GankModel { public static void loadGank(String id, int num, int page, final RequestListener listener) { HttpClient.Builder.getGankService().getGankData(id, num, page) .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber() { @Override public void onSubscribe(Subscription s) { s.request(Long.MAX_VALUE); } @Override public void onNext(GankBean gankBean) { DebugUtil.debug("welfaress", "successed"); listener.onSuccess(gankBean); } @Override public void onError(Throwable t) { DebugUtil.debug("welfaress", "failed"); listener.onFailed(t); } @Override public void onComplete() { } }); } } ================================================ FILE: app/src/main/java/com/example/discover/model/HotVideoModel.java ================================================ package com.example.discover.model; import com.example.discover.bean.HotEyeBean; import com.example.discover.bean.LitePalBean.LikeVideo; import com.example.discover.http.HttpClient; import com.example.discover.http.RequestListener; import com.example.discover.ui.Video.VideoFragment; import com.example.discover.utils.DebugUtil; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; /** * Created by Administrator on 2017/12/12 0012. */ public class HotVideoModel { public static void showVideo(VideoFragment context, int start, int num, final RequestListener listener) { DebugUtil.debug("test12345", "successed111"); HttpClient.Builder.getEyeService().getEyeHot(start, num) .compose(context.bindToLifecycle()) .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber() { @Override public void onSubscribe(Subscription s) { s.request(Long.MAX_VALUE); } @Override public void onNext(HotEyeBean hotEyeBean) { listener.onSuccess(hotEyeBean); } @Override public void onError(Throwable t) { listener.onFailed(t); } @Override public void onComplete() { } }); } } ================================================ FILE: app/src/main/java/com/example/discover/model/ReplyModel.java ================================================ package com.example.discover.model; import com.example.discover.bean.DetailBean.Replies; import com.example.discover.bean.DetailBean.ReplyList; import com.example.discover.http.HttpClient; import com.example.discover.http.RequestListener; import com.trello.rxlifecycle2.components.support.RxAppCompatActivity; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; import io.reactivex.Flowable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; /** * Created by monkeyWiiu on 2018/1/30. */ public class ReplyModel { public static void showReplies(RxAppCompatActivity activity, boolean clean, int lastSequence, int id, final RequestListener listener) { Flowable repliesFlowable; if (clean) { repliesFlowable = HttpClient.Builder.getEyeService().fetchReplies(id); }else { repliesFlowable = HttpClient.Builder.getEyeService().fetchReplies(id, lastSequence); } repliesFlowable.compose(activity.bindToLifecycle()) .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber() { @Override public void onSubscribe(Subscription s) { s.request(Long.MAX_VALUE); } @Override public void onNext(Replies replies) { listener.onSuccess(replies); } @Override public void onError(Throwable t) { listener.onFailed(t); } @Override public void onComplete() { } }); } } ================================================ FILE: app/src/main/java/com/example/discover/model/SearchModel.java ================================================ package com.example.discover.model; import android.content.Context; import com.example.discover.ResultActivity; import com.example.discover.SearchActivity; import com.example.discover.app.Constant; import com.example.discover.bean.DetailBean.FindCategory; import com.example.discover.bean.DetailBean.SectionList; import com.example.discover.bean.ResultBean; import com.example.discover.http.HttpClient; import com.example.discover.http.RequestListener; import com.example.discover.ui.Search.SearchFragment; import com.example.discover.utils.DebugUtil; import org.reactivestreams.Publisher; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; import java.util.ArrayList; import java.util.List; import io.reactivex.Flowable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.functions.Function; import io.reactivex.functions.Predicate; import io.reactivex.schedulers.Schedulers; /** * Created by monkeyWiiu on 2018/1/16. */ public class SearchModel { public static void showDetail(SearchFragment context, List idList, final RequestListener listener) { List> sources = new ArrayList<>(); for (int id : idList) { sources.add(HttpClient.Builder.getEyeService().getEyeCateGory(id)); } Flowable.mergeDelayError(sources) .compose(context.bindToLifecycle()) .filter(new Predicate() { @Override public boolean test(FindCategory findCategory) throws Exception { return findCategory != null; } }) .filter(new Predicate() { @Override public boolean test(FindCategory findCategory) throws Exception { return findCategory.sectionList != null; } }) .flatMap(new Function>() { @Override public Publisher apply(FindCategory findCategory) throws Exception { return Flowable.fromIterable(findCategory.sectionList); } }) .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber() { @Override public void onSubscribe(Subscription s) { s.request(Long.MAX_VALUE); } @Override public void onNext(SectionList sectionList) { DebugUtil.debug("searchmodel", "chenggon"); listener.onSuccess(sectionList); } @Override public void onError(Throwable t) { DebugUtil.debug("searchmodel", "failed"); listener.onFailed(t); } @Override public void onComplete() { listener.onCompleted(); } }); } public static void showTrendingTag(SearchActivity context, final RequestListener listener) { HttpClient.Builder.getEyeService().getTrendingTag() .compose(context.>bindToLifecycle()) .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber>() { @Override public void onSubscribe(Subscription s) { s.request(Long.MAX_VALUE); } @Override public void onNext(List list) { listener.onSuccess(list); } @Override public void onError(Throwable t) { listener.onFailed(t); } @Override public void onComplete() { } }); } public static void showResult(ResultActivity context, String key, int start, final RequestListener listener) { HttpClient.Builder.getEyeService().getResult(key, start) .compose(context.bindToLifecycle()) .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber() { @Override public void onSubscribe(Subscription s) { s.request(Long.MAX_VALUE); } @Override public void onNext(ResultBean resultBean) { listener.onSuccess(resultBean); } @Override public void onError(Throwable t) { listener.onFailed(t); } @Override public void onComplete() { } }); } } ================================================ FILE: app/src/main/java/com/example/discover/ui/DiscoverFragment.java ================================================ package com.example.discover.ui; import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.view.View; import com.example.discover.R; import com.example.discover.TestActivity; import com.example.discover.app.Constant; import com.example.discover.base.BaseFragment; import com.example.discover.bean.HotEyeBean; import com.example.discover.databinding.FragmentDiscoverBinding; import com.example.discover.http.cahe.ACache; import com.example.discover.utils.DebugUtil; import java.util.ArrayList; import java.util.List; /** * Created by Administrator on 2017/12/5 0005. */ public class DiscoverFragment extends BaseFragment { private boolean isPrepare = false; private HotEyeBean hotEyeBean; @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); showContentView(); isPrepare = true; loadData(); bindingView.testText.setText(Test()); } public StringBuffer Test() { StringBuffer text = new StringBuffer(); for (int i = 0; i < 2000; i++) { text.append("你好你好你好"); } return text; } @Override public void loadData() { if (!isPrepare || !isVisibile) { return; } /*ACache cache = ACache.get(getContext()); hotEyeBean = (HotEyeBean) cache.getAsObject(Constant.EYE_VIDEO); if (hotEyeBean == null) { DebugUtil.debug("test111", "null"); } bindingView.text.setText("bu");*/ } @Override public int setContentView() { return R.layout.fragment_discover; } } ================================================ FILE: app/src/main/java/com/example/discover/ui/Personal/PersonalFragment.java ================================================ package com.example.discover.ui.Personal; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import com.example.discover.R; import com.example.discover.adapter.MyFragmentPagerAdapter; import com.example.discover.base.BaseFragment; import com.example.discover.databinding.FragmentPersonalBinding; import com.example.discover.ui.Personal.child.FollowFragment; import com.example.discover.ui.Personal.child.LikeFragment; import java.util.ArrayList; import java.util.List; /** * Created by monkeyWiiu on 2017/12/30. */ public class PersonalFragment extends BaseFragment { private List fragmentList; private List titleList; @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); initFragmentList(); loadViewPager(); showContentView(); } @Override public int setContentView() { return R.layout.fragment_personal; } public void initFragmentList() { fragmentList = new ArrayList<>(); fragmentList.add(new LikeFragment()); fragmentList.add(new FollowFragment()); titleList = new ArrayList<>(); titleList.add("喜欢的作品"); titleList.add("关注"); } public void loadViewPager() { MyFragmentPagerAdapter adapter = new MyFragmentPagerAdapter(getChildFragmentManager(), fragmentList, titleList); bindingView.vpCollect.setAdapter(adapter); bindingView.vpCollect.setOffscreenPageLimit(2); adapter.notifyDataSetChanged(); bindingView.tabCollect.setTabMode(TabLayout.MODE_FIXED); bindingView.tabCollect.setupWithViewPager(bindingView.vpCollect); } } ================================================ FILE: app/src/main/java/com/example/discover/ui/Personal/child/FollowFragment.java ================================================ package com.example.discover.ui.Personal.child; import android.os.Bundle; import android.os.Handler; import android.support.annotation.Nullable; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import com.example.discover.R; import com.example.discover.adapter.FollowRecyclerAdapter; import com.example.discover.base.BaseFragment; import com.example.discover.bean.LitePalBean.Follow; import com.example.discover.bean.LitePalBean.LikeVideo; import com.example.discover.databinding.FragmentFollowBinding; import com.example.discover.utils.DebugUtil; import com.example.zmenu.PUtils; import com.jcodecraeer.xrecyclerview.XRecyclerView; import org.litepal.crud.DataSupport; import java.util.List; /** * Created by monkeyWiiu on 2018/1/26. */ public class FollowFragment extends BaseFragment{ private boolean isPrepare = false; private boolean isFirst = true; private int mNum = 15; private int currentId; private int totalNum; private List followList; private FollowRecyclerAdapter adapter; private LinearLayoutManager mLayoutManager; @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); initRecyclerView(); showContentView(); totalNum = DataSupport.findAll(Follow.class).size(); isPrepare = true; } @Override protected void loadData() { if (!isVisibile || !isPrepare || !isFirst) { return; } followList = DataSupport.order("id desc").limit(mNum).find(Follow.class); if (followList != null) { setAdapter(followList); } //避免重复加载 isFirst = false; } private void initRecyclerView() { mLayoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false); bindingView.rvFollow.setLayoutManager(mLayoutManager); //下拉刷新 bindingView.srlRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { bindingView.rvFollow.postDelayed(new Runnable() { @Override public void run() { followList = DataSupport.order("id desc").limit(mNum).find(Follow.class); totalNum = DataSupport.findAll(Follow.class).size(); if (followList != null && followList.size() > 0) { currentId = followList.get(followList.size() - 1).getId(); } setAdapter(followList); adapter.notifyDataSetChanged(); bindingView.srlRefresh.setRefreshing(false); } }, 1000); } }); //上拉加载更多 bindingView.rvFollow.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); int lastVisibleItem = mLayoutManager.findLastVisibleItemPosition(); final int totalItemCount = mLayoutManager.getItemCount(); if (lastVisibleItem == totalItemCount - 1 && !adapter.isLoading()) { adapter.updateStateLoad(true); followList = DataSupport.order("id desc").limit(mNum).where("id < ?", String.valueOf(currentId)).find(Follow.class); if (followList != null && followList.size() > 0) { currentId = followList.get(followList.size() - 1).getId(); } new Handler().postDelayed(new Runnable() { @Override public void run() { if (totalItemCount - 1 == totalNum) { adapter.hideLoading(); } adapter.updateStateLoad(false); adapter.addAll(followList); adapter.notifyDataSetChanged(); } }, 1000); } } //recyclerview滑动时ZMemu自动隐藏 @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState == XRecyclerView.SCROLL_STATE_IDLE && PUtils.getInstance().getViewList() != null) { for (int i = 0; i < PUtils.getInstance().getViewList().size(); i++) { PUtils.getInstance().getViewList().get(i).show(); } } else { for (int i = 0; i < PUtils.getInstance().getViewList().size(); i++) { PUtils.getInstance().getViewList().get(i).hide(); } } } }); } private void setAdapter(List list) { adapter = new FollowRecyclerAdapter(getContext()); adapter.clear(); adapter.addAll(list); bindingView.rvFollow.setAdapter(adapter); } @Override public int setContentView() { return R.layout.fragment_follow; } } ================================================ FILE: app/src/main/java/com/example/discover/ui/Personal/child/LikeFragment.java ================================================ package com.example.discover.ui.Personal.child; import android.os.Bundle; import android.os.Handler; import android.support.annotation.Nullable; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import com.example.discover.R; import com.example.discover.adapter.LikeVideoRecyclerAdapter; import com.example.discover.base.BaseFragment; import com.example.discover.bean.LitePalBean.LikeVideo; import com.example.discover.databinding.FragmentPersonalLikeBinding; import com.example.discover.ui.RecyclerViewNoBugLinearLayoutManager; import com.example.discover.utils.DebugUtil; import com.example.zmenu.PUtils; import com.jcodecraeer.xrecyclerview.XRecyclerView; import org.litepal.crud.DataSupport; import java.util.List; import cn.jzvd.JZVideoPlayer; /** * Created by monkeyWiiu on 2017/12/30. */ public class LikeFragment extends BaseFragment { private boolean isPrepare = false; private List likeVideoList; private boolean isFirst = true; private LikeVideoRecyclerAdapter mLikeVideoAdapter; private LinearLayoutManager mLayoutManager; private int mNum = 5; private int currentId; private int largestId; private int totalNum; @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); isPrepare = true; likeVideoList = DataSupport.order("id desc").limit(mNum).find(LikeVideo.class); if (DataSupport.findLast(LikeVideo.class) != null) { largestId = DataSupport.findLast(LikeVideo.class).getId(); } totalNum = DataSupport.findAll(LikeVideo.class).size(); initRecyclerView(); loadData(); showContentView(); } @Override public void loadData() { if (!isPrepare || !isVisibile || !isFirst) { return; } setAdapter(); //避免重复加载 isFirst = false; } public void initRecyclerView() { mLikeVideoAdapter = new LikeVideoRecyclerAdapter(getContext()); mLayoutManager = new RecyclerViewNoBugLinearLayoutManager(getActivity()); mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); bindingView.rvLikeVideo.setLayoutManager(mLayoutManager); bindingView.srlRefresh.setColorSchemeResources(R.color.background5, R.color.background2, R.color.background4); bindingView.srlRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { JZVideoPlayer.goOnPlayOnPause(); bindingView.rvLikeVideo.postDelayed(new Runnable() { @Override public void run() { likeVideoList = DataSupport.order("id desc").limit(mNum).find(LikeVideo.class); totalNum = DataSupport.findAll(LikeVideo.class).size(); if (likeVideoList != null && likeVideoList.size() > 0) { currentId = likeVideoList.get(likeVideoList.size() - 1).getId(); largestId = DataSupport.findLast(LikeVideo.class).getId(); } setAdapter(); mLikeVideoAdapter.notifyDataSetChanged(); bindingView.srlRefresh.setRefreshing(false); } }, 1000); } }); //上拉加载更多 bindingView.rvLikeVideo.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); int lastVisibleItem = mLayoutManager.findLastVisibleItemPosition(); final int totalItemCount = mLayoutManager.getItemCount(); if (lastVisibleItem == totalItemCount - 1 && !mLikeVideoAdapter.isLoading()) { mLikeVideoAdapter.updateStateLoad(true); likeVideoList = DataSupport.order("id desc").limit(mNum).where("id < ?", String.valueOf(currentId)).find(LikeVideo.class); if (likeVideoList != null && likeVideoList.size() > 0) { currentId = likeVideoList.get(likeVideoList.size() - 1).getId(); DebugUtil.debug("totalTest", "currentIdLoad" + currentId); } new Handler().postDelayed(new Runnable() { @Override public void run() { DebugUtil.debug("likefollowtest", totalItemCount +"/" +totalNum); if (totalItemCount - 1 == totalNum) { mLikeVideoAdapter.hideLoading(); } mLikeVideoAdapter.updateStateLoad(false); mLikeVideoAdapter.addAll(likeVideoList); mLikeVideoAdapter.notifyDataSetChanged(); } }, 1000); } } //recyclerview滑动时ZMemu自动隐藏 @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState == XRecyclerView.SCROLL_STATE_IDLE && PUtils.getInstance().getViewList() != null) { for (int i = 0; i < PUtils.getInstance().getViewList().size(); i++) { PUtils.getInstance().getViewList().get(i).show(); } } else { for (int i = 0; i < PUtils.getInstance().getViewList().size(); i++) { PUtils.getInstance().getViewList().get(i).hide(); } } } }); //删除item mLikeVideoAdapter.setOnClickListener(new LikeVideoRecyclerAdapter.MyDeleteClickListener() { @Override public void onDelete(int position, int id) { DataSupport.deleteAll(LikeVideo.class, "id = ?", String.valueOf(id)); totalNum = DataSupport.findAll(LikeVideo.class).size(); DebugUtil.debug("totalTest", "largestId" + largestId + "position:" + position); mLikeVideoAdapter.delete(position); } }); } public void setAdapter() { mLikeVideoAdapter.clear(); mLikeVideoAdapter.addAll(likeVideoList); bindingView.rvLikeVideo.setAdapter(mLikeVideoAdapter); } @Override public int setContentView() { return R.layout.fragment_personal_like; } } ================================================ FILE: app/src/main/java/com/example/discover/ui/RecyclerViewNoBugLinearLayoutManager.java ================================================ package com.example.discover.ui; import android.content.Context; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; /** * Created by monkeyWiiu on 2018/1/6. */ public class RecyclerViewNoBugLinearLayoutManager extends LinearLayoutManager{ public RecyclerViewNoBugLinearLayoutManager(Context context) { super(context); } public RecyclerViewNoBugLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout); } public RecyclerViewNoBugLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } //避免了RecyclerView可能出现的holder数组越界Bug @Override public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { try { super.onLayoutChildren(recycler, state); } catch (Exception e) { e.printStackTrace(); } } } ================================================ FILE: app/src/main/java/com/example/discover/ui/Search/Author/ItemFragment.java ================================================ package com.example.discover.ui.Search.Author; import android.os.Bundle; import android.os.Handler; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import com.example.discover.R; import com.example.discover.adapter.VideoRecyclerAdapter; import com.example.discover.app.Constant; import com.example.discover.base.BaseFragment; import com.example.discover.bean.AuthorDetailBean; import com.example.discover.bean.DetailBean.ItemList; import com.example.discover.bean.HotEyeBean; import com.example.discover.databinding.FragmentVideoBinding; import com.example.discover.http.RequestListener; import com.example.discover.http.cahe.ACache; import com.example.discover.model.AuthorVideoModel; import com.example.discover.model.HotVideoModel; import com.example.discover.ui.RecyclerViewNoBugLinearLayoutManager; import com.example.discover.utils.DebugUtil; import com.example.zmenu.FloatButton; import com.example.zmenu.PUtils; import com.jcodecraeer.xrecyclerview.XRecyclerView; import java.util.List; import cn.jzvd.JZVideoPlayer; /** * Created by monkeyWiiu on 2018/1/23. */ public class ItemFragment extends BaseFragment { private static final String STRATEGY = "Strategy"; private static final String ID = "AuthorId" ; private int id; private int start = 0; private int num = 10;//一次请求的数目 private String mStrategy; private int mPage = 1; private boolean isPrepare = false; private boolean isFirst = true; private VideoRecyclerAdapter mVideoAdapter; private LinearLayoutManager mLayoutManager; public static ItemFragment newInstance(String strategy, int id) { ItemFragment fragment = new ItemFragment(); Bundle args = new Bundle(); args.putString(STRATEGY, strategy); args.putInt(ID, id); fragment.setArguments(args); return fragment; } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { mStrategy = getArguments().getString(STRATEGY); id = getArguments().getInt(ID); } } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); initRecyclerView(); //准备就绪 isPrepare = true; //解决懒加载首页不显示,手动loadData() if ("date".equals(mStrategy)) { loadData(); } } @Override public void loadData() { if (!isPrepare || !isVisibile || !isFirst) { return; } loadVideo(); //避免重复加载 isFirst = false; } public void loadVideo() { DebugUtil.debug("loadvideo", "load"); AuthorVideoModel.showVideo(this, start, id, mStrategy, new RequestListener() { @Override public void onSuccess(Object object) { showContentView(); AuthorDetailBean detailBean = (AuthorDetailBean) object; List list = detailBean.getItemList(); if (mPage == 1) { if(detailBean != null && detailBean.getItemList() != null&& detailBean.getItemList().size() > 0) { DebugUtil.debug("test123456", "video" + detailBean.getItemList().size()); bindingView.srlVideo.setRefreshing(false); setAdapter(detailBean); } } else { if(detailBean != null && detailBean.getItemList() != null&& detailBean.getItemList().size() > 0) { mVideoAdapter.updateStateLoad(false); mVideoAdapter.addAll(detailBean.getItemList()); mVideoAdapter.notifyDataSetChanged(); } else { //数据刷新到底了 mVideoAdapter.hideLoading(); } } } @Override public void onFailed(Throwable t) { DebugUtil.debug("loadvideo", "failed"); bindingView.srlVideo.setRefreshing(false); if (mVideoAdapter.getItemCount() == 1) { Error(); } } @Override public void onCompleted() { } }); } @Override public int setContentView() { return R.layout.fragment_video; } public void initRecyclerView() { mVideoAdapter = new VideoRecyclerAdapter(getContext()); mVideoAdapter.setAuthor(true); mLayoutManager = new RecyclerViewNoBugLinearLayoutManager(getActivity()); mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); bindingView.rvVideo.setLayoutManager(mLayoutManager); bindingView.srlVideo.setColorSchemeResources(R.color.background5, R.color.background2, R.color.background4); //上拉刷新 bindingView.srlVideo.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { JZVideoPlayer.goOnPlayOnPause(); bindingView.srlVideo.postDelayed(new Runnable() { @Override public void run() { mPage = 1; start = 5; loadVideo(); } }, 1000); } }); //设置recycler滚动监听 bindingView.rvVideo.setOnScrollListener(new RecyclerView.OnScrollListener() { //下拉加载更多 @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); int lastVisibleItem = mLayoutManager.findLastVisibleItemPosition(); int totalItemCount = mLayoutManager.getItemCount(); DebugUtil.debug("position1", lastVisibleItem + " " + totalItemCount); if (lastVisibleItem == totalItemCount - 1 && !mVideoAdapter.isLoading()) { mVideoAdapter.updateStateLoad(true); mPage++; start += num; new Handler().postDelayed(new Runnable() { @Override public void run() { loadVideo(); } }, 1000); } } }); } public void setAdapter(AuthorDetailBean authorDetailBean) { mVideoAdapter.clear(); mVideoAdapter.addAll(authorDetailBean.getItemList()); bindingView.rvVideo.setAdapter(mVideoAdapter); } @Override public void onPause() { JZVideoPlayer.releaseAllVideos(); super.onPause(); } } ================================================ FILE: app/src/main/java/com/example/discover/ui/Search/SearchFragment.java ================================================ package com.example.discover.ui.Search; import android.content.Intent; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.design.widget.AppBarLayout; import android.support.design.widget.CoordinatorLayout; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; import com.example.discover.R; import com.example.discover.SearchActivity; import com.example.discover.ViewBigImageActivity; import com.example.discover.adapter.SearchRecyclerAdapter; import com.example.discover.adapter.SelectTypeRecyclerAdapter; import com.example.discover.app.Constant; import com.example.discover.base.BaseFragment; import com.example.discover.bean.DetailBean.ACacheFindList; import com.example.discover.bean.DetailBean.ItemList; import com.example.discover.bean.DetailBean.SectionList; import com.example.discover.bean.LitePalBean.LabelType; import com.example.discover.databinding.FragmentSearchBinding; import com.example.discover.http.RequestListener; import com.example.discover.http.cahe.ACache; import com.example.discover.model.SearchModel; import com.example.discover.ui.RecyclerViewNoBugLinearLayoutManager; import com.example.discover.utils.DebugUtil; import com.example.discover.utils.DensityUtil; import com.example.discover.utils.LitePalUtil; import com.example.discover.view.CustomView.CategoryPopupWindow; import com.example.zmenu.PUtils; import com.jakewharton.rxbinding2.view.RxView; import com.jcodecraeer.xrecyclerview.XRecyclerView; import org.litepal.crud.DataSupport; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import cn.jzvd.JZVideoPlayer; import io.reactivex.functions.Consumer; /** * Created by monkeyWiiu on 2018/1/12. */ public class SearchFragment extends BaseFragment implements View.OnClickListener { private boolean isPrepare = false; private boolean isFirst = true; private List categoryIdList = new ArrayList<>(); private ACacheFindList findList; private List combineList = new ArrayList<>(); private List authorList = new ArrayList<>(); private ACache mCache; private RecyclerView sTRecyclerView; private SearchRecyclerAdapter adapter; private List selectLabel; private List savedLabelList; private SelectTypeRecyclerAdapter strAdapter; @Override public int setContentView() { return R.layout.fragment_search; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); showContentView(); mCache = ACache.get(getContext()); selectLabel = LitePalUtil.getSelectLabel(); init(); initSelectTypeRecyclerView(); categoryIdList = getCategoryIdList(); isPrepare = true; initMainRecycler(); } @Override protected void loadData() { if (!isPrepare || !isFirst || !isVisibile) { return; } findList = (ACacheFindList) mCache.getAsObject(Constant.EYE_FIND); if (findList != null) { bindingView.rvMain.setVisibility(View.VISIBLE); loadSuccess(); setAdapterTest(getPrecessedData()); } else { findList = new ACacheFindList(); loadDetail(); } //避免重复加载 isFirst = false; } public void initMainRecycler() { LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity()); linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); bindingView.rvMain.setLayoutManager(linearLayoutManager); bindingView.srlSearchRefresh.setColorSchemeResources(R.color.background5, R.color.background2, R.color.background4); //SwipeRefreshLayout与CoordinatorLayout嵌套刷新,动态设置SwipeRefreshLayout是否可用 bindingView.abl.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { @Override public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { if (verticalOffset >= 0) { bindingView.srlSearchRefresh.setEnabled(true); } else { bindingView.srlSearchRefresh.setEnabled(false); } } }); //上拉刷新 bindingView.srlSearchRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { JZVideoPlayer.goOnPlayOnPause(); bindingView.srlSearchRefresh.postDelayed(new Runnable() { @Override public void run() { loadDetail(); } }, 1000); } }); //recyclerview滑动时ZMemu自动隐藏 bindingView.rvMain.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState == XRecyclerView.SCROLL_STATE_IDLE && PUtils.getInstance().getViewList() != null) { for (int i = 0; i < PUtils.getInstance().getViewList().size(); i++) { PUtils.getInstance().getViewList().get(i).show(); } } else { for (int i = 0; i < PUtils.getInstance().getViewList().size(); i++) { PUtils.getInstance().getViewList().get(i).hide(); } } } }); } public void setAdapterTest(List objects) { adapter = new SearchRecyclerAdapter(getContext()); adapter.clear(); adapter.addAll(objects); bindingView.rvMain.setAdapter(adapter); adapter.notifyDataSetChanged(); } private void init() { Drawable drawable = getResources().getDrawable(R.drawable.search_normal); drawable.setBounds(0, 0 , DensityUtil.dip2px(30), DensityUtil.dip2px(30)); bindingView.tvSearch.setCompoundDrawables(drawable, null, null, null); bindingView.tvSearch.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(getContext(), SearchActivity.class); startActivity(intent); } }); bindingView.cvAdd.setOnClickListener(this); //加载失败重新加载 RxView.clicks(bindingView.rlError) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(new Consumer() { @Override public void accept(Object o) throws Exception { showLoading(); loadDetail(); } }); } private void loadDetail() { categoryIdList = getCategoryIdList(); findList = new ACacheFindList(); if (categoryIdList.size() > 0) { bindingView.rvMain.setVisibility(View.VISIBLE); SearchModel.showDetail(this, categoryIdList, new RequestListener() { @Override public void onSuccess(Object object) { SectionList find = (SectionList) object; switch (find.getType()) { case "horizontalScrollCardSection": findList.getScrollCardSection().add(find); break; case "videoListSection": findList.getVideoSection().add(find); break; case "authorSection": findList.getAuthorSection().add(find); break; } } @Override public void onFailed(Throwable throwable) { bindingView.srlSearchRefresh.setRefreshing(false); loadError(); } @Override public void onCompleted() { if (findList.getScrollCardSection().size() > 0 || findList.getVideoSection().size() > 0 || findList.getAuthorSection().size() > 0) { loadSuccess(); setAdapterTest(getPrecessedData()); mCache.remove(Constant.EYE_FIND); mCache.put(Constant.EYE_FIND, findList, 18000); } } }); } else { bindingView.rvMain.setVisibility(View.GONE); clear(); loadSuccess(); } } public void clear() { if (adapter != null) { adapter.clear(); adapter.notifyDataSetChanged(); } } public List getPrecessedData() { authorList.clear(); combineList.clear(); for (int i = 0; i < findList.getAuthorSection().size(); i++) { authorList.addAll(findList.getAuthorSection().get(i).getItemList()); } combineList.add(authorList); combineList.addAll(findList.getVideoSection()); return combineList; } public void initSelectTypeRecyclerView() { sTRecyclerView = bindingView.rvSelectType; //初始化selectTypeRecyclerView strAdapter = new SelectTypeRecyclerAdapter(selectLabel, getContext()); LinearLayoutManager layoutManager = new RecyclerViewNoBugLinearLayoutManager(getContext()); layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); sTRecyclerView.setLayoutManager(layoutManager); sTRecyclerView.setAdapter(strAdapter); //长按删除监听 strAdapter.setItemCLickListener(new SelectTypeRecyclerAdapter.ItemClickListener() { @Override public void onLongItemLClick(int position) { DebugUtil.debug("itemposition", "" + position); DataSupport.deleteAll(LabelType.class, "type = ?", selectLabel.get(position)); selectLabel.remove(position); strAdapter.notifyItemRemoved(position); strAdapter.notifyItemRangeChanged(position, selectLabel.size() - position); } }); //设置拖拽监听 /*ItemTouchHelper mItemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() { @Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { final int dragFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; return makeMovementFlags(dragFlags, swipeFlags); } @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { //strAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); return false; } @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { //strAdapter.onItemDismiss(viewHolder.getAdapterPosition()); } }); mItemTouchHelper.attachToRecyclerView(sTRecyclerView);*/ } @Override public void onClick(View v) { switch (v.getId()) { case R.id.cv_add: CategoryPopupWindow popupWindow = new CategoryPopupWindow(getContext()); popupWindow.showPopupWindow(bindingView.cvAdd); popupWindow.setPopItemClickListener(new CategoryPopupWindow.PopItemClickListener() { @Override public void ItemClick(String labelType) { //存入labelType中没有的type savedLabelList = DataSupport.findAll(LabelType.class); for (LabelType label : savedLabelList) { if (labelType.equals(label.getType())) { return; } } LabelType label = new LabelType(); label.setType(labelType); label.save(); //刷新数据 selectLabel.add(DataSupport.findLast(LabelType.class).getType()); strAdapter.notifyDataSetChanged(); } }); } } public void loadSuccess() { bindingView.srlSearchRefresh.setRefreshing(false); if (bindingView.rlError.getVisibility() == View.VISIBLE) { bindingView.rlError.setVisibility(View.GONE); } if (bindingView.rlSearchLoading.getVisibility() == View.VISIBLE) { bindingView.rlSearchLoading.setVisibility(View.GONE); } } public void showLoading() { if (bindingView.rlError.getVisibility() == View.VISIBLE) { bindingView.rlError.setVisibility(View.GONE); } if (bindingView.rlSearchLoading.getVisibility() == View.GONE) { bindingView.rlSearchLoading.setVisibility(View.VISIBLE); } } public void loadError() { if (bindingView.rlError.getVisibility() == View.GONE) { bindingView.rlError.setVisibility(View.VISIBLE); } } private List getCategoryIdList() { List labelTypes = DataSupport.findAll(LabelType.class); List list = new ArrayList<>(); for (LabelType type : labelTypes) { switch (type.getType()) { case "创意": list.add(2); break; case "开胃": list.add(4); break; case "旅行": list.add(6); break; case "预告": list.add(8); break; case "动画": list.add(10); break; case "剧情": list.add(12); break; case "广告": list.add(14); break; case "运动": list.add(18); break; case "音乐": list.add(20); break; case "记录": list.add(22); break; case "时尚": list.add(24); break; case "萌宠": list.add(26); break; case "搞笑": list.add(28); break; case "游戏": list.add(30); break; case "科普": list.add(32); break; case "集锦": list.add(34); break; case "生活": list.add(36); break; case "综艺": list.add(38); break; } } return list; } } ================================================ FILE: app/src/main/java/com/example/discover/ui/Video/VideoFragment.java ================================================ package com.example.discover.ui.Video; import android.os.Bundle; import android.os.Handler; import android.support.annotation.Nullable; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import com.example.discover.R; import com.example.discover.adapter.VideoRecyclerAdapter; import com.example.discover.app.Constant; import com.example.discover.base.BaseFragment; import com.example.discover.bean.HotEyeBean; import com.example.discover.databinding.FragmentVideoBinding; import com.example.discover.http.RequestListener; import com.example.discover.http.cahe.ACache; import com.example.discover.model.HotVideoModel; import com.example.discover.ui.RecyclerViewNoBugLinearLayoutManager; import com.example.discover.utils.DebugUtil; import com.example.zmenu.FloatButton; import com.example.zmenu.PUtils; import com.jcodecraeer.xrecyclerview.XRecyclerView; import java.util.List; import cn.jzvd.JZVideoPlayer; /** * Created by Administrator on 2017/12/9 0009. */ public class VideoFragment extends BaseFragment { private VideoRecyclerAdapter mVideoAdapter; private LinearLayoutManager mLayoutManager; private int start = 5; //前几个数据可能没有video,所以从5开始 private int num = 15; private int mPage = 1; private boolean isPrepare = false; private boolean isFirst = true; private HotEyeBean mHotEyeBean; private ACache mCache; @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mCache = ACache.get(getContext()); initRecyclerView(); //准备就绪 isPrepare = true; //解决懒加载首页不显示,手动loadData() loadData(); } @Override public void loadData() { if (!isPrepare || !isVisibile || !isFirst) { return; } //先从缓存读取数据,如果没有在请求 mHotEyeBean = (HotEyeBean) mCache.getAsObject(Constant.EYE_VIDEO); if (mHotEyeBean != null ) { showContentView(); setAdapter(mHotEyeBean); DebugUtil.debug("test12", mHotEyeBean.getItemList().get(0).getType()); }else { loadVideo(); } //避免重复加载 isFirst = false; } public void loadVideo() { HotVideoModel.showVideo(this, start, num, new RequestListener() { @Override public void onSuccess(Object object) { showContentView(); HotEyeBean hotEyeBean = (HotEyeBean) object; if (mPage == 1) { if(hotEyeBean != null && hotEyeBean.getItemList() != null&& hotEyeBean.getItemList().size() > 0) { DebugUtil.debug("test1 23456", "video" + hotEyeBean.getItemList().size()); bindingView.srlVideo.setRefreshing(false); setAdapter(hotEyeBean); //缓存5小时 mCache.remove(Constant.EYE_VIDEO); mCache.put(Constant.EYE_VIDEO, hotEyeBean, 18000); } } else { if(hotEyeBean != null && hotEyeBean.getItemList() != null&& hotEyeBean.getItemList().size() > 0) { mVideoAdapter.updateStateLoad(false); mVideoAdapter.addAll(hotEyeBean.getItemList()); mVideoAdapter.notifyDataSetChanged(); } else { //数据刷新到底了 mVideoAdapter.hideLoading(); } } } @Override public void onFailed(Throwable throwable) { bindingView.srlVideo.setRefreshing(false); if (mVideoAdapter.getItemCount() == 1) { Error(); } } @Override public void onCompleted() { } }); } @Override public int setContentView() { return R.layout.fragment_video; } public void initRecyclerView() { mVideoAdapter = new VideoRecyclerAdapter(getContext()); mLayoutManager = new RecyclerViewNoBugLinearLayoutManager(getActivity()); mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); bindingView.rvVideo.setLayoutManager(mLayoutManager); bindingView.srlVideo.setColorSchemeResources(R.color.background5, R.color.background2, R.color.background4); //上拉刷新 bindingView.srlVideo.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { JZVideoPlayer.goOnPlayOnPause(); bindingView.srlVideo.postDelayed(new Runnable() { @Override public void run() { mPage = 1; start = 5; loadVideo(); } }, 1000); } }); //设置recycler滚动监听 bindingView.rvVideo.setOnScrollListener(new RecyclerView.OnScrollListener() { //下拉加载更多 @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); int lastVisibleItem = mLayoutManager.findLastVisibleItemPosition(); int totalItemCount = mLayoutManager.getItemCount(); DebugUtil.debug("position1", lastVisibleItem + " " + totalItemCount); if (lastVisibleItem == totalItemCount - 1 && !mVideoAdapter.isLoading()) { mVideoAdapter.updateStateLoad(true); mPage++; start += num; new Handler().postDelayed(new Runnable() { @Override public void run() { DebugUtil.debug("startpage", mPage + "" + start); loadVideo(); } }, 1000); } } //recyclerview滑动时ZMemu自动隐藏 @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState == XRecyclerView.SCROLL_STATE_IDLE && PUtils.getInstance().getViewList() != null) { for (int i = 0; i < PUtils.getInstance().getViewList().size(); i++) { PUtils.getInstance().getViewList().get(i).show(); } } else { for (int i = 0; i < PUtils.getInstance().getViewList().size(); i++) { PUtils.getInstance().getViewList().get(i).hide(); } } } }); } public void setAdapter(HotEyeBean hotEyeBean) { mVideoAdapter.clear(); mVideoAdapter.addAll(hotEyeBean.getItemList()); bindingView.rvVideo.setAdapter(mVideoAdapter); } @Override protected void Refresh() { super.Refresh(); showLoading(); loadVideo(); } @Override public void onPause() { JZVideoPlayer.releaseAllVideos(); super.onPause(); } } ================================================ FILE: app/src/main/java/com/example/discover/ui/Welfare/WelFareFragment.java ================================================ package com.example.discover.ui.Welfare; import android.os.Bundle; import android.os.Handler; import android.support.annotation.Nullable; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGridLayoutManager; import android.view.View; import com.example.discover.R; import com.example.discover.adapter.WelfareAdapter; import com.example.discover.app.Constant; import com.example.discover.base.BaseFragment; import com.example.discover.base.baseadapter.OnItemClickListener; import com.example.discover.bean.GankBean; import com.example.discover.bean.HotEyeBean; import com.example.discover.databinding.FragmentWelfareBinding; import com.example.discover.http.RequestListener; import com.example.discover.http.cahe.ACache; import com.example.discover.model.GankModel; import com.example.discover.utils.DebugUtil; import com.example.discover.utils.IntentManager; import com.example.zmenu.PUtils; import com.jcodecraeer.xrecyclerview.XRecyclerView; import java.util.ArrayList; import java.util.List; /** * Created by monkeyWiiu on 2018/2/3. */ public class WelFareFragment extends BaseFragment { private boolean isFirst = true; private boolean isPrepare = false; private int num = 20; private int page = 1; private ACache mCache; private GankBean mgankBean; private WelfareAdapter welfareAdapter; private StaggeredGridLayoutManager layoutManager; private ArrayList imgList = new ArrayList<>(); @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mCache = ACache.get(getContext()); welfareAdapter = new WelfareAdapter(getContext()); initRecyclerView(); isPrepare = true; } @Override public void loadData() { if (!isPrepare || !isVisibile || !isFirst) { return; } //先从缓存读取数据,如果没有在请求 mgankBean = (GankBean) mCache.getAsObject(Constant.GANK_WELFARE); if (mgankBean != null ) { showContentView(); for (int i = 0; i < mgankBean.getResults().size(); i++) { imgList.add(mgankBean.getResults().get(i).getUrl()); } setWelfareAdapter(mgankBean); page ++; DebugUtil.debug("test12", mgankBean.getResults().get(0).getType()); }else { showWelfare(); } isFirst = false; } public void showWelfare() { GankModel.loadGank("福利", num, page, new RequestListener() { @Override public void onSuccess(Object object) { showContentView(); GankBean gankBean = (GankBean) object; if (page == 1) { if (gankBean != null && gankBean.getResults() != null && gankBean.getResults().size() > 0) { imgList.clear(); for (int i = 0; i < gankBean.getResults().size(); i++) { imgList.add(gankBean.getResults().get(i).getUrl()); } setWelfareAdapter(gankBean); mCache.remove(Constant.GANK_WELFARE); mCache.put(Constant.GANK_WELFARE, gankBean, 18000); } } else { if (gankBean.getResults() != null && gankBean.getResults().size() > 0) { welfareAdapter.updateStateLoad(false); welfareAdapter.addAll(gankBean.getResults()); welfareAdapter.notifyDataSetChanged(); for (int i = 0; i < gankBean.getResults().size(); i++) { imgList.add(gankBean.getResults().get(i).getUrl()); } } else { //数据刷新到底了 welfareAdapter.hideLoading(); } } DebugUtil.debug("welfaress", gankBean.getResults().size() + ""); page++; } @Override public void onFailed(Throwable t) { } @Override public void onCompleted() { } }); } public void initRecyclerView() { layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL); bindingView.rvWelfare.setLayoutManager(layoutManager); bindingView.rvWelfare.setOnScrollListener(new RecyclerView.OnScrollListener() { //recyclerview滑动时ZMemu自动隐藏 @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState == XRecyclerView.SCROLL_STATE_IDLE && PUtils.getInstance().getViewList() != null) { for (int i = 0; i < PUtils.getInstance().getViewList().size(); i++) { PUtils.getInstance().getViewList().get(i).show(); } } else { for (int i = 0; i < PUtils.getInstance().getViewList().size(); i++) { PUtils.getInstance().getViewList().get(i).hide(); } } int column = layoutManager.getColumnCountForAccessibility(null,null); int[] positions = new int[column]; layoutManager.findLastCompletelyVisibleItemPositions(positions); if (!welfareAdapter.isLoading()) { for (int i =0; i < positions.length; i++){ if (positions[i] >= layoutManager.getItemCount() - column && layoutManager .findViewByPosition(positions[i]).getBottom() <= recyclerView.getHeight()){ welfareAdapter.updateStateLoad(true); new Handler().postDelayed(new Runnable() { @Override public void run() { DebugUtil.debug("startpage", page + ""); showWelfare(); } }, 1000); break; } } } } }); } public void setWelfareAdapter(GankBean result) { welfareAdapter.addAll(result.getResults()); bindingView.rvWelfare.setAdapter(welfareAdapter); welfareAdapter.notifyDataSetChanged(); welfareAdapter.setOnItemClickListener(new OnItemClickListener() { @Override public void onClick(View view, GankBean.ResultBean resultBean, int position) { DebugUtil.debug("wellll", "click"); IntentManager.toBigImageActivity(getActivity(), view, position, imgList); } }); } @Override public int setContentView() { return R.layout.fragment_welfare; } } ================================================ FILE: app/src/main/java/com/example/discover/utils/BindingUtil.java ================================================ package com.example.discover.utils; import android.databinding.BindingAdapter; import android.databinding.BindingBuildInfo; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.format.DateUtils; import android.view.View; import android.widget.ImageView; import android.widget.TextView; import com.bumptech.glide.Glide; import com.example.discover.R; import com.example.discover.adapter.AuthorPopAdapter; import com.example.discover.adapter.CategoryPopAdapter; import com.example.discover.bean.DetailBean.Data; import com.example.discover.bean.DetailBean.ItemList; import com.example.discover.view.CustomView.CircleImageView; import java.util.List; /** * Created by monkeyWiiu on 2018/1/18. */ public class BindingUtil { @BindingAdapter("authorData") public static void setAuthorData(RecyclerView view, List lists) { AuthorPopAdapter authorPopAdapter = new AuthorPopAdapter(view.getContext()); LinearLayoutManager manager = new LinearLayoutManager(view.getContext() , LinearLayoutManager.HORIZONTAL, false); authorPopAdapter.addAll(lists); view.setLayoutManager(manager); view.setAdapter(authorPopAdapter); } @BindingAdapter("categoryData") public static void setCategoryData(RecyclerView view, List list) { CategoryPopAdapter categoryPopAdapter = new CategoryPopAdapter(view.getContext()); categoryPopAdapter.addAll(list); LinearLayoutManager manager = new LinearLayoutManager(view.getContext() , LinearLayoutManager.HORIZONTAL, false); view.setLayoutManager(manager); view.setAdapter(categoryPopAdapter); } @BindingAdapter("imageUrl") public static void setImage(ImageView view, String url) { Glide.with(view.getContext()).load(url) .crossFade(500) .placeholder(R.drawable.cross_image) .error(R.drawable.cross_image) .into(view); } @BindingAdapter("welfareImageUrl") public static void setWelfareImage(ImageView view, String url) { Glide.with(view.getContext()).load(url) .crossFade(500) .error(R.drawable.cross_image_welfare) .into(view); } @BindingAdapter("circleImageUrl") public static void setCircleImage(CircleImageView view, String url) { Glide.with(view.getContext()).load(url) .crossFade(800) .dontAnimate() .placeholder(R.drawable.cross_image) .error(R.drawable.close_press) .into(view); } @BindingAdapter("visibility") public static void setVisibility(View view, boolean visible) { if (visible) { view.setVisibility(View.VISIBLE); } else { view.setVisibility(View.GONE); } } @BindingAdapter("authorName") public static void setAuthorName(TextView v, ItemList item) { if (item.getData().getAuthor() != null) { v.setText(item.getData().getAuthor().getName()); } else v.setText(""); } @BindingAdapter("time") public static void setTime(TextView view, Long time) { view.setText(DateUtils.getRelativeTimeSpanString(time, System.currentTimeMillis(), DateUtils.SECOND_IN_MILLIS).toString().toLowerCase()); } @BindingAdapter("type") public static void setType(TextView view, Data data) { view.setText(data.getCategory() + " | " + TimeUtils.secToTime((int) data.getDuration())); } } ================================================ FILE: app/src/main/java/com/example/discover/utils/DebugUtil.java ================================================ package com.example.discover.utils; import android.content.Context; import android.util.Log; import android.widget.Toast; /** * Created by Administrator on 2017/12/6 0006. */ //在代码中要打印log,就直接DebugUtil.debug(....).然后如果发布的时候,就直接把这个类的DEBUG 改成false,这样所有的log就不会再打印在控制台. public class DebugUtil { public static final String TAG = "wuikii"; public static final boolean DEBUG = true; public static void toast(Context context, String content) { Toast.makeText(context, content, Toast.LENGTH_SHORT).show(); } public static void debug(String tag, String msg) { if (DEBUG) { Log.d(tag, msg); } } public static void debug(String msg) { if (DEBUG) { Log.d(TAG, msg); } } public static void error(String tag, String error) { if (DEBUG) { Log.e(tag, error); } } public static void error(String error) { if (DEBUG) { Log.e(TAG, error); } } } ================================================ FILE: app/src/main/java/com/example/discover/utils/DensityUtil.java ================================================ package com.example.discover.utils; import android.content.Context; import android.util.TypedValue; import android.view.WindowManager; import com.example.discover.app.DiscoverApplication; /** * Created by monkeyWiiu on 2017/12/20. */ public class DensityUtil { public static int getScreenWidth(Context context) { WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); int width = wm.getDefaultDisplay().getWidth(); return width; } /** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) */ public static int dip2px(float dpValue) { final float scale = DiscoverApplication.getDiscoverApplication().getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } /** * 根据手机的分辨率从 px(像素) 的单位 转成为 dp */ public static int px2dip(float pxValue) { final float scale = DiscoverApplication.getDiscoverApplication().getResources().getDisplayMetrics().density; return (int) (pxValue / scale + 0.5f); } /** * 获取actionBarSize 高度 */ public static int getActionBarSize() { TypedValue tv = new TypedValue(); if (DiscoverApplication.getDiscoverApplication().getApplicationContext().getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) { int actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, DiscoverApplication.getDiscoverApplication().getApplicationContext().getResources().getDisplayMetrics()); return actionBarHeight; } else { return 0; } } } ================================================ FILE: app/src/main/java/com/example/discover/utils/IntentManager.java ================================================ package com.example.discover.utils; import android.app.Activity; import android.app.ActivityOptions; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityOptionsCompat; import android.util.Pair; import android.view.View; import com.example.discover.AuthorHomeActivity; import com.example.discover.R; import com.example.discover.ResultActivity; import com.example.discover.VideoDetailActivity; import com.example.discover.ViewBigImageActivity; import com.example.discover.app.Constant; import com.example.discover.bean.DetailBean.ItemList; import com.example.discover.bean.LitePalBean.LikeVideo; import java.util.ArrayList; import java.util.List; /** * Created by monkeyWiiu on 2018/1/30. */ public class IntentManager { public static void toVideoDetailActivity(Activity context, ItemList item, View view) { Intent intent = new Intent(context, VideoDetailActivity.class); intent.putExtra("item", item); /*ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation( context, Pair.create(view, context.getString(R.string.transition_shot)), Pair.create(view, context.getString(R.string.transition_shot_background)) );*/ ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation( context, android.support.v4.util.Pair.create(view, context.getString(R.string.transition_shot)), android.support.v4.util.Pair.create(view, context.getString(R.string.transition_shot_background)) ); ActivityCompat.startActivity(context, intent, optionsCompat.toBundle()); //context.startActivity(intent); } public static void toAuthorHomeActivity(Context context,ItemList list) { int color = 0; if (list.getData().getItemList().size() > 0) { color = (Integer) Constant.LabelMap.get(list.getData().getItemList().get(0).getData().getCategory()); } Intent intent = new Intent(context, AuthorHomeActivity.class); intent.putExtra("AuthorId", list.getData().getHeader().getId()); intent.putExtra("AuthorName", list.getData().getHeader().getTitle()); intent.putExtra("AuthorIcon", list.getData().getHeader().getIcon()); intent.putExtra("AuthorDesc", list.getData().getHeader().getDescription()); intent.putExtra("Color", color); try { intent.putExtra("AuthorBack", list.getData().getItemList().get(0).getData().getTags().get(0).getHeaderImage()); } catch (Exception e) { e.printStackTrace(); } context.startActivity(intent); } public static void fromDetailtoAuthor(Context context, ItemList list) { int color = 0; color = (int) Constant.LabelMap.get(list.getData().getCategory()); Intent intent = new Intent(context, AuthorHomeActivity.class); intent.putExtra("AuthorId", list.getData().getAuthor().getId()); intent.putExtra("AuthorName", list.getData().getAuthor().getName()); intent.putExtra("AuthorIcon", list.getData().getAuthor().getIcon()); intent.putExtra("AuthorDesc", list.getData().getAuthor().getDescription()); intent.putExtra("Color", color); try { intent.putExtra("AuthorBack", list.getData().getTags().get(0).getHeaderImage()); } catch (Exception e) { e.printStackTrace(); } context.startActivity(intent); } public static void fromPersonalToAuthor(Context context, LikeVideo likeVideo) { Intent intent = new Intent(context, AuthorHomeActivity.class); intent.putExtra("AuthorId", likeVideo.getAuthorId()); intent.putExtra("AuthorName", likeVideo.getAuthorName()); intent.putExtra("AuthorIcon", likeVideo.getAuthorIcon()); intent.putExtra("AuthorDesc", likeVideo.getAuthorDesc()); intent.putExtra("Color", likeVideo.getLabelColor()); intent.putExtra("AuthorBack", likeVideo.getImageUrl()); context.startActivity(intent); } public static void toBigImageActivity(Activity context, View view, int position, ArrayList imgList) { Bundle bundle = new Bundle(); bundle.putInt("selet", 2);// 2,大图显示当前页数,1,头像,不显示页数 bundle.putInt("code", position);//第几张 bundle.putStringArrayList("imageuri", imgList); ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation( context, android.support.v4.util.Pair.create(view, context.getString(R.string.transition_shot)), android.support.v4.util.Pair.create(view, context.getString(R.string.transition_shot_background)) ); Intent intent = new Intent(context, ViewBigImageActivity.class); intent.putExtras(bundle); ActivityCompat.startActivity(context, intent, options.toBundle()); } } ================================================ FILE: app/src/main/java/com/example/discover/utils/LitePalUtil.java ================================================ package com.example.discover.utils; import com.example.discover.bean.DetailBean.Data; import com.example.discover.bean.LitePalBean.Follow; import com.example.discover.bean.LitePalBean.LabelType; import com.example.discover.bean.LitePalBean.LikeVideo; import com.example.discover.view.CustomView.LabelView; import org.litepal.crud.DataSupport; import java.util.ArrayList; import java.util.List; /** * Created by monkeyWiiu on 2018/1/13. */ public class LitePalUtil { public static List getSelectLabel() { List list = DataSupport.findAll(LabelType.class); List labelList = new ArrayList(); for (LabelType labelType : list) { labelList.add(labelType.getType()); } return labelList; } public static void addVideoToFavor(int id, String title, String desc, String playUrl, String imageUrl, String authorName, int authorId, String authorIcon, String authorDesc, int labelColor, String labelText, int size) { LikeVideo likeVideo = new LikeVideo(); likeVideo.setId(1); likeVideo.setVideoId(id); likeVideo.setTitle(title); likeVideo.setDescription(desc); likeVideo.setPlayUrl(playUrl); likeVideo.setImageUrl(imageUrl); likeVideo.setAuthorName(authorName); likeVideo.setAuthorId(authorId); likeVideo.setAuthorIcon(authorIcon); likeVideo.setAuthorDesc(authorDesc); likeVideo.setLabelColor(labelColor); likeVideo.setLabelText(labelText); likeVideo.setSize(size); likeVideo.save(); } public static void deleteVideoFromFavor(int videoId) { DataSupport.deleteAll(LikeVideo.class, "videoId = ?", String.valueOf(videoId)); } public static void addToFollow(int authorId, String authorName, String desc, String iconUrl, int backgroundColor,String backgroundImage) { Follow follow = new Follow(); follow.setAuthorId(authorId); follow.setAuthorName(authorName); follow.setAuthorDesc(desc); follow.setIconUrl(iconUrl); follow.setBackgroundColor(backgroundColor); follow.setBackgroundImage(backgroundImage); follow.save(); } public static void deleteFromFollow(int authorId) { DataSupport.deleteAll(Follow.class, "authorId = ?", String.valueOf(authorId)); } } ================================================ FILE: app/src/main/java/com/example/discover/utils/ShareUtil.java ================================================ package com.example.discover.utils; import android.content.Context; import android.content.Intent; import com.example.discover.R; /** * Created by monkeyWiiu on 2017/12/29. */ public class ShareUtil { public static void share(Context context, String shareText) { Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_TEXT, shareText); context.startActivity(Intent.createChooser(intent, context.getString(R.string.action_share))); } } ================================================ FILE: app/src/main/java/com/example/discover/utils/TimeUtils.java ================================================ package com.example.discover.utils; public class TimeUtils { private static final String ZERO = "0"; private static final String COLON_SYMBOL = ":"; private TimeUtils() {} public static int millsToSec(int mills) { return mills / 1000; } public static String secToTime(int time) { String timeStr; int hour = time / 3600; int minute = time / 60 % 60; int second = time % 60; if (hour == 0) { timeStr = unitFormat(minute) + COLON_SYMBOL + unitFormat(second); } else { timeStr = unitFormat(hour) + COLON_SYMBOL + unitFormat(minute) + COLON_SYMBOL + unitFormat(second); } return timeStr; } private static String unitFormat(int i) { String retStr; if (i >= 0 && i < 10) { retStr = ZERO + Integer.toString(i); } else { retStr = String.valueOf(i); } return retStr; } } ================================================ FILE: app/src/main/java/com/example/discover/view/CustomView/CategoryPopupWindow.java ================================================ package com.example.discover.view.CustomView; import android.content.Context; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.PopupWindow; import com.example.discover.R; import com.example.discover.adapter.LabelChooseAdapter; import com.example.discover.app.Constant; /** * Created by monkeyWiiu on 2018/1/13. */ public class CategoryPopupWindow extends PopupWindow { private PopItemClickListener mListener; public interface PopItemClickListener { void ItemClick(String labelType); } public void setPopItemClickListener(PopItemClickListener listener) { this.mListener = listener; } public CategoryPopupWindow(Context context) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View contentView = inflater.inflate(R.layout.category_popup_window, null); // 设置SelectPicPopupWindow的View this.setContentView(contentView); // 设置SelectPicPopupWindow弹出窗体的宽 //this.setWidth(DensityUtil.dip2px(300)); this.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT); // 设置SelectPicPopupWindow弹出窗体的高 this.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); // 设置SelectPicPopupWindow弹出窗体可点击 this.setFocusable(true); this.setOutsideTouchable(true); /*if (Build.VERSION.SDK_INT > 20) { this.setElevation(10f); }*/ //刷新状态 this.update(); // 实例化一个ColorDrawable颜色为半透明 //ColorDrawable dw = new ColorDrawable(); // 点back键和其他地方使其消失,设置了这个才能触发OnDismisslistener ,设置其他控件变化等操作 //this.setBackgroundDrawable(dw); // 设置SelectPicPopupWindow弹出窗体动画效果 this.setAnimationStyle(R.style.AnimationFadeLT); initRecycler(contentView, context); } /** * 显示popupWindow * * @param parent */ public void showPopupWindow(View parent) { if (!this.isShowing()) { // 以下拉方式显示popupwindow this.showAsDropDown(parent, parent.getLayoutParams().width / 2, 48); } else { this.dismiss(); } } public void initRecycler(View view, Context context) { RecyclerView rvLabel = view.findViewById(R.id.rv_label_choose); LabelChooseAdapter adapter;adapter = new LabelChooseAdapter(Constant.videoTypeList, Constant.LabelMap, context); adapter.setItemClickListener(new LabelChooseAdapter.ItemClickListener() { @Override public void itemClick(String labelType) { mListener.ItemClick(labelType); } }); GridLayoutManager layoutManager = new GridLayoutManager(context, 3, GridLayoutManager.VERTICAL, false); rvLabel.setLayoutManager(layoutManager); rvLabel.setAdapter(adapter); } } ================================================ FILE: app/src/main/java/com/example/discover/view/CustomView/CircleImageView.java ================================================ package com.example.discover.view.CustomView; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Matrix; import android.graphics.Outline; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.support.annotation.ColorInt; import android.support.annotation.ColorRes; import android.support.annotation.DrawableRes; import android.support.annotation.RequiresApi; import android.util.AttributeSet; import android.view.View; import android.view.ViewOutlineProvider; import android.widget.ImageView; import com.example.discover.R; /** * Created by monkeyWiiu on 2018/1/9. */ public class CircleImageView extends android.support.v7.widget.AppCompatImageView { private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP; private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888; private static final int COLORDRAWABLE_DIMENSION = 2; private static final int DEFAULT_BORDER_WIDTH = 0; private static final int DEFAULT_BORDER_COLOR = Color.BLACK; private static final int DEFAULT_CIRCLE_BACKGROUND_COLOR = Color.TRANSPARENT; private static final boolean DEFAULT_BORDER_OVERLAY = false; private final RectF mDrawableRect = new RectF(); private final RectF mBorderRect = new RectF(); private final Matrix mShaderMatrix = new Matrix(); private final Paint mBitmapPaint = new Paint(); private final Paint mBorderPaint = new Paint(); private final Paint mCircleBackgroundPaint = new Paint(); private int mBorderColor = DEFAULT_BORDER_COLOR; private int mBorderWidth = DEFAULT_BORDER_WIDTH; private int mCircleBackgroundColor = DEFAULT_CIRCLE_BACKGROUND_COLOR; private Bitmap mBitmap; private BitmapShader mBitmapShader; private int mBitmapWidth; private int mBitmapHeight; private float mDrawableRadius; private float mBorderRadius; private ColorFilter mColorFilter; private boolean mReady; private boolean mSetupPending; private boolean mBorderOverlay; private boolean mDisableCircularTransformation; public CircleImageView(Context context) { super(context); init(); } public CircleImageView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CircleImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0); mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_civ_border_width, DEFAULT_BORDER_WIDTH); mBorderColor = a.getColor(R.styleable.CircleImageView_civ_border_color, DEFAULT_BORDER_COLOR); mBorderOverlay = a.getBoolean(R.styleable.CircleImageView_civ_border_overlay, DEFAULT_BORDER_OVERLAY); // Look for deprecated civ_fill_color if civ_circle_background_color is not set if (a.hasValue(R.styleable.CircleImageView_civ_circle_background_color)) { mCircleBackgroundColor = a.getColor(R.styleable.CircleImageView_civ_circle_background_color, DEFAULT_CIRCLE_BACKGROUND_COLOR); } else if (a.hasValue(R.styleable.CircleImageView_civ_fill_color)) { mCircleBackgroundColor = a.getColor(R.styleable.CircleImageView_civ_fill_color, DEFAULT_CIRCLE_BACKGROUND_COLOR); } a.recycle(); init(); } private void init() { super.setScaleType(SCALE_TYPE); mReady = true; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { setOutlineProvider(new OutlineProvider()); } if (mSetupPending) { setup(); mSetupPending = false; } } @Override public ScaleType getScaleType() { return SCALE_TYPE; } @Override public void setScaleType(ScaleType scaleType) { if (scaleType != SCALE_TYPE) { throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType)); } } @Override public void setAdjustViewBounds(boolean adjustViewBounds) { if (adjustViewBounds) { throw new IllegalArgumentException("adjustViewBounds not supported."); } } @Override protected void onDraw(Canvas canvas) { if (mDisableCircularTransformation) { super.onDraw(canvas); return; } if (mBitmap == null) { return; } if (mCircleBackgroundColor != Color.TRANSPARENT) { canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mCircleBackgroundPaint); } canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mBitmapPaint); if (mBorderWidth > 0) { canvas.drawCircle(mBorderRect.centerX(), mBorderRect.centerY(), mBorderRadius, mBorderPaint); } } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); setup(); } @Override public void setPadding(int left, int top, int right, int bottom) { super.setPadding(left, top, right, bottom); setup(); } @Override public void setPaddingRelative(int start, int top, int end, int bottom) { super.setPaddingRelative(start, top, end, bottom); setup(); } public int getBorderColor() { return mBorderColor; } public void setBorderColor(@ColorInt int borderColor) { if (borderColor == mBorderColor) { return; } mBorderColor = borderColor; mBorderPaint.setColor(mBorderColor); invalidate(); } /** * @deprecated Use {@link #setBorderColor(int)} instead */ @Deprecated public void setBorderColorResource(@ColorRes int borderColorRes) { setBorderColor(getContext().getResources().getColor(borderColorRes)); } public int getCircleBackgroundColor() { return mCircleBackgroundColor; } public void setCircleBackgroundColor(@ColorInt int circleBackgroundColor) { if (circleBackgroundColor == mCircleBackgroundColor) { return; } mCircleBackgroundColor = circleBackgroundColor; mCircleBackgroundPaint.setColor(circleBackgroundColor); invalidate(); } public void setCircleBackgroundColorResource(@ColorRes int circleBackgroundRes) { setCircleBackgroundColor(getContext().getResources().getColor(circleBackgroundRes)); } /** * Return the color drawn behind the circle-shaped drawable. * * @return The color drawn behind the drawable * * @deprecated Use {@link #getCircleBackgroundColor()} instead. */ @Deprecated public int getFillColor() { return getCircleBackgroundColor(); } /** * Set a color to be drawn behind the circle-shaped drawable. Note that * this has no effect if the drawable is opaque or no drawable is set. * * @param fillColor The color to be drawn behind the drawable * * @deprecated Use {@link #setCircleBackgroundColor(int)} instead. */ @Deprecated public void setFillColor(@ColorInt int fillColor) { setCircleBackgroundColor(fillColor); } /** * Set a color to be drawn behind the circle-shaped drawable. Note that * this has no effect if the drawable is opaque or no drawable is set. * * @param fillColorRes The color resource to be resolved to a color and * drawn behind the drawable * * @deprecated Use {@link #setCircleBackgroundColorResource(int)} instead. */ @Deprecated public void setFillColorResource(@ColorRes int fillColorRes) { setCircleBackgroundColorResource(fillColorRes); } public int getBorderWidth() { return mBorderWidth; } public void setBorderWidth(int borderWidth) { if (borderWidth == mBorderWidth) { return; } mBorderWidth = borderWidth; setup(); } public boolean isBorderOverlay() { return mBorderOverlay; } public void setBorderOverlay(boolean borderOverlay) { if (borderOverlay == mBorderOverlay) { return; } mBorderOverlay = borderOverlay; setup(); } public boolean isDisableCircularTransformation() { return mDisableCircularTransformation; } public void setDisableCircularTransformation(boolean disableCircularTransformation) { if (mDisableCircularTransformation == disableCircularTransformation) { return; } mDisableCircularTransformation = disableCircularTransformation; initializeBitmap(); } @Override public void setImageBitmap(Bitmap bm) { super.setImageBitmap(bm); initializeBitmap(); } @Override public void setImageDrawable(Drawable drawable) { super.setImageDrawable(drawable); initializeBitmap(); } @Override public void setImageResource(@DrawableRes int resId) { super.setImageResource(resId); initializeBitmap(); } @Override public void setImageURI(Uri uri) { super.setImageURI(uri); initializeBitmap(); } @Override public void setColorFilter(ColorFilter cf) { if (cf == mColorFilter) { return; } mColorFilter = cf; applyColorFilter(); invalidate(); } @Override public ColorFilter getColorFilter() { return mColorFilter; } private void applyColorFilter() { if (mBitmapPaint != null) { mBitmapPaint.setColorFilter(mColorFilter); } } private Bitmap getBitmapFromDrawable(Drawable drawable) { if (drawable == null) { return null; } if (drawable instanceof BitmapDrawable) { return ((BitmapDrawable) drawable).getBitmap(); } try { Bitmap bitmap; if (drawable instanceof ColorDrawable) { bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG); } else { bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG); } Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); drawable.draw(canvas); return bitmap; } catch (Exception e) { e.printStackTrace(); return null; } } private void initializeBitmap() { if (mDisableCircularTransformation) { mBitmap = null; } else { mBitmap = getBitmapFromDrawable(getDrawable()); } setup(); } private void setup() { if (!mReady) { mSetupPending = true; return; } if (getWidth() == 0 && getHeight() == 0) { return; } if (mBitmap == null) { invalidate(); return; } mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); mBitmapPaint.setAntiAlias(true); mBitmapPaint.setShader(mBitmapShader); mBorderPaint.setStyle(Paint.Style.STROKE); mBorderPaint.setAntiAlias(true); mBorderPaint.setColor(mBorderColor); mBorderPaint.setStrokeWidth(mBorderWidth); mCircleBackgroundPaint.setStyle(Paint.Style.FILL); mCircleBackgroundPaint.setAntiAlias(true); mCircleBackgroundPaint.setColor(mCircleBackgroundColor); mBitmapHeight = mBitmap.getHeight(); mBitmapWidth = mBitmap.getWidth(); mBorderRect.set(calculateBounds()); mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f); mDrawableRect.set(mBorderRect); if (!mBorderOverlay && mBorderWidth > 0) { mDrawableRect.inset(mBorderWidth - 1.0f, mBorderWidth - 1.0f); } mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f); applyColorFilter(); updateShaderMatrix(); invalidate(); } private RectF calculateBounds() { int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight(); int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom(); int sideLength = Math.min(availableWidth, availableHeight); float left = getPaddingLeft() + (availableWidth - sideLength) / 2f; float top = getPaddingTop() + (availableHeight - sideLength) / 2f; return new RectF(left, top, left + sideLength, top + sideLength); } private void updateShaderMatrix() { float scale; float dx = 0; float dy = 0; mShaderMatrix.set(null); if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) { scale = mDrawableRect.height() / (float) mBitmapHeight; dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f; } else { scale = mDrawableRect.width() / (float) mBitmapWidth; dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f; } mShaderMatrix.setScale(scale, scale); mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top); mBitmapShader.setLocalMatrix(mShaderMatrix); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private class OutlineProvider extends ViewOutlineProvider { @Override public void getOutline(View view, Outline outline) { Rect bounds = new Rect(); mBorderRect.roundOut(bounds); outline.setRoundRect(bounds, bounds.width() / 2.0f); } } } ================================================ FILE: app/src/main/java/com/example/discover/view/CustomView/DragFrameLayout.java ================================================ package com.example.discover.view.CustomView; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.support.v4.widget.ViewDragHelper; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; /** * Created by monkeyWiiu on 2018/2/3. */ public class DragFrameLayout extends FrameLayout { public static final String TAG = "DragFramlayout"; private ViewDragHelper mDragHelper; //#00000000 public int DEF_BG_COLOR = 0xff000000; /**拖动是否进行缩放变化*/ private boolean mDragScale=true; /** * 拖拽时是否进行缩放操作,默认TRUE * @param dragScale TRUE:是 FALSE:否 */ public void setDragScale(boolean dragScale) { mDragScale = dragScale; } public DragFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { if (getContext() instanceof Activity) { ((Activity) getContext()).getWindow().getDecorView().setBackgroundColor(DEF_BG_COLOR); } mDragHelper= ViewDragHelper.create(this,1.0f,new ViewDragHelper.Callback(){ @Override public boolean tryCaptureView(View child, int pointerId) { //允许子视图进行拖拽,这里默认都允许 return true; } /**是否允许所有方向拖拽*/ boolean needDrag; @Override public int clampViewPositionVertical(View child, int top, int dy) { if (needDrag) { return top; } if (top < 0) {//只允许向下拖拽 top = 0; } else if (top > 100) {//向下拖拽超过100px后,释放允许任何方向拖拽 needDrag = true; } return top; } @Override public int clampViewPositionHorizontal(View child, int left, int dx) { return needDrag ? left : 0; } /** * * @param changedView 被拖动的View * @param left 水平拖动距离 * @param top 垂直拖动距离 * @param dx 每次拖拽产生的水平距离x2-x1 * @param dy 每次拖拽产生的垂直距离y2-y1 */ @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { super.onViewPositionChanged(changedView, left, top, dx, dy); float present = 1 - (top * 1.0f) / (getHeight()); if (getContext() instanceof Activity) { int alpah = Math.min((int) (255 * present), 255); ((Activity) getContext()).getWindow().getDecorView().setBackgroundColor(Color.argb(alpah, 0, 0, 0)); } float maxScale = Math.min(present, 1.0f);//Max,1.0f float minScale = Math.max(0.5f, maxScale);//Min,5.0f; changedView.setScaleX(minScale); changedView.setScaleY(minScale); } boolean mNeedRelease; @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); if (mNeedRelease) { if (getContext() instanceof Activity) { ((Activity) getContext()).onBackPressed(); } } else { needDrag = false; //让视图归位 mDragHelper.settleCapturedViewAt(finalLeft, finalTop); releasedChild.setScaleX(1.0f); releasedChild.setScaleY(1.0f); invalidate(); } } }); mDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() { @Override public boolean tryCaptureView(View child, int pointerId) { return true; } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); if (mNeedRelease) { if (getContext() instanceof Activity) { ((Activity) getContext()).onBackPressed(); } } else { needDrag = false; //让视图归位, mDragHelper.settleCapturedViewAt(finalLeft, finalTop); if(mDragScale){ releasedChild.setScaleX(1.0f); releasedChild.setScaleY(1.0f); } invalidate(); } } boolean mNeedRelease; @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { super.onViewPositionChanged(changedView, left, top, dx, dy); mNeedRelease = top > getHeight() * 0.25;//Release //ChangeBg float present = 1 - (top * 1.0f) / (getHeight()); if (getContext() instanceof Activity) { int alpah = Math.min((int) (255 * present), 255); ((Activity) getContext()).getWindow().getDecorView().setBackgroundColor(Color.argb(alpah, 0, 0, 0)); } //ChangeScale if(mDragScale){ float maxScale = Math.min(present, 1.0f);//Max,1.0f float minScale = Math.max(0.5f, maxScale);//Min,5.0f; // if(present>1.0f){ // present=1.0f; // }else if(present<0.5f){ // present=0.5f; // } changedView.setScaleX(minScale); changedView.setScaleY(minScale); } Log.i(TAG, "Top=" + top + "Release=" + getHeight() * 0.25 + "Present=" + present); } boolean needDrag; @Override public int clampViewPositionVertical(View child, int top, int dy) { if (needDrag) { return top; } if (top < 0) { top = 0; } else if (top > 100) {//释放允许任何方向拖拽 needDrag = true; } return top; } @Override public int clampViewPositionHorizontal(View child, int left, int dx) { return needDrag ? left : 0; } @Override public int getViewVerticalDragRange(View child) { return getHeight() / 2; } }); } int finalLeft; int finalTop; @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); finalLeft = getChildAt(0).getLeft(); finalTop = getChildAt(0).getTop(); } @Override public void computeScroll() { if (mDragHelper.continueSettling(true)) { invalidate(); } } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return mDragHelper.shouldInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { mDragHelper.processTouchEvent(event); return true; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); } } ================================================ FILE: app/src/main/java/com/example/discover/view/CustomView/FollowPopupWindow.java ================================================ package com.example.discover.view.CustomView; import android.content.Context; import android.support.v7.widget.CardView; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.PopupWindow; import android.widget.Toast; import com.example.discover.R; import com.example.discover.adapter.LabelChooseAdapter; import com.example.discover.app.Constant; /** * Created by monkeyWiiu on 2018/1/26. */ public class FollowPopupWindow extends PopupWindow { private PopItemClickListener mListener; public interface PopItemClickListener { void ItemClick(); } public void setPopItemClickListener(PopItemClickListener listener) { this.mListener = listener; } public FollowPopupWindow(Context context) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View contentView = inflater.inflate(R.layout.follow_popup, null); // 设置SelectPicPopupWindow的View this.setContentView(contentView); // 设置SelectPicPopupWindow弹出窗体的宽 this.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT); // 设置SelectPicPopupWindow弹出窗体的高 this.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); // 设置SelectPicPopupWindow弹出窗体可点击 this.setFocusable(true); this.setOutsideTouchable(true); //刷新状态 this.update(); // 设置SelectPicPopupWindow弹出窗体动画效果 this.setAnimationStyle(R.style.AnimationFadeRT); CardView cardView = this.getContentView().findViewById(R.id.cv); cardView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mListener.ItemClick(); hide(); } }); } /** * 显示popupWindow * * @param parent */ public void showPopupWindow(View parent) { if (!this.isShowing()) { // 以下拉方式显示popupwindow this.showAsDropDown(parent, parent.getLayoutParams().width / 2, 0); } else { this.dismiss(); } } public void hide() { this.dismiss(); } } ================================================ FILE: app/src/main/java/com/example/discover/view/CustomView/HackyViewPager.java ================================================ package com.example.discover.view.CustomView; import android.content.Context; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.view.MotionEvent; /** * Hacky fix for Issue #4 and * http://code.google.com/p/android/issues/detail?id=18990 *

* ScaleGestureDetector seems to mess up the touch events, which means that * ViewGroups which make use of onInterceptTouchEvent throw a lot of * IllegalArgumentException: pointerIndex out of range. *

* There's not much I can do in my code for now, but we can mask the result by * just catching the problem and ignoring it. * * @author Chris Banes */ public class HackyViewPager extends ViewPager { public HackyViewPager(Context context) { super(context); } public HackyViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { try { return super.onInterceptTouchEvent(ev); } catch (IllegalArgumentException e) { return false; } } } ================================================ FILE: app/src/main/java/com/example/discover/view/CustomView/LabelView.java ================================================ package com.example.discover.view.CustomView; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; import android.view.View; import android.widget.Button; import com.example.discover.R; import com.example.discover.utils.DebugUtil; import com.example.discover.utils.DensityUtil; /** * Created by monkeyWiiu on 2017/12/28. */ public class LabelView extends View { /** * 文本 */ private String mLabelText; /** * 文本的颜色 */ private int mLabelTextColor; /** * 文本的大小 */ private int mLabelTextSize; /** * 背景颜色 */ private int mBackground; /** * 绘制时控制文本绘制的范围 */ private Rect mBound; private Paint mPaint; private RectF mRectF; public LabelView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public LabelView(Context context) { this(context, null); } /** * 获得我自定义的样式属性 * * @param context * @param attrs * @param defStyle */ public LabelView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); //默认为黑,否则不设置颜色就为透明不可见 mLabelTextColor = Color.BLACK; mBackground = Color.WHITE; /** * 获得我们所定义的自定义样式属性 */ TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.LabelView, defStyle, 0); int n = a.getIndexCount(); for (int i = 0; i < n; i++) { int attr = a.getIndex(i); switch (attr) { case R.styleable.LabelView_labelText: mLabelText = a.getString(attr); break; case R.styleable.LabelView_labelTextColor: mLabelTextColor = a.getColor(attr, Color.BLACK); break; case R.styleable.LabelView_labelTextSize: //默认设置为16sp, TypeValue也可以把sp转化为px mLabelTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); break; case R.styleable.LabelView_labelBackground: mBackground = a.getColor(attr, Color.YELLOW); break; } } a.recycle(); /** * 获得绘制文本的宽和高 */ mPaint = new Paint(); mPaint.setTextSize(mLabelTextSize); // mPaint.setColor(mTitleTextColor); mBound = new Rect(); //防止mLabelText空 if (mLabelText == null) { mLabelText = ""; } mPaint.getTextBounds(mLabelText, 0, mLabelText.length(), mBound); mRectF = new RectF(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int width; int height; if (widthMode == MeasureSpec.EXACTLY) { width = widthSize; DebugUtil.debug("tesfsdf", width + ""); } else { //动态设置时不起作用 mPaint.setTextSize(mLabelTextSize); mPaint.getTextBounds(mLabelText, 0, mLabelText.length(), mBound); float textWidth = mBound.width(); int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight()); width = desired; } if (heightMode == MeasureSpec.EXACTLY) { height = heightSize; } else { //动态设置时不起作用 mPaint.setTextSize(mLabelTextSize); mPaint.getTextBounds(mLabelText, 0, mLabelText.length(), mBound); float textHeight = mBound.height(); int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom()); height = desired; } setMeasuredDimension(width, height); } @Override protected void onDraw(Canvas canvas) { mPaint.getTextBounds(mLabelText, 0, mLabelText.length(), mBound); mPaint.setColor(mBackground); mPaint.setAntiAlias(true); canvas.drawRect(getMeasuredHeight() / 2, 0, getMeasuredWidth() - getMeasuredHeight() / 2, getMeasuredHeight(), mPaint); //左半圆 mRectF.left = 0; mRectF.top = 0; mRectF.right = getMeasuredHeight(); mRectF.bottom = getMeasuredHeight(); canvas.drawArc(mRectF, -90, -180, false, mPaint); //右半圆 mRectF.left = getMeasuredWidth() - getMeasuredHeight(); mRectF.top = 0; mRectF.right = getMeasuredWidth(); mRectF.bottom = getMeasuredHeight(); canvas.drawArc(mRectF, -90, 180, false, mPaint); mPaint.setColor(mLabelTextColor); canvas.drawText(mLabelText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint); } public void setText(String text) { mLabelText = text; } public void setBackground(int color) { mBackground = color; } } ================================================ FILE: app/src/main/java/com/example/discover/view/CustomView/ReplyPopupWindow.java ================================================ package com.example.discover.view.CustomView; import android.content.Context; import android.os.Handler; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.PopupWindow; import com.example.discover.R; import com.example.discover.adapter.PopReplyAdapter; import com.example.discover.adapter.ReplyAdapter; import com.example.discover.app.Constant; import com.example.discover.bean.DetailBean.ItemList; import com.example.discover.bean.DetailBean.Replies; import com.example.discover.bean.DetailBean.ReplyList; import com.example.discover.http.HttpClient; import com.example.discover.http.RequestListener; import com.example.discover.model.ReplyModel; import com.example.discover.utils.DebugUtil; import com.example.discover.utils.DensityUtil; import com.jakewharton.rxbinding2.view.RxView; import com.trello.rxlifecycle2.components.support.RxAppCompatActivity; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import io.reactivex.Flowable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.functions.Consumer; import io.reactivex.schedulers.Schedulers; /** * Created by monkeyWiiu on 2018/2/1. */ public class ReplyPopupWindow extends PopupWindow { private int id; private PopReplyAdapter replyAdapter; private LinearLayoutManager linearLayoutManager; private FrameLayout noComment; private FrameLayout avLoading; private FrameLayout reLoading; private RecyclerView replyRecyclerView; private List replyLists = new ArrayList<>(); private boolean firstRequest = true; private boolean loading = false; private int lastSequence; private Subscription mSubscription; public ReplyPopupWindow(Context context, int id) { this.id = id; //this.id = 25923; LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View contentView = inflater.inflate(R.layout.reply_popup_window, null); // 设置SelectPicPopupWindow的View this.setContentView(contentView); // 设置SelectPicPopupWindow弹出窗体的宽 //this.setWidth(DensityUtil.dip2px(300)); this.setWidth(ViewGroup.LayoutParams.MATCH_PARENT); // 设置SelectPicPopupWindow弹出窗体的高 this.setHeight(DensityUtil.dip2px((300))); // 设置SelectPicPopupWindow弹出窗体可点击 //this.setFocusable(true); this.setOutsideTouchable(true); /*if (Build.VERSION.SDK_INT > 20) { this.setElevation(10f); }*/ //刷新状态 this.update(); // 实例化一个ColorDrawable颜色为半透明 //ColorDrawable dw = new ColorDrawable(); // 点back键和其他地方使其消失,设置了这个才能触发OnDismisslistener ,设置其他控件变化等操作 //this.setBackgroundDrawable(dw); // 设置SelectPicPopupWindow弹出窗体动画效果 this.setAnimationStyle(R.style.AnimationFadeBT); noComment = contentView.findViewById(R.id.no_comment); avLoading = contentView.findViewById(R.id.loading); reLoading = contentView.findViewById(R.id.reloading); initRecyclerView(contentView, context); showReplies(); RxView.clicks(reLoading) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(new Consumer() { @Override public void accept(Object o) throws Exception { showReplies(); DebugUtil.debug("eeee", "eee"); } }); } /** * 显示popupWindow * * @param parent */ public void showPopupWindow(View parent) { if (!this.isShowing()) { // 以下拉方式显示popupwindow this.showAtLocation(parent, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0); } else { this.dismiss(); } } public void initRecyclerView(View view, Context context) { replyRecyclerView = view.findViewById(R.id.rv_reply); replyAdapter = new PopReplyAdapter(replyLists); linearLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL,false); replyRecyclerView.setLayoutManager(linearLayoutManager); replyRecyclerView.setAdapter(replyAdapter); //上拉加载 replyRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); int lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition(); int totalItemCount = linearLayoutManager.getItemCount(); if (lastVisibleItem == totalItemCount - 5 && !loading) { loading = true; new Handler().postDelayed(new Runnable() { @Override public void run() { showReplies(); } }, 1000); } } }); } public void showReplies() { Flowable repliesFlowable; if (firstRequest) { repliesFlowable = HttpClient.Builder.getEyeService().fetchReplies(id); }else { repliesFlowable = HttpClient.Builder.getEyeService().fetchReplies(id, lastSequence); } repliesFlowable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber() { @Override public void onSubscribe(Subscription s) { mSubscription = s; s.request(Long.MAX_VALUE); } @Override public void onNext(Replies replies) { avLoading.setVisibility(View.GONE); reLoading.setVisibility(View.GONE); DebugUtil.debug("eeee", "next"); if (replies.getReplyList().size() > 0) { replyLists.addAll(replies.getReplyList()); replyAdapter.notifyDataSetChanged(); lastSequence = replies.getReplyList().get(replies.getReplyList().size() - 1).getSequence(); firstRequest = false; loading =false; } else { noComment.setVisibility(View.VISIBLE); } } @Override public void onError(Throwable t) { DebugUtil.debug("eeee", "error"); avLoading.setVisibility(View.GONE); if (firstRequest) { reLoading.setVisibility(View.VISIBLE); } } @Override public void onComplete() { DebugUtil.debug("eeee", "ecccr"); mSubscription.cancel(); } }); } @Override public void dismiss() { //repliesFlowable.un mSubscription.cancel(); super.dismiss(); } } ================================================ FILE: app/src/main/java/com/example/discover/view/test.java ================================================ package com.example.discover.view; /** * Created by monkeyWiiu on 2017/12/28. */ public class test { } ================================================ FILE: app/src/main/res/anim/fade_in_bottom.xml ================================================ ================================================ FILE: app/src/main/res/anim/fade_in_lt.xml ================================================ ================================================ FILE: app/src/main/res/anim/fade_in_rt.xml ================================================ ================================================ FILE: app/src/main/res/anim/fade_out_lb.xml ================================================ ================================================ FILE: app/src/main/res/anim/fade_out_rb.xml ================================================ ================================================ FILE: app/src/main/res/anim/fade_out_top.xml ================================================ ================================================ FILE: app/src/main/res/drawable/bg_save_big_image.xml ================================================ ================================================ FILE: app/src/main/res/drawable/corner_view.xml ================================================ ================================================ FILE: app/src/main/res/drawable/ic_arrow_back_white_24px.xml ================================================ ================================================ FILE: app/src/main/res/drawable/ic_clear_black_24px.xml ================================================ ================================================ FILE: app/src/main/res/drawable/ic_heart_full_24dp_pink.xml ================================================ ================================================ FILE: app/src/main/res/drawable/ic_heart_hollow_24dp.xml ================================================ ================================================ FILE: app/src/main/res/drawable/item_figure.xml ================================================ ================================================ FILE: app/src/main/res/drawable/item_home.xml ================================================ ================================================ FILE: app/src/main/res/drawable/item_search.xml ================================================ ================================================ FILE: app/src/main/res/drawable/item_smile.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_author_home.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_main.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_result.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_search.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_test.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_video_detail.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_view_big_image.xml ================================================ ================================================ FILE: app/src/main/res/layout/author_card.xml ================================================ ================================================ FILE: app/src/main/res/layout/bottom_bar.xml ================================================ ================================================ FILE: app/src/main/res/layout/category_card.xml ================================================ ================================================ FILE: app/src/main/res/layout/category_popup_window.xml ================================================ ================================================ FILE: app/src/main/res/layout/follow_popup.xml ================================================ ================================================ FILE: app/src/main/res/layout/footer_item_video.xml ================================================ ================================================ FILE: app/src/main/res/layout/fragment_base.xml ================================================ ================================================ FILE: app/src/main/res/layout/fragment_discover.xml ================================================ ================================================ FILE: app/src/main/res/layout/fragment_follow.xml ================================================ ================================================ FILE: app/src/main/res/layout/fragment_personal.xml ================================================ ================================================ FILE: app/src/main/res/layout/fragment_personal_like.xml ================================================ ================================================ FILE: app/src/main/res/layout/fragment_search.xml ================================================ ================================================ FILE: app/src/main/res/layout/fragment_video.xml ================================================ ================================================ FILE: app/src/main/res/layout/fragment_welfare.xml ================================================ ================================================ FILE: app/src/main/res/layout/item_follow.xml ================================================ ================================================ FILE: app/src/main/res/layout/item_movie_detail_header.xml ================================================ ================================================ FILE: app/src/main/res/layout/item_reply.xml ================================================ ================================================ FILE: app/src/main/res/layout/item_welfare.xml ================================================ ================================================ FILE: app/src/main/res/layout/label_view.xml ================================================ ================================================ FILE: app/src/main/res/layout/like_video_card.xml ================================================ ================================================ FILE: app/src/main/res/layout/null_layout.xml ================================================ ================================================ FILE: app/src/main/res/layout/recommend_author.xml ================================================ ================================================ FILE: app/src/main/res/layout/recommend_category.xml ================================================ ================================================ FILE: app/src/main/res/layout/reply_popup_window.xml ================================================ ================================================ FILE: app/src/main/res/layout/search_tag.xml ================================================ ================================================ FILE: app/src/main/res/layout/select_label_view.xml ================================================ ================================================ FILE: app/src/main/res/layout/tag_header_new.xml ================================================ ================================================ FILE: app/src/main/res/layout/tag_header_reco.xml ================================================ ================================================ FILE: app/src/main/res/layout/test.xml ================================================ ================================================ FILE: app/src/main/res/layout/test_cardview.xml ================================================ ================================================ FILE: app/src/main/res/layout/video_card.xml ================================================ ================================================ FILE: app/src/main/res/layout/viewpager_very_image.xml ================================================ ================================================ FILE: app/src/main/res/values/attrs.xml ================================================ ================================================ FILE: app/src/main/res/values/colors.xml ================================================ #3F51B5 #303F9F #FF4081 #383737 #36465d #2f3e53 #ffffff #ffffff #FFD2CFCF #f2f2f2 #FFEEEEEE #86909E #c0c2c4 #000000 #2d2d30 #fff5f5f5 #a63939 #d47e38 #fac654 #bbcf1f #89f959 #5fe18f #62f5d5 #66bcd9 #6599e7 #295981 #5458cc #3a4afa #7e4cd4 #af2ec2 #ca73d4 #98cf78 #e64570 #e76fc7 #ffffff #1c574c #00d21c #eabf3b #e13f0e #1068ea #7f08e7 ================================================ FILE: app/src/main/res/values/dimens.xml ================================================ 20dp 70dp ================================================ FILE: app/src/main/res/values/strings.xml ================================================ Discover 分享给朋友 (来自Discover(开眼视频)) 搜索开眼视频 你关注的标签 推荐的视频作者 进入主页 暂无评论 backdrop transition_shot_background M12,21 L10.695,19.853406 C6.06,15.7771117 3,13.0871935 3,9.79564033 C3,7.10572207 5.1735,5 7.95,5 C9.516,5 11.019,5.70626703 12,6.81798365 C12.981,5.70626703 14.484,5 16.05,5 C18.8265,5 21,7.10572207 21,9.79564033 C21,13.0871935 17.94,15.7771117 13.305,19.853406 L12,21 L12,21 Z ================================================ FILE: app/src/main/res/values/styles.xml ================================================ ================================================ FILE: app/src/main/res/values-v21/dimens.xml ================================================ ================================================ FILE: app/src/main/res/values-v21/styles.xml ================================================ ================================================ FILE: app/src/test/java/com/example/discover/ExampleUnitTest.java ================================================ package com.example.discover; import org.junit.Test; import static org.junit.Assert.*; /** * Example local unit test, which will execute on the development machine (host). * * @see Testing documentation */ public class ExampleUnitTest { @Test public void addition_isCorrect() throws Exception { assertEquals(4, 2 + 2); } } ================================================ FILE: build.gradle ================================================ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { jcenter() google() } dependencies { classpath 'com.android.tools.build:gradle:3.0.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { jcenter() google() maven { url "https://jitpack.io" } } } task clean(type: Delete) { delete rootProject.buildDir } ================================================ FILE: gradle/wrapper/gradle-wrapper.properties ================================================ #Mon Dec 18 15:30:27 CST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip ================================================ FILE: gradle.properties ================================================ # Project-wide Gradle settings. # IDE (e.g. Android Studio) users: # Gradle settings configured through the IDE *will override* # any settings specified in this file. # For more details on how to configure your build environment visit # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. org.gradle.jvmargs=-Xmx1536m # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true ================================================ FILE: gradlew ================================================ #!/usr/bin/env bash ############################################################################## ## ## Gradle start up script for UN*X ## ############################################################################## # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS="" APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" warn ( ) { echo "$*" } die ( ) { echo echo "$*" echo exit 1 } # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false case "`uname`" in CYGWIN* ) cygwin=true ;; Darwin* ) darwin=true ;; MINGW* ) msys=true ;; esac # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" # Need this for relative symlinks. while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`"/$link" fi done SAVED="`pwd`" cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" cd "$SAVED" >/dev/null CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD="$MAX_FD_LIMIT" fi ulimit -n $MAX_FD if [ $? -ne 0 ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin, switch paths to Windows format before running java if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` SEP="" for dir in $ROOTDIRSRAW ; do ROOTDIRS="$ROOTDIRS$SEP$dir" SEP="|" done OURCYGPATTERN="(^($ROOTDIRS))" # Add a user-defined pattern to the cygpath arguments if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" fi # Now convert the arguments - kludge to limit ourselves to /bin/sh i=0 for arg in "$@" ; do CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` else eval `echo args$i`="\"$arg\"" fi i=$((i+1)) done case $i in (0) set -- ;; (1) set -- "$args0" ;; (2) set -- "$args0" "$args1" ;; (3) set -- "$args0" "$args1" "$args2" ;; (4) set -- "$args0" "$args1" "$args2" "$args3" ;; (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules function splitJvmOpts() { JVM_OPTS=("$@") } eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" ================================================ FILE: gradlew.bat ================================================ @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS= set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :init @rem Get command-line arguments, handling Windowz variants if not "%OS%" == "Windows_NT" goto win9xME_args if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. set CMD_LINE_ARGS= set _SKIP=2 :win9xME_args_slurp if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* goto execute :4NT_args @rem Get arguments from the 4NT Shell from JP Software set CMD_LINE_ARGS=%$ :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: librarys/http/.gitignore ================================================ /build ================================================ FILE: librarys/http/build.gradle ================================================ apply plugin: 'com.android.library' android { compileSdkVersion 24 buildToolsVersion '26.0.2' defaultConfig { minSdkVersion 15 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:26.+' compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:converter-gson:2.3.0' compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0' //compile 'io.reactivex:rxandroid:1.2.1' //compile 'io.reactivex:rxjava:1.2.1' compile 'io.reactivex.rxjava2:rxandroid:2.0.1' compile 'io.reactivex.rxjava2:rxjava:2.0.7' compile 'com.squareup.okhttp3:logging-interceptor:3.4.1' testCompile 'junit:junit:4.12' } ================================================ FILE: librarys/http/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in G:\Android\sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: librarys/http/src/androidTest/java/com/example/http/ExampleInstrumentedTest.java ================================================ package com.example.http; import android.content.Context; import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.*; /** * Instrumentation test, which will execute on an Android device. * * @see Testing documentation */ @RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest { @Test public void useAppContext() throws Exception { // Context of the app under test. Context appContext = InstrumentationRegistry.getTargetContext(); assertEquals("com.example.http.test", appContext.getPackageName()); } } ================================================ FILE: librarys/http/src/main/AndroidManifest.xml ================================================ ================================================ FILE: librarys/http/src/main/java/com/example/http/HttpUtils.java ================================================ package com.example.http; import android.content.Context; import java.security.SecureRandom; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.concurrent.TimeUnit; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import okhttp3.OkHttpClient; import okhttp3.logging.HttpLoggingInterceptor; import retrofit2.Retrofit; import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; import retrofit2.converter.gson.GsonConverterFactory; /** * Created by Administrator on 2017/12/9 0009. */ public class HttpUtils { private static HttpUtils instance ; private boolean debug; private Context context; private Object eyeHttp; private Object gankHttp; //天眼API private String EYE_API = "http://baobab.kaiyanapp.com/api/"; //干货API private final static String API_GANKIO = "https://gank.io/api/"; public static HttpUtils getInstance() { if (instance == null) { synchronized (HttpUtils.class) { if (instance == null) { return new HttpUtils(); } } } return instance; } public T getEyeServer(Class a) { if (eyeHttp == null) { synchronized (HttpUtils.class) { if (eyeHttp == null) { return getBuilder(EYE_API).build().create(a); } } } return (T) eyeHttp; } public T getGankServer(Class a) { if (gankHttp == null) { synchronized (HttpUtils.class) { if (gankHttp == null) { return getBuilder(API_GANKIO).build().create(a); } } } return (T) gankHttp; } public void init(Context context, boolean debug) { this.debug = debug; this.context = context; } public Retrofit.Builder getBuilder(String url) { Retrofit.Builder builder = new Retrofit.Builder() .baseUrl(url) .client(getClient()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create()); return builder; } public OkHttpClient getClient() { OkHttpClient client = new OkHttpClient(); client = getUnsafeOkHttpClient(); return client; } /** * https请求由于证书验证问题,直接请求一般都会失败. * 一般是做证书验证处理或者忽略证书验证 * 这里采用后者 */ public OkHttpClient getUnsafeOkHttpClient() { try { final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[]{}; } }}; // Install the all-trusting trust manager SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustAllCerts, new SecureRandom()); // Create an ssl socket factory with our all-trusting manager SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); OkHttpClient.Builder okBuilder = new OkHttpClient.Builder(); okBuilder.readTimeout(20, TimeUnit.SECONDS); okBuilder.connectTimeout(10, TimeUnit.SECONDS); okBuilder.writeTimeout(20, TimeUnit.SECONDS); okBuilder.addInterceptor(getInterceptor()); okBuilder.sslSocketFactory(sslSocketFactory); okBuilder.hostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } }); return okBuilder.build(); } catch (Exception e) { throw new RuntimeException(e); } } private HttpLoggingInterceptor getInterceptor() { HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); /*if (debug) { interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); // 测试 } else { interceptor.setLevel(HttpLoggingInterceptor.Level.NONE); // 打包 }*/ interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); return interceptor; } } ================================================ FILE: librarys/http/src/main/res/values/strings.xml ================================================ http ================================================ FILE: librarys/http/src/test/java/com/example/http/ExampleUnitTest.java ================================================ package com.example.http; import org.junit.Test; import static org.junit.Assert.*; /** * Example local unit test, which will execute on the development machine (host). * * @see Testing documentation */ public class ExampleUnitTest { @Test public void addition_isCorrect() throws Exception { assertEquals(4, 2 + 2); } } ================================================ FILE: librarys/jiaozivideoplayer/.idea/compiler.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/.idea/copyright/profiles_settings.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/.idea/gradle.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/.idea/misc.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/.idea/modules.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/.idea/runConfigurations.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/.idea/workspace.xml ================================================ 1512987845548 ================================================ FILE: librarys/jiaozivideoplayer/build.gradle ================================================ apply plugin: 'com.android.library' android { compileSdkVersion 26 buildToolsVersion '26.0.2' defaultConfig { minSdkVersion 16 targetSdkVersion 26 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } lintOptions { abortOnError false } } dependencies { testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:26.+' } ================================================ FILE: librarys/jiaozivideoplayer/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /Users/Nathen/WorkEnv/android-sdk-macosx/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: librarys/jiaozivideoplayer/src/androidTest/java/cn/jzvd/ApplicationTest.java ================================================ package cn.jzvd; import android.app.Application; import android.test.ApplicationTestCase; /** * Testing Fundamentals */ public class ApplicationTest extends ApplicationTestCase { public ApplicationTest() { super(Application.class); } } ================================================ FILE: librarys/jiaozivideoplayer/src/main/AndroidManifest.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/java/cn/jzvd/JZMediaInterface.java ================================================ package cn.jzvd; import android.view.Surface; /** * Created by Nathen on 2017/11/7. * 自定义播放器 */ public abstract class JZMediaInterface { public Object currentDataSource;//正在播放的当前url或uri /** * 第一个是url的map * 第二个是loop * 第三个是header * 第四个是context */ public Object[] dataSourceObjects;//包含了地址的map(多分辨率用),context,loop,header等 public abstract void start(); public abstract void prepare(); public abstract void pause(); public abstract boolean isPlaying(); public abstract void seekTo(long time); public abstract void release(); public abstract long getCurrentPosition(); public abstract long getDuration(); public abstract void setSurface(Surface surface); } ================================================ FILE: librarys/jiaozivideoplayer/src/main/java/cn/jzvd/JZMediaManager.java ================================================ package cn.jzvd; import android.graphics.SurfaceTexture; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.util.Log; import android.view.Surface; import android.view.TextureView; /** * 这个类用来和jzvd互相调用,当jzvd需要调用Media的时候调用这个类,当MediaPlayer有回调的时候,通过这个类回调JZVD * Created by Nathen on 2017/11/18. */ public class JZMediaManager implements TextureView.SurfaceTextureListener { public static final String TAG = "JiaoZiVideoPlayer"; public static final int HANDLER_PREPARE = 0; public static final int HANDLER_RELEASE = 2; public static JZResizeTextureView textureView; public static SurfaceTexture savedSurfaceTexture; public static Surface surface; public static JZMediaManager jzMediaManager; public int positionInList = -1; public JZMediaInterface jzMediaInterface; public int currentVideoWidth = 0; public int currentVideoHeight = 0; public HandlerThread mMediaHandlerThread; public MediaHandler mMediaHandler; public Handler mainThreadHandler; public JZMediaManager() { mMediaHandlerThread = new HandlerThread(TAG); mMediaHandlerThread.start(); mMediaHandler = new MediaHandler(mMediaHandlerThread.getLooper()); mainThreadHandler = new Handler(); if (jzMediaInterface == null) jzMediaInterface = new JZMediaSystem(); } public static JZMediaManager instance() { if (jzMediaManager == null) { jzMediaManager = new JZMediaManager(); } return jzMediaManager; } public static Object[] getDataSource() { return instance().jzMediaInterface.dataSourceObjects; } //这几个方法是不是多余了,为了不让其他地方动MediaInterface的方法 public static void setDataSource(Object[] dataSourceObjects) { instance().jzMediaInterface.dataSourceObjects = dataSourceObjects; } //正在播放的url或者uri public static Object getCurrentDataSource() { return instance().jzMediaInterface.currentDataSource; } public static void setCurrentDataSource(Object currentDataSource) { instance().jzMediaInterface.currentDataSource = currentDataSource; } public static long getCurrentPosition() { return instance().jzMediaInterface.getCurrentPosition(); } public static long getDuration() { return instance().jzMediaInterface.getDuration(); } public static void seekTo(long time) { instance().jzMediaInterface.seekTo(time); } public static void pause() { instance().jzMediaInterface.pause(); } public static void start() { instance().jzMediaInterface.start(); } public static boolean isPlaying() { return instance().jzMediaInterface.isPlaying(); } public void releaseMediaPlayer() { Message msg = new Message(); msg.what = HANDLER_RELEASE; mMediaHandler.sendMessage(msg); } public void prepare() { releaseMediaPlayer(); Message msg = new Message(); msg.what = HANDLER_PREPARE; mMediaHandler.sendMessage(msg); } @Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) { Log.i(TAG, "onSurfaceTextureAvailable [" + JZVideoPlayerManager.getCurrentJzvd().hashCode() + "] "); if (savedSurfaceTexture == null) { savedSurfaceTexture = surfaceTexture; prepare(); } else { textureView.setSurfaceTexture(savedSurfaceTexture); } } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) { } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { return savedSurfaceTexture == null; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { } public class MediaHandler extends Handler { public MediaHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case HANDLER_PREPARE: currentVideoWidth = 0; currentVideoHeight = 0; jzMediaInterface.prepare(); if (surface != null) { surface.release(); } surface = new Surface(savedSurfaceTexture); jzMediaInterface.setSurface(surface); break; case HANDLER_RELEASE: jzMediaInterface.release(); break; } } } } ================================================ FILE: librarys/jiaozivideoplayer/src/main/java/cn/jzvd/JZMediaSystem.java ================================================ package cn.jzvd; import android.media.AudioManager; import android.media.MediaPlayer; import android.view.Surface; import java.lang.reflect.Method; import java.util.Map; /** * Created by Nathen on 2017/11/8. * 实现系统的播放引擎 */ public class JZMediaSystem extends JZMediaInterface implements MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnBufferingUpdateListener, MediaPlayer.OnSeekCompleteListener, MediaPlayer.OnErrorListener, MediaPlayer.OnInfoListener, MediaPlayer.OnVideoSizeChangedListener { public MediaPlayer mediaPlayer; @Override public void start() { mediaPlayer.start(); } @Override public void prepare() { try { mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); if (dataSourceObjects.length > 1) { mediaPlayer.setLooping((boolean) dataSourceObjects[1]); } mediaPlayer.setOnPreparedListener(JZMediaSystem.this); mediaPlayer.setOnCompletionListener(JZMediaSystem.this); mediaPlayer.setOnBufferingUpdateListener(JZMediaSystem.this); mediaPlayer.setScreenOnWhilePlaying(true); mediaPlayer.setOnSeekCompleteListener(JZMediaSystem.this); mediaPlayer.setOnErrorListener(JZMediaSystem.this); mediaPlayer.setOnInfoListener(JZMediaSystem.this); mediaPlayer.setOnVideoSizeChangedListener(JZMediaSystem.this); Class clazz = MediaPlayer.class; Method method = clazz.getDeclaredMethod("setDataSource", String.class, Map.class); if (dataSourceObjects.length > 2) { method.invoke(mediaPlayer, currentDataSource.toString(), dataSourceObjects[2]); } else { method.invoke(mediaPlayer, currentDataSource.toString(), null); } mediaPlayer.prepareAsync(); } catch (Exception e) { e.printStackTrace(); } } @Override public void pause() { mediaPlayer.pause(); } @Override public boolean isPlaying() { return mediaPlayer.isPlaying(); } @Override public void seekTo(long time) { mediaPlayer.seekTo((int) time); } @Override public void release() { if (mediaPlayer != null) mediaPlayer.release(); } @Override public long getCurrentPosition() { return mediaPlayer.getCurrentPosition(); } @Override public long getDuration() { return mediaPlayer.getDuration(); } @Override public void setSurface(Surface surface) { mediaPlayer.setSurface(surface); } @Override public void onPrepared(MediaPlayer mediaPlayer) { mediaPlayer.start(); if (currentDataSource.toString().toLowerCase().contains("mp3")) { JZMediaManager.instance().mainThreadHandler.post(new Runnable() { @Override public void run() { if (JZVideoPlayerManager.getCurrentJzvd() != null) { JZVideoPlayerManager.getCurrentJzvd().onPrepared(); } } }); } } @Override public void onCompletion(MediaPlayer mediaPlayer) { JZMediaManager.instance().mainThreadHandler.post(new Runnable() { @Override public void run() { if (JZVideoPlayerManager.getCurrentJzvd() != null) { JZVideoPlayerManager.getCurrentJzvd().onAutoCompletion(); } } }); } @Override public void onBufferingUpdate(MediaPlayer mediaPlayer, final int percent) { JZMediaManager.instance().mainThreadHandler.post(new Runnable() { @Override public void run() { if (JZVideoPlayerManager.getCurrentJzvd() != null) { JZVideoPlayerManager.getCurrentJzvd().setBufferProgress(percent); } } }); } @Override public void onSeekComplete(MediaPlayer mediaPlayer) { JZMediaManager.instance().mainThreadHandler.post(new Runnable() { @Override public void run() { if (JZVideoPlayerManager.getCurrentJzvd() != null) { JZVideoPlayerManager.getCurrentJzvd().onSeekComplete(); } } }); } @Override public boolean onError(MediaPlayer mediaPlayer, final int what, final int extra) { JZMediaManager.instance().mainThreadHandler.post(new Runnable() { @Override public void run() { if (JZVideoPlayerManager.getCurrentJzvd() != null) { JZVideoPlayerManager.getCurrentJzvd().onError(what, extra); } } }); return true; } @Override public boolean onInfo(MediaPlayer mediaPlayer, final int what, final int extra) { JZMediaManager.instance().mainThreadHandler.post(new Runnable() { @Override public void run() { if (JZVideoPlayerManager.getCurrentJzvd() != null) { if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) { JZVideoPlayerManager.getCurrentJzvd().onPrepared(); } else { JZVideoPlayerManager.getCurrentJzvd().onInfo(what, extra); } } } }); return false; } @Override public void onVideoSizeChanged(MediaPlayer mediaPlayer, int width, int height) { JZMediaManager.instance().currentVideoWidth = width; JZMediaManager.instance().currentVideoHeight = height; JZMediaManager.instance().mainThreadHandler.post(new Runnable() { @Override public void run() { if (JZVideoPlayerManager.getCurrentJzvd() != null) { JZVideoPlayerManager.getCurrentJzvd().onVideoSizeChanged(); } } }); } } ================================================ FILE: librarys/jiaozivideoplayer/src/main/java/cn/jzvd/JZResizeTextureView.java ================================================ package cn.jzvd; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.TextureView; import android.view.View; /** *

参照Android系统的VideoView的onMeasure方法 *
注意!relativelayout中无法全屏,要嵌套一个linearlayout

*

Referring Android system Video View of onMeasure method *
NOTE! Can not fullscreen relativelayout, to nest a linearlayout

* Created by Nathen * On 2016/06/02 00:01 */ public class JZResizeTextureView extends TextureView { protected static final String TAG = "JZResizeTextureView"; public int currentVideoWidth = 0; public int currentVideoHeight = 0; public JZResizeTextureView(Context context) { super(context); currentVideoWidth = 0; currentVideoHeight = 0; } public JZResizeTextureView(Context context, AttributeSet attrs) { super(context, attrs); currentVideoWidth = 0; currentVideoHeight = 0; } public void setVideoSize(int currentVideoWidth, int currentVideoHeight) { if (this.currentVideoWidth != currentVideoWidth || this.currentVideoHeight != currentVideoHeight) { this.currentVideoWidth = currentVideoWidth; this.currentVideoHeight = currentVideoHeight; requestLayout(); } } @Override public void setRotation(float rotation) { if (rotation != getRotation()) { super.setRotation(rotation); requestLayout(); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { Log.i(TAG, "onMeasure " + " [" + this.hashCode() + "] "); int viewRotation = (int) getRotation(); int videoWidth = currentVideoWidth; int videoHeight = currentVideoHeight; int parentHeight = ((View) getParent()).getMeasuredHeight(); int parentWidth = ((View) getParent()).getMeasuredWidth(); if (parentWidth != 0 && parentHeight != 0 && videoWidth != 0 && videoHeight != 0) { if (JZVideoPlayer.VIDEO_IMAGE_DISPLAY_TYPE == JZVideoPlayer.VIDEO_IMAGE_DISPLAY_TYPE_FILL_PARENT) { if (viewRotation == 90 || viewRotation == 270) { int tempSize = parentWidth; parentWidth = parentHeight; parentHeight = tempSize; } /**强制充满**/ videoHeight = videoWidth * parentHeight / parentWidth; } } // 如果判断成立,则说明显示的TextureView和本身的位置是有90度的旋转的,所以需要交换宽高参数。 if (viewRotation == 90 || viewRotation == 270) { int tempMeasureSpec = widthMeasureSpec; widthMeasureSpec = heightMeasureSpec; heightMeasureSpec = tempMeasureSpec; } int width = getDefaultSize(videoWidth, widthMeasureSpec); int height = getDefaultSize(videoHeight, heightMeasureSpec); if (videoWidth > 0 && videoHeight > 0) { int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); Log.i(TAG, "widthMeasureSpec [" + MeasureSpec.toString(widthMeasureSpec) + "]"); Log.i(TAG, "heightMeasureSpec [" + MeasureSpec.toString(heightMeasureSpec) + "]"); if (widthSpecMode == MeasureSpec.EXACTLY && heightSpecMode == MeasureSpec.EXACTLY) { // the size is fixed width = widthSpecSize; height = heightSpecSize; // for compatibility, we adjust size based on aspect ratio if (videoWidth * height < width * videoHeight) { width = height * videoWidth / videoHeight; } else if (videoWidth * height > width * videoHeight) { height = width * videoHeight / videoWidth; } } else if (widthSpecMode == MeasureSpec.EXACTLY) { // only the width is fixed, adjust the height to match aspect ratio if possible width = widthSpecSize; height = width * videoHeight / videoWidth; if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) { // couldn't match aspect ratio within the constraints height = heightSpecSize; width = height * videoWidth / videoHeight; } } else if (heightSpecMode == MeasureSpec.EXACTLY) { // only the height is fixed, adjust the width to match aspect ratio if possible height = heightSpecSize; width = height * videoWidth / videoHeight; if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) { // couldn't match aspect ratio within the constraints width = widthSpecSize; height = width * videoHeight / videoWidth; } } else { // neither the width nor the height are fixed, try to use actual video size width = videoWidth; height = videoHeight; if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) { // too tall, decrease both width and height height = heightSpecSize; width = height * videoWidth / videoHeight; } if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) { // too wide, decrease both width and height width = widthSpecSize; height = width * videoHeight / videoWidth; } } } else { // no size yet, just adopt the given spec sizes } if (parentWidth != 0 && parentHeight != 0 && videoWidth != 0 && videoHeight != 0) { if (JZVideoPlayer.VIDEO_IMAGE_DISPLAY_TYPE == JZVideoPlayer.VIDEO_IMAGE_DISPLAY_TYPE_ORIGINAL) { /**原图**/ height = videoHeight; width = videoWidth; } else if (JZVideoPlayer.VIDEO_IMAGE_DISPLAY_TYPE == JZVideoPlayer.VIDEO_IMAGE_DISPLAY_TYPE_FILL_SCROP) { if (viewRotation == 90 || viewRotation == 270) { int tempSize = parentWidth; parentWidth = parentHeight; parentHeight = tempSize; } /**充满剪切**/ if (videoHeight / videoWidth > parentHeight / parentWidth) { height = parentWidth / width * height; width = parentWidth; } else if (videoHeight / videoWidth < parentHeight / parentWidth) { width = parentHeight / height * width; height = parentHeight; } } } setMeasuredDimension(width, height); } } ================================================ FILE: librarys/jiaozivideoplayer/src/main/java/cn/jzvd/JZUserAction.java ================================================ package cn.jzvd; /** * Created by Nathen * On 2016/04/04 22:13 */ public interface JZUserAction { int ON_CLICK_START_ICON = 0; int ON_CLICK_START_ERROR = 1; int ON_CLICK_START_AUTO_COMPLETE = 2; int ON_CLICK_PAUSE = 3; int ON_CLICK_RESUME = 4; int ON_SEEK_POSITION = 5; int ON_AUTO_COMPLETE = 6; int ON_ENTER_FULLSCREEN = 7; int ON_QUIT_FULLSCREEN = 8; int ON_ENTER_TINYSCREEN = 9; int ON_QUIT_TINYSCREEN = 10; int ON_TOUCH_SCREEN_SEEK_VOLUME = 11; int ON_TOUCH_SCREEN_SEEK_POSITION = 12; void onEvent(int type, Object url, int screen, Object... objects); } ================================================ FILE: librarys/jiaozivideoplayer/src/main/java/cn/jzvd/JZUserActionStandard.java ================================================ package cn.jzvd; /** * Created by Nathen * On 2016/04/26 20:53 */ public interface JZUserActionStandard extends JZUserAction { int ON_CLICK_START_THUMB = 101; int ON_CLICK_BLANK = 102; } ================================================ FILE: librarys/jiaozivideoplayer/src/main/java/cn/jzvd/JZUtils.java ================================================ package cn.jzvd; import android.app.Activity; import android.content.Context; import android.content.ContextWrapper; import android.content.SharedPreferences; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.support.v7.app.AppCompatActivity; import android.support.v7.view.ContextThemeWrapper; import android.text.TextUtils; import android.util.Log; import android.view.Window; import java.util.Formatter; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Locale; /** * Created by Nathen * On 2016/02/21 12:25 */ public class JZUtils { public static final String TAG = "JiaoZiVideoPlayer"; public static String stringForTime(long timeMs) { if (timeMs <= 0 || timeMs >= 24 * 60 * 60 * 1000) { return "00:00"; } long totalSeconds = timeMs / 1000; int seconds = (int) (totalSeconds % 60); int minutes = (int) ((totalSeconds / 60) % 60); int hours = (int) (totalSeconds / 3600); StringBuilder stringBuilder = new StringBuilder(); Formatter mFormatter = new Formatter(stringBuilder, Locale.getDefault()); if (hours > 0) { return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString(); } else { return mFormatter.format("%02d:%02d", minutes, seconds).toString(); } } /** * This method requires the caller to hold the permission ACCESS_NETWORK_STATE. * * @param context context * @return if wifi is connected,return true */ public static boolean isWifiConnected(Context context) { ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); return networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI; } /** * Get activity from context object * * @param context context * @return object of Activity or null if it is not Activity */ public static Activity scanForActivity(Context context) { if (context == null) return null; if (context instanceof Activity) { return (Activity) context; } else if (context instanceof ContextWrapper) { return scanForActivity(((ContextWrapper) context).getBaseContext()); } return null; } /** * Get AppCompatActivity from context * * @param context context * @return AppCompatActivity if it's not null */ public static AppCompatActivity getAppCompActivity(Context context) { if (context == null) return null; if (context instanceof AppCompatActivity) { return (AppCompatActivity) context; } else if (context instanceof ContextThemeWrapper) { return getAppCompActivity(((ContextThemeWrapper) context).getBaseContext()); } return null; } public static void setRequestedOrientation(Context context, int orientation) { if (JZUtils.getAppCompActivity(context) != null) { JZUtils.getAppCompActivity(context).setRequestedOrientation( orientation); } else { JZUtils.scanForActivity(context).setRequestedOrientation( orientation); } } public static Window getWindow(Context context) { if (JZUtils.getAppCompActivity(context) != null) { return JZUtils.getAppCompActivity(context).getWindow(); } else { return JZUtils.scanForActivity(context).getWindow(); } } public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } public static void saveProgress(Context context, Object url, long progress) { if (!JZVideoPlayer.SAVE_PROGRESS) return; Log.i(TAG, "saveProgress: " + progress); if (progress < 5000) { progress = 0; } SharedPreferences spn = context.getSharedPreferences("JZVD_PROGRESS", Context.MODE_PRIVATE); SharedPreferences.Editor editor = spn.edit(); editor.putLong("newVersion:" + url.toString(), progress); editor.apply(); } public static long getSavedProgress(Context context, Object url) { if (!JZVideoPlayer.SAVE_PROGRESS) return 0; SharedPreferences spn; spn = context.getSharedPreferences("JZVD_PROGRESS", Context.MODE_PRIVATE); return spn.getLong("newVersion:" + url.toString(), 0); } /** * if url == null, clear all progress * * @param context context * @param url if url!=null clear this url progress */ public static void clearSavedProgress(Context context, String url) { if (TextUtils.isEmpty(url)) { SharedPreferences spn = context.getSharedPreferences("JZVD_PROGRESS", Context.MODE_PRIVATE); spn.edit().clear().apply(); } else { SharedPreferences spn = context.getSharedPreferences("JZVD_PROGRESS", Context.MODE_PRIVATE); spn.edit().putInt(url, 0).apply(); } } public static Object getCurrentFromDataSource(Object[] dataSourceObjects, int index) { LinkedHashMap map = (LinkedHashMap) dataSourceObjects[0]; if (map != null && map.size() > 0) { return getValueFromLinkedMap(map, index); } return null; } public static Object getValueFromLinkedMap(LinkedHashMap map, int index) { int currentIndex = 0; for (Iterator it = map.keySet().iterator(); it.hasNext(); ) { Object key = it.next(); if (currentIndex == index) { return map.get(key); } currentIndex++; } return null; } public static boolean dataSourceObjectsContainsUri(Object[] dataSourceObjects, Object object) { LinkedHashMap map = (LinkedHashMap) dataSourceObjects[0]; if (map != null) { return map.containsValue(object); } return false; } public static String getKeyFromDataSource(Object[] dataSourceObjects, int index) { LinkedHashMap map = (LinkedHashMap) dataSourceObjects[0]; int currentIndex = 0; for (Iterator it = map.keySet().iterator(); it.hasNext(); ) { Object key = it.next(); if (currentIndex == index) { return key.toString(); } currentIndex++; } return null; } } ================================================ FILE: librarys/jiaozivideoplayer/src/main/java/cn/jzvd/JZVideoPlayer.java ================================================ package cn.jzvd; import android.annotation.SuppressLint; import android.content.Context; import android.content.pm.ActivityInfo; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.media.AudioManager; import android.os.Handler; import android.provider.Settings; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.util.AttributeSet; import android.util.Log; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; import android.view.Window; import android.view.WindowManager; import android.widget.AbsListView; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.SeekBar; import android.widget.TextView; import android.widget.Toast; import java.lang.reflect.Constructor; import java.util.LinkedHashMap; import java.util.Timer; import java.util.TimerTask; /** * Created by Nathen on 16/7/30. */ public abstract class JZVideoPlayer extends FrameLayout implements View.OnClickListener, SeekBar.OnSeekBarChangeListener, View.OnTouchListener { public static final String TAG = "JiaoZiVideoPlayer"; public static final int THRESHOLD = 80; public static final int FULL_SCREEN_NORMAL_DELAY = 300; public static final int SCREEN_WINDOW_NORMAL = 0; public static final int SCREEN_WINDOW_LIST = 1; public static final int SCREEN_WINDOW_FULLSCREEN = 2; public static final int SCREEN_WINDOW_TINY = 3; public static final int CURRENT_STATE_NORMAL = 0; public static final int CURRENT_STATE_PREPARING = 1; public static final int CURRENT_STATE_PREPARING_CHANGING_URL = 2; public static final int CURRENT_STATE_PLAYING = 3; public static final int CURRENT_STATE_PAUSE = 5; public static final int CURRENT_STATE_AUTO_COMPLETE = 6; public static final int CURRENT_STATE_ERROR = 7; public static final String URL_KEY_DEFAULT = "URL_KEY_DEFAULT";//当播放的地址只有一个的时候的key public static final int VIDEO_IMAGE_DISPLAY_TYPE_ADAPTER = 0;//default public static final int VIDEO_IMAGE_DISPLAY_TYPE_FILL_PARENT = 1; public static final int VIDEO_IMAGE_DISPLAY_TYPE_FILL_SCROP = 2; public static final int VIDEO_IMAGE_DISPLAY_TYPE_ORIGINAL = 3; public static boolean ACTION_BAR_EXIST = true; public static boolean TOOL_BAR_EXIST = true; public static int FULLSCREEN_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_SENSOR; public static int NORMAL_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; public static boolean SAVE_PROGRESS = true; public static boolean WIFI_TIP_DIALOG_SHOWED = false; public static int VIDEO_IMAGE_DISPLAY_TYPE = 0; public static long CLICK_QUIT_FULLSCREEN_TIME = 0; public static long lastAutoFullscreenTime = 0; public static AudioManager.OnAudioFocusChangeListener onAudioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() {//是否新建个class,代码更规矩,并且变量的位置也很尴尬 @Override public void onAudioFocusChange(int focusChange) { switch (focusChange) { case AudioManager.AUDIOFOCUS_GAIN: break; case AudioManager.AUDIOFOCUS_LOSS: releaseAllVideos(); Log.d(TAG, "AUDIOFOCUS_LOSS [" + this.hashCode() + "]"); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: try { if (JZMediaManager.isPlaying()) { JZMediaManager.pause(); } } catch (IllegalStateException e) { e.printStackTrace(); } Log.d(TAG, "AUDIOFOCUS_LOSS_TRANSIENT [" + this.hashCode() + "]"); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: break; } } }; protected static JZUserAction JZ_USER_EVENT; protected static Timer UPDATE_PROGRESS_TIMER; public int currentState = -1; public int currentScreen = -1; public Object[] objects = null; public long seekToInAdvance = 0; public ImageView startButton; public SeekBar progressBar; public ImageView fullscreenButton; public TextView currentTimeTextView, totalTimeTextView; public ViewGroup textureViewContainer; public ViewGroup topContainer, bottomContainer; public int widthRatio = 0; public int heightRatio = 0; public Object[] dataSourceObjects;//这个参数原封不动直接通过JZMeidaManager传给JZMediaInterface。 public int currentUrlMapIndex = 0; public int positionInList = -1; public int videoRotation = 0; protected int mScreenWidth; protected int mScreenHeight; protected AudioManager mAudioManager; protected Handler mHandler; protected ProgressTimerTask mProgressTimerTask; protected boolean mTouchingProgressBar; protected float mDownX; protected float mDownY; protected boolean mChangeVolume; protected boolean mChangePosition; protected boolean mChangeBrightness; protected long mGestureDownPosition; protected int mGestureDownVolume; protected float mGestureDownBrightness; protected long mSeekTimePosition; boolean tmp_test_back = false; public JZVideoPlayer(Context context) { super(context); init(context); } public JZVideoPlayer(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public static void releaseAllVideos() { if ((System.currentTimeMillis() - CLICK_QUIT_FULLSCREEN_TIME) > FULL_SCREEN_NORMAL_DELAY) { Log.d(TAG, "releaseAllVideos"); JZVideoPlayerManager.completeAll(); JZMediaManager.instance().positionInList = -1; JZMediaManager.instance().releaseMediaPlayer(); } } public static void startFullscreen(Context context, Class _class, String url, Object... objects) { LinkedHashMap map = new LinkedHashMap(); map.put(URL_KEY_DEFAULT, url); Object[] dataSourceObjects = new Object[1]; dataSourceObjects[0] = map; startFullscreen(context, _class, dataSourceObjects, 0, objects); } public static void startFullscreen(Context context, Class _class, Object[] dataSourceObjects, int defaultUrlMapIndex, Object... objects) { hideSupportActionBar(context); JZUtils.setRequestedOrientation(context, FULLSCREEN_ORIENTATION); ViewGroup vp = (JZUtils.scanForActivity(context))//.getWindow().getDecorView(); .findViewById(Window.ID_ANDROID_CONTENT); View old = vp.findViewById(R.id.jz_fullscreen_id); if (old != null) { vp.removeView(old); } try { Constructor constructor = _class.getConstructor(Context.class); final JZVideoPlayer jzVideoPlayer = constructor.newInstance(context); jzVideoPlayer.setId(R.id.jz_fullscreen_id); FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); vp.addView(jzVideoPlayer, lp); // final Animation ra = AnimationUtils.loadAnimation(context, R.anim.start_fullscreen); // jzVideoPlayer.setAnimation(ra); jzVideoPlayer.setUp(dataSourceObjects, defaultUrlMapIndex, JZVideoPlayerStandard.SCREEN_WINDOW_FULLSCREEN, objects); CLICK_QUIT_FULLSCREEN_TIME = System.currentTimeMillis(); jzVideoPlayer.startButton.performClick(); } catch (InstantiationException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } public static boolean backPress() { Log.i(TAG, "backPress"); if ((System.currentTimeMillis() - CLICK_QUIT_FULLSCREEN_TIME) < FULL_SCREEN_NORMAL_DELAY) return false; if (JZVideoPlayerManager.getSecondFloor() != null) { CLICK_QUIT_FULLSCREEN_TIME = System.currentTimeMillis(); if (JZUtils.dataSourceObjectsContainsUri(JZVideoPlayerManager.getFirstFloor().dataSourceObjects, JZMediaManager.getCurrentDataSource())) { JZVideoPlayer jzVideoPlayer = JZVideoPlayerManager.getSecondFloor(); jzVideoPlayer.onEvent(jzVideoPlayer.currentScreen == JZVideoPlayerStandard.SCREEN_WINDOW_FULLSCREEN ? JZUserAction.ON_QUIT_FULLSCREEN : JZUserAction.ON_QUIT_TINYSCREEN); JZVideoPlayerManager.getFirstFloor().playOnThisJzvd(); } else { quitFullscreenOrTinyWindow(); } return true; } else if (JZVideoPlayerManager.getFirstFloor() != null && (JZVideoPlayerManager.getFirstFloor().currentScreen == SCREEN_WINDOW_FULLSCREEN || JZVideoPlayerManager.getFirstFloor().currentScreen == SCREEN_WINDOW_TINY)) {//以前我总想把这两个判断写到一起,这分明是两个独立是逻辑 CLICK_QUIT_FULLSCREEN_TIME = System.currentTimeMillis(); quitFullscreenOrTinyWindow(); return true; } return false; } public static void quitFullscreenOrTinyWindow() { //直接退出全屏和小窗 JZVideoPlayerManager.getFirstFloor().clearFloatScreen(); JZMediaManager.instance().releaseMediaPlayer(); JZVideoPlayerManager.completeAll(); } @SuppressLint("RestrictedApi") public static void showSupportActionBar(Context context) { if (ACTION_BAR_EXIST && JZUtils.getAppCompActivity(context) != null) { ActionBar ab = JZUtils.getAppCompActivity(context).getSupportActionBar(); if (ab != null) { ab.setShowHideAnimationEnabled(false); ab.show(); } } if (TOOL_BAR_EXIST) { JZUtils.getWindow(context).clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); } } @SuppressLint("RestrictedApi") public static void hideSupportActionBar(Context context) { if (ACTION_BAR_EXIST && JZUtils.getAppCompActivity(context) != null) { ActionBar ab = JZUtils.getAppCompActivity(context).getSupportActionBar(); if (ab != null) { ab.setShowHideAnimationEnabled(false); ab.hide(); } } if (TOOL_BAR_EXIST) { JZUtils.getWindow(context).setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); } } public static void clearSavedProgress(Context context, String url) { JZUtils.clearSavedProgress(context, url); } public static void setJzUserAction(JZUserAction jzUserEvent) { JZ_USER_EVENT = jzUserEvent; } public static void goOnPlayOnResume() { if (JZVideoPlayerManager.getCurrentJzvd() != null) { JZVideoPlayer jzvd = JZVideoPlayerManager.getCurrentJzvd(); if (jzvd.currentState == JZVideoPlayer.CURRENT_STATE_PAUSE) { jzvd.onStatePlaying(); JZMediaManager.start(); } } } public static void goOnPlayOnPause() { if (JZVideoPlayerManager.getCurrentJzvd() != null) { JZVideoPlayer jzvd = JZVideoPlayerManager.getCurrentJzvd(); if (jzvd.currentState == JZVideoPlayer.CURRENT_STATE_AUTO_COMPLETE || jzvd.currentState == JZVideoPlayer.CURRENT_STATE_NORMAL || jzvd.currentState == JZVideoPlayer.CURRENT_STATE_ERROR) { // JZVideoPlayer.releaseAllVideos(); } else { jzvd.onStatePause(); JZMediaManager.pause(); } } } public static void onScrollAutoTiny(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { int lastVisibleItem = firstVisibleItem + visibleItemCount; int currentPlayPosition = JZMediaManager.instance().positionInList; if (currentPlayPosition >= 0) { if ((currentPlayPosition < firstVisibleItem || currentPlayPosition > (lastVisibleItem - 1))) { if (JZVideoPlayerManager.getCurrentJzvd() != null && JZVideoPlayerManager.getCurrentJzvd().currentScreen != JZVideoPlayer.SCREEN_WINDOW_TINY && JZVideoPlayerManager.getCurrentJzvd().currentScreen != JZVideoPlayer.SCREEN_WINDOW_FULLSCREEN) { if (JZVideoPlayerManager.getCurrentJzvd().currentState == JZVideoPlayer.CURRENT_STATE_PAUSE) { JZVideoPlayer.releaseAllVideos(); } else { Log.e(TAG, "onScroll: out screen"); JZVideoPlayerManager.getCurrentJzvd().startWindowTiny(); } } } else { if (JZVideoPlayerManager.getCurrentJzvd() != null && JZVideoPlayerManager.getCurrentJzvd().currentScreen == JZVideoPlayer.SCREEN_WINDOW_TINY) { Log.e(TAG, "onScroll: into screen"); JZVideoPlayer.backPress(); } } } } public static void onScrollReleaseAllVideos(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { int lastVisibleItem = firstVisibleItem + visibleItemCount; int currentPlayPosition = JZMediaManager.instance().positionInList; Log.e(TAG, "onScrollReleaseAllVideos: " + currentPlayPosition + " " + firstVisibleItem + " " + currentPlayPosition + " " + lastVisibleItem); if (currentPlayPosition >= 0) { if ((currentPlayPosition < firstVisibleItem || currentPlayPosition > (lastVisibleItem - 1))) { if (JZVideoPlayerManager.getCurrentJzvd().currentScreen != JZVideoPlayer.SCREEN_WINDOW_FULLSCREEN) { JZVideoPlayer.releaseAllVideos();//为什么最后一个视频横屏会调用这个,其他地方不会 } } } } public static void onChildViewAttachedToWindow(View view, int jzvdId) { if (JZVideoPlayerManager.getCurrentJzvd() != null && JZVideoPlayerManager.getCurrentJzvd().currentScreen == JZVideoPlayer.SCREEN_WINDOW_TINY) { JZVideoPlayer videoPlayer = view.findViewById(jzvdId); if (videoPlayer != null && JZUtils.getCurrentFromDataSource(videoPlayer.dataSourceObjects, videoPlayer.currentUrlMapIndex).equals(JZMediaManager.getCurrentDataSource())) { JZVideoPlayer.backPress(); } } } public static void onChildViewDetachedFromWindow(View view) { if (JZVideoPlayerManager.getCurrentJzvd() != null && JZVideoPlayerManager.getCurrentJzvd().currentScreen != JZVideoPlayer.SCREEN_WINDOW_TINY) { JZVideoPlayer videoPlayer = JZVideoPlayerManager.getCurrentJzvd(); if (((ViewGroup) view).indexOfChild(videoPlayer) != -1) { if (videoPlayer.currentState == JZVideoPlayer.CURRENT_STATE_PAUSE) { JZVideoPlayer.releaseAllVideos(); } else { videoPlayer.startWindowTiny(); } } } } public static void setTextureViewRotation(int rotation) { if (JZMediaManager.textureView != null) { JZMediaManager.textureView.setRotation(rotation); } } public static void setVideoImageDisplayType(int type) { JZVideoPlayer.VIDEO_IMAGE_DISPLAY_TYPE = type; if (JZMediaManager.textureView != null) { JZMediaManager.textureView.requestLayout(); } } public Object getCurrentUrl() { return JZUtils.getCurrentFromDataSource(dataSourceObjects, currentUrlMapIndex); } public abstract int getLayoutId(); public void init(Context context) { View.inflate(context, getLayoutId(), this); startButton = findViewById(R.id.start); fullscreenButton = findViewById(R.id.fullscreen); progressBar = findViewById(R.id.bottom_seek_progress); currentTimeTextView = findViewById(R.id.current); totalTimeTextView = findViewById(R.id.total); bottomContainer = findViewById(R.id.layout_bottom); textureViewContainer = findViewById(R.id.surface_container); topContainer = findViewById(R.id.layout_top); startButton.setOnClickListener(this); fullscreenButton.setOnClickListener(this); progressBar.setOnSeekBarChangeListener(this); bottomContainer.setOnClickListener(this); textureViewContainer.setOnClickListener(this); textureViewContainer.setOnTouchListener(this); mScreenWidth = getContext().getResources().getDisplayMetrics().widthPixels; mScreenHeight = getContext().getResources().getDisplayMetrics().heightPixels; mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); mHandler = new Handler(); try { if (isCurrentPlay()) { NORMAL_ORIENTATION = ((AppCompatActivity) context).getRequestedOrientation(); } } catch (Exception e) { e.printStackTrace(); } } public void setUp(String url, int screen, String objects) { LinkedHashMap map = new LinkedHashMap(); map.put(URL_KEY_DEFAULT, url); Object[] dataSourceObjects = new Object[1]; dataSourceObjects[0] = map; setUp(dataSourceObjects, 0, screen, objects); } public void setUp(Object[] dataSourceObjects, int defaultUrlMapIndex, int screen, Object... objects) { if (this.dataSourceObjects != null && JZUtils.getCurrentFromDataSource(dataSourceObjects, currentUrlMapIndex) != null && JZUtils.getCurrentFromDataSource(this.dataSourceObjects, currentUrlMapIndex).equals(JZUtils.getCurrentFromDataSource(dataSourceObjects, currentUrlMapIndex))) { return; } if (isCurrentJZVD() && JZUtils.dataSourceObjectsContainsUri(dataSourceObjects, JZMediaManager.getCurrentDataSource())) { long position = 0; try { position = JZMediaManager.getCurrentPosition(); } catch (IllegalStateException e) { e.printStackTrace(); } if (position != 0) { JZUtils.saveProgress(getContext(), JZMediaManager.getCurrentDataSource(), position); } JZMediaManager.instance().releaseMediaPlayer(); } else if (isCurrentJZVD() && !JZUtils.dataSourceObjectsContainsUri(dataSourceObjects, JZMediaManager.getCurrentDataSource())) { startWindowTiny(); } else if (!isCurrentJZVD() && JZUtils.dataSourceObjectsContainsUri(dataSourceObjects, JZMediaManager.getCurrentDataSource())) { if (JZVideoPlayerManager.getCurrentJzvd() != null && JZVideoPlayerManager.getCurrentJzvd().currentScreen == JZVideoPlayer.SCREEN_WINDOW_TINY) { //需要退出小窗退到我这里,我这里是第一层级 tmp_test_back = true; } } else if (!isCurrentJZVD() && !JZUtils.dataSourceObjectsContainsUri(dataSourceObjects, JZMediaManager.getCurrentDataSource())) { } this.dataSourceObjects = dataSourceObjects; this.currentUrlMapIndex = defaultUrlMapIndex; this.currentScreen = screen; this.objects = objects; onStateNormal(); } @Override public void onClick(View v) { int i = v.getId(); if (i == R.id.start) { Log.i(TAG, "onClick start [" + this.hashCode() + "] "); if (dataSourceObjects == null || JZUtils.getCurrentFromDataSource(dataSourceObjects, currentUrlMapIndex) == null) { Toast.makeText(getContext(), getResources().getString(R.string.no_url), Toast.LENGTH_SHORT).show(); return; } if (currentState == CURRENT_STATE_NORMAL) { if (!JZUtils.getCurrentFromDataSource(dataSourceObjects, currentUrlMapIndex).toString().startsWith("file") && ! JZUtils.getCurrentFromDataSource(dataSourceObjects, currentUrlMapIndex).toString().startsWith("/") && !JZUtils.isWifiConnected(getContext()) && !WIFI_TIP_DIALOG_SHOWED) { showWifiDialog(JZUserAction.ON_CLICK_START_ICON); return; } startVideo(); onEvent(JZUserAction.ON_CLICK_START_ICON); } else if (currentState == CURRENT_STATE_PLAYING) { onEvent(JZUserAction.ON_CLICK_PAUSE); Log.d(TAG, "pauseVideo [" + this.hashCode() + "] "); JZMediaManager.pause(); onStatePause(); } else if (currentState == CURRENT_STATE_PAUSE) { onEvent(JZUserAction.ON_CLICK_RESUME); JZMediaManager.start(); onStatePlaying(); } else if (currentState == CURRENT_STATE_AUTO_COMPLETE) { onEvent(JZUserAction.ON_CLICK_START_AUTO_COMPLETE); startVideo(); } } else if (i == R.id.fullscreen) { Log.i(TAG, "onClick fullscreen [" + this.hashCode() + "] "); if (currentState == CURRENT_STATE_AUTO_COMPLETE) return; if (currentScreen == SCREEN_WINDOW_FULLSCREEN) { //quit fullscreen backPress(); } else { Log.d(TAG, "toFullscreenActivity [" + this.hashCode() + "] "); onEvent(JZUserAction.ON_ENTER_FULLSCREEN); startWindowFullscreen(); } } } @Override public boolean onTouch(View v, MotionEvent event) { float x = event.getX(); float y = event.getY(); int id = v.getId(); if (id == R.id.surface_container) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: Log.i(TAG, "onTouch surfaceContainer actionDown [" + this.hashCode() + "] "); mTouchingProgressBar = true; mDownX = x; mDownY = y; mChangeVolume = false; mChangePosition = false; mChangeBrightness = false; break; case MotionEvent.ACTION_MOVE: Log.i(TAG, "onTouch surfaceContainer actionMove [" + this.hashCode() + "] "); float deltaX = x - mDownX; float deltaY = y - mDownY; float absDeltaX = Math.abs(deltaX); float absDeltaY = Math.abs(deltaY); if (currentScreen == SCREEN_WINDOW_FULLSCREEN) { if (!mChangePosition && !mChangeVolume && !mChangeBrightness) { if (absDeltaX > THRESHOLD || absDeltaY > THRESHOLD) { cancelProgressTimer(); if (absDeltaX >= THRESHOLD) { // 全屏模式下的CURRENT_STATE_ERROR状态下,不响应进度拖动事件. // 否则会因为mediaplayer的状态非法导致App Crash if (currentState != CURRENT_STATE_ERROR) { mChangePosition = true; mGestureDownPosition = getCurrentPositionWhenPlaying(); } } else { //如果y轴滑动距离超过设置的处理范围,那么进行滑动事件处理 if (mDownX < mScreenWidth * 0.5f) {//左侧改变亮度 mChangeBrightness = true; WindowManager.LayoutParams lp = JZUtils.getWindow(getContext()).getAttributes(); if (lp.screenBrightness < 0) { try { mGestureDownBrightness = Settings.System.getInt(getContext().getContentResolver(), Settings.System.SCREEN_BRIGHTNESS); Log.i(TAG, "current system brightness: " + mGestureDownBrightness); } catch (Settings.SettingNotFoundException e) { e.printStackTrace(); } } else { mGestureDownBrightness = lp.screenBrightness * 255; Log.i(TAG, "current activity brightness: " + mGestureDownBrightness); } } else {//右侧改变声音 mChangeVolume = true; mGestureDownVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); } } } } } if (mChangePosition) { long totalTimeDuration = getDuration(); mSeekTimePosition = (int) (mGestureDownPosition + deltaX * totalTimeDuration / mScreenWidth); if (mSeekTimePosition > totalTimeDuration) mSeekTimePosition = totalTimeDuration; String seekTime = JZUtils.stringForTime(mSeekTimePosition); String totalTime = JZUtils.stringForTime(totalTimeDuration); showProgressDialog(deltaX, seekTime, mSeekTimePosition, totalTime, totalTimeDuration); } if (mChangeVolume) { deltaY = -deltaY; int max = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); int deltaV = (int) (max * deltaY * 3 / mScreenHeight); mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, mGestureDownVolume + deltaV, 0); //dialog中显示百分比 int volumePercent = (int) (mGestureDownVolume * 100 / max + deltaY * 3 * 100 / mScreenHeight); showVolumeDialog(-deltaY, volumePercent); } if (mChangeBrightness) { deltaY = -deltaY; int deltaV = (int) (255 * deltaY * 3 / mScreenHeight); WindowManager.LayoutParams params = JZUtils.getWindow(getContext()).getAttributes(); if (((mGestureDownBrightness + deltaV) / 255) >= 1) {//这和声音有区别,必须自己过滤一下负值 params.screenBrightness = 1; } else if (((mGestureDownBrightness + deltaV) / 255) <= 0) { params.screenBrightness = 0.01f; } else { params.screenBrightness = (mGestureDownBrightness + deltaV) / 255; } JZUtils.getWindow(getContext()).setAttributes(params); //dialog中显示百分比 int brightnessPercent = (int) (mGestureDownBrightness * 100 / 255 + deltaY * 3 * 100 / mScreenHeight); showBrightnessDialog(brightnessPercent); // mDownY = y; } break; case MotionEvent.ACTION_UP: Log.i(TAG, "onTouch surfaceContainer actionUp [" + this.hashCode() + "] "); mTouchingProgressBar = false; dismissProgressDialog(); dismissVolumeDialog(); dismissBrightnessDialog(); if (mChangePosition) { onEvent(JZUserAction.ON_TOUCH_SCREEN_SEEK_POSITION); JZMediaManager.seekTo(mSeekTimePosition); long duration = getDuration(); int progress = (int) (mSeekTimePosition * 100 / (duration == 0 ? 1 : duration)); progressBar.setProgress(progress); } if (mChangeVolume) { onEvent(JZUserAction.ON_TOUCH_SCREEN_SEEK_VOLUME); } startProgressTimer(); break; } } return false; } public void startVideo() { JZVideoPlayerManager.completeAll(); Log.d(TAG, "startVideo [" + this.hashCode() + "] "); initTextureView(); addTextureView(); AudioManager mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); mAudioManager.requestAudioFocus(onAudioFocusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); JZUtils.scanForActivity(getContext()).getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); JZMediaManager.setDataSource(dataSourceObjects); JZMediaManager.setCurrentDataSource(JZUtils.getCurrentFromDataSource(dataSourceObjects, currentUrlMapIndex)); JZMediaManager.instance().positionInList = positionInList; onStatePreparing(); JZVideoPlayerManager.setFirstFloor(this); } public void onPrepared() { Log.i(TAG, "onPrepared " + " [" + this.hashCode() + "] "); onStatePrepared(); onStatePlaying(); } public void setState(int state) { setState(state, 0, 0); } public void setState(int state, int urlMapIndex, int seekToInAdvance) { switch (state) { case CURRENT_STATE_NORMAL: onStateNormal(); break; case CURRENT_STATE_PREPARING: onStatePreparing(); break; case CURRENT_STATE_PREPARING_CHANGING_URL: onStatePreparingChangingUrl(urlMapIndex, seekToInAdvance); break; case CURRENT_STATE_PLAYING: onStatePlaying(); break; case CURRENT_STATE_PAUSE: onStatePause(); break; case CURRENT_STATE_ERROR: onStateError(); break; case CURRENT_STATE_AUTO_COMPLETE: onStateAutoComplete(); break; } } public void onStateNormal() { Log.i(TAG, "onStateNormal " + " [" + this.hashCode() + "] "); currentState = CURRENT_STATE_NORMAL; cancelProgressTimer(); } public void onStatePreparing() { Log.i(TAG, "onStatePreparing " + " [" + this.hashCode() + "] "); currentState = CURRENT_STATE_PREPARING; resetProgressAndTime(); } public void onStatePreparingChangingUrl(int urlMapIndex, long seekToInAdvance) { currentState = CURRENT_STATE_PREPARING_CHANGING_URL; this.currentUrlMapIndex = urlMapIndex; this.seekToInAdvance = seekToInAdvance; JZMediaManager.setDataSource(dataSourceObjects); JZMediaManager.setCurrentDataSource(JZUtils.getCurrentFromDataSource(dataSourceObjects, currentUrlMapIndex)); JZMediaManager.instance().prepare(); } public void onStatePrepared() {//因为这个紧接着就会进入播放状态,所以不设置state if (seekToInAdvance != 0) { JZMediaManager.seekTo(seekToInAdvance); seekToInAdvance = 0; } else { long position = JZUtils.getSavedProgress(getContext(), JZUtils.getCurrentFromDataSource(dataSourceObjects, currentUrlMapIndex)); if (position != 0) { JZMediaManager.seekTo(position); } } } public void onStatePlaying() { Log.i(TAG, "onStatePlaying " + " [" + this.hashCode() + "] "); currentState = CURRENT_STATE_PLAYING; startProgressTimer(); } public void onStatePause() { Log.i(TAG, "onStatePause " + " [" + this.hashCode() + "] "); currentState = CURRENT_STATE_PAUSE; startProgressTimer(); } public void onStateError() { Log.i(TAG, "onStateError " + " [" + this.hashCode() + "] "); currentState = CURRENT_STATE_ERROR; cancelProgressTimer(); } public void onStateAutoComplete() { Log.i(TAG, "onStateAutoComplete " + " [" + this.hashCode() + "] "); currentState = CURRENT_STATE_AUTO_COMPLETE; cancelProgressTimer(); progressBar.setProgress(100); currentTimeTextView.setText(totalTimeTextView.getText()); } public void onInfo(int what, int extra) { Log.d(TAG, "onInfo what - " + what + " extra - " + extra); } public void onError(int what, int extra) { Log.e(TAG, "onError " + what + " - " + extra + " [" + this.hashCode() + "] "); if (what != 38 && extra != -38 && what != -38 && extra != 38 && extra != -19) { onStateError(); if (isCurrentPlay()) { JZMediaManager.instance().releaseMediaPlayer(); } } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (currentScreen == SCREEN_WINDOW_FULLSCREEN || currentScreen == SCREEN_WINDOW_TINY) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); return; } if (widthRatio != 0 && heightRatio != 0) { int specWidth = MeasureSpec.getSize(widthMeasureSpec); int specHeight = (int) ((specWidth * (float) heightRatio) / widthRatio); setMeasuredDimension(specWidth, specHeight); int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(specWidth, MeasureSpec.EXACTLY); int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(specHeight, MeasureSpec.EXACTLY); getChildAt(0).measure(childWidthMeasureSpec, childHeightMeasureSpec); } else { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } } public void onAutoCompletion() { Runtime.getRuntime().gc(); Log.i(TAG, "onAutoCompletion " + " [" + this.hashCode() + "] "); onEvent(JZUserAction.ON_AUTO_COMPLETE); dismissVolumeDialog(); dismissProgressDialog(); dismissBrightnessDialog(); onStateAutoComplete(); if (currentScreen == SCREEN_WINDOW_FULLSCREEN || currentScreen == SCREEN_WINDOW_TINY) { backPress(); } JZMediaManager.instance().releaseMediaPlayer(); JZUtils.saveProgress(getContext(), JZUtils.getCurrentFromDataSource(dataSourceObjects, currentUrlMapIndex), 0); } public void onCompletion() { Log.i(TAG, "onCompletion " + " [" + this.hashCode() + "] "); if (currentState == CURRENT_STATE_PLAYING || currentState == CURRENT_STATE_PAUSE) { long position = getCurrentPositionWhenPlaying(); JZUtils.saveProgress(getContext(), JZUtils.getCurrentFromDataSource(dataSourceObjects, currentUrlMapIndex), position); } cancelProgressTimer(); onStateNormal(); textureViewContainer.removeView(JZMediaManager.textureView); JZMediaManager.instance().currentVideoWidth = 0; JZMediaManager.instance().currentVideoHeight = 0; AudioManager mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); mAudioManager.abandonAudioFocus(onAudioFocusChangeListener); JZUtils.scanForActivity(getContext()).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); clearFullscreenLayout(); JZUtils.setRequestedOrientation(getContext(), NORMAL_ORIENTATION); if (JZMediaManager.surface != null) JZMediaManager.surface.release(); if (JZMediaManager.savedSurfaceTexture != null) JZMediaManager.savedSurfaceTexture.release(); JZMediaManager.textureView = null; JZMediaManager.savedSurfaceTexture = null; } public void release() { if (JZUtils.getCurrentFromDataSource(dataSourceObjects, currentUrlMapIndex).equals(JZMediaManager.getCurrentDataSource()) && (System.currentTimeMillis() - CLICK_QUIT_FULLSCREEN_TIME) > FULL_SCREEN_NORMAL_DELAY) { //在非全屏的情况下只能backPress() if (JZVideoPlayerManager.getSecondFloor() != null && JZVideoPlayerManager.getSecondFloor().currentScreen == SCREEN_WINDOW_FULLSCREEN) {//点击全屏 } else if (JZVideoPlayerManager.getSecondFloor() == null && JZVideoPlayerManager.getFirstFloor() != null && JZVideoPlayerManager.getFirstFloor().currentScreen == SCREEN_WINDOW_FULLSCREEN) {//直接全屏 } else { Log.d(TAG, "releaseMediaPlayer [" + this.hashCode() + "]"); releaseAllVideos(); } } } public void initTextureView() { removeTextureView(); JZMediaManager.textureView = new JZResizeTextureView(getContext()); JZMediaManager.textureView.setSurfaceTextureListener(JZMediaManager.instance()); } public void addTextureView() { Log.d(TAG, "addTextureView [" + this.hashCode() + "] "); FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER); textureViewContainer.addView(JZMediaManager.textureView, layoutParams); } public void removeTextureView() { JZMediaManager.savedSurfaceTexture = null; if (JZMediaManager.textureView != null && JZMediaManager.textureView.getParent() != null) { ((ViewGroup) JZMediaManager.textureView.getParent()).removeView(JZMediaManager.textureView); } } public void clearFullscreenLayout() { ViewGroup vp = (JZUtils.scanForActivity(getContext()))//.getWindow().getDecorView(); .findViewById(Window.ID_ANDROID_CONTENT); View oldF = vp.findViewById(R.id.jz_fullscreen_id); View oldT = vp.findViewById(R.id.jz_tiny_id); if (oldF != null) { vp.removeView(oldF); } if (oldT != null) { vp.removeView(oldT); } showSupportActionBar(getContext()); } public void clearFloatScreen() { JZUtils.setRequestedOrientation(getContext(), NORMAL_ORIENTATION); showSupportActionBar(getContext()); JZVideoPlayer currJzvd = JZVideoPlayerManager.getCurrentJzvd(); currJzvd.textureViewContainer.removeView(JZMediaManager.textureView); ViewGroup vp = (JZUtils.scanForActivity(getContext()))//.getWindow().getDecorView(); .findViewById(Window.ID_ANDROID_CONTENT); vp.removeView(currJzvd); JZVideoPlayerManager.setSecondFloor(null); } public void onVideoSizeChanged() { Log.i(TAG, "onVideoSizeChanged " + " [" + this.hashCode() + "] "); if (JZMediaManager.textureView != null) { if (videoRotation != 0) { JZMediaManager.textureView.setRotation(videoRotation); } JZMediaManager.textureView.setVideoSize(JZMediaManager.instance().currentVideoWidth, JZMediaManager.instance().currentVideoHeight); } } public void startProgressTimer() { Log.i(TAG, "startProgressTimer: " + " [" + this.hashCode() + "] "); cancelProgressTimer(); UPDATE_PROGRESS_TIMER = new Timer(); mProgressTimerTask = new ProgressTimerTask(); UPDATE_PROGRESS_TIMER.schedule(mProgressTimerTask, 0, 300); } public void cancelProgressTimer() { if (UPDATE_PROGRESS_TIMER != null) { UPDATE_PROGRESS_TIMER.cancel(); } if (mProgressTimerTask != null) { mProgressTimerTask.cancel(); } } public void setProgressAndText(int progress, long position, long duration) { // Log.d(TAG, "setProgressAndText: progress=" + progress + " position=" + position + " duration=" + duration); if (!mTouchingProgressBar) { if (progress != 0) progressBar.setProgress(progress); } if (position != 0) currentTimeTextView.setText(JZUtils.stringForTime(position)); totalTimeTextView.setText(JZUtils.stringForTime(duration)); } public void setBufferProgress(int bufferProgress) { if (bufferProgress != 0) progressBar.setSecondaryProgress(bufferProgress); } public void resetProgressAndTime() { progressBar.setProgress(0); progressBar.setSecondaryProgress(0); currentTimeTextView.setText(JZUtils.stringForTime(0)); totalTimeTextView.setText(JZUtils.stringForTime(0)); } public long getCurrentPositionWhenPlaying() { long position = 0; //TODO 这块的判断应该根据MediaPlayer来 // if (JZMediaManager.instance().mediaPlayer == null) // return position;//这行代码不应该在这,如果代码和逻辑万无一失的话,心头之恨呐 if (currentState == CURRENT_STATE_PLAYING || currentState == CURRENT_STATE_PAUSE) { try { position = JZMediaManager.getCurrentPosition(); } catch (IllegalStateException e) { e.printStackTrace(); return position; } } return position; } public long getDuration() { long duration = 0; //TODO MediaPlayer 判空的问题 // if (JZMediaManager.instance().mediaPlayer == null) return duration; try { duration = JZMediaManager.getDuration(); } catch (IllegalStateException e) { e.printStackTrace(); return duration; } return duration; } @Override public void onStartTrackingTouch(SeekBar seekBar) { Log.i(TAG, "bottomProgress onStartTrackingTouch [" + this.hashCode() + "] "); cancelProgressTimer(); ViewParent vpdown = getParent(); while (vpdown != null) { vpdown.requestDisallowInterceptTouchEvent(true); vpdown = vpdown.getParent(); } } @Override public void onStopTrackingTouch(SeekBar seekBar) { Log.i(TAG, "bottomProgress onStopTrackingTouch [" + this.hashCode() + "] "); onEvent(JZUserAction.ON_SEEK_POSITION); startProgressTimer(); ViewParent vpup = getParent(); while (vpup != null) { vpup.requestDisallowInterceptTouchEvent(false); vpup = vpup.getParent(); } if (currentState != CURRENT_STATE_PLAYING && currentState != CURRENT_STATE_PAUSE) return; long time = seekBar.getProgress() * getDuration() / 100; JZMediaManager.seekTo(time); Log.i(TAG, "seekTo " + time + " [" + this.hashCode() + "] "); } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { } public void startWindowFullscreen() { Log.i(TAG, "startWindowFullscreen " + " [" + this.hashCode() + "] "); hideSupportActionBar(getContext()); JZUtils.setRequestedOrientation(getContext(), FULLSCREEN_ORIENTATION); ViewGroup vp = (JZUtils.scanForActivity(getContext()))//.getWindow().getDecorView(); .findViewById(Window.ID_ANDROID_CONTENT); View old = vp.findViewById(R.id.jz_fullscreen_id); if (old != null) { vp.removeView(old); } textureViewContainer.removeView(JZMediaManager.textureView); try { Constructor constructor = (Constructor) JZVideoPlayer.this.getClass().getConstructor(Context.class); JZVideoPlayer jzVideoPlayer = constructor.newInstance(getContext()); jzVideoPlayer.setId(R.id.jz_fullscreen_id); FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); vp.addView(jzVideoPlayer, lp); jzVideoPlayer.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN); jzVideoPlayer.setUp(dataSourceObjects, currentUrlMapIndex, JZVideoPlayerStandard.SCREEN_WINDOW_FULLSCREEN, objects); jzVideoPlayer.setState(currentState); jzVideoPlayer.addTextureView(); JZVideoPlayerManager.setSecondFloor(jzVideoPlayer); // final Animation ra = AnimationUtils.loadAnimation(getContext(), R.anim.start_fullscreen); // jzVideoPlayer.setAnimation(ra); onStateNormal(); jzVideoPlayer.progressBar.setSecondaryProgress(progressBar.getSecondaryProgress()); jzVideoPlayer.startProgressTimer(); CLICK_QUIT_FULLSCREEN_TIME = System.currentTimeMillis(); } catch (Exception e) { e.printStackTrace(); } } public void startWindowTiny() { Log.i(TAG, "startWindowTiny " + " [" + this.hashCode() + "] "); onEvent(JZUserAction.ON_ENTER_TINYSCREEN); if (currentState == CURRENT_STATE_NORMAL || currentState == CURRENT_STATE_ERROR || currentState == CURRENT_STATE_AUTO_COMPLETE) return; ViewGroup vp = (JZUtils.scanForActivity(getContext()))//.getWindow().getDecorView(); .findViewById(Window.ID_ANDROID_CONTENT); View old = vp.findViewById(R.id.jz_tiny_id); if (old != null) { vp.removeView(old); } textureViewContainer.removeView(JZMediaManager.textureView); try { Constructor constructor = (Constructor) JZVideoPlayer.this.getClass().getConstructor(Context.class); JZVideoPlayer jzVideoPlayer = constructor.newInstance(getContext()); jzVideoPlayer.setId(R.id.jz_tiny_id); FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(400, 400); lp.gravity = Gravity.RIGHT | Gravity.BOTTOM; vp.addView(jzVideoPlayer, lp); jzVideoPlayer.setUp(dataSourceObjects, currentUrlMapIndex, JZVideoPlayerStandard.SCREEN_WINDOW_TINY, objects); jzVideoPlayer.setState(currentState); jzVideoPlayer.addTextureView(); JZVideoPlayerManager.setSecondFloor(jzVideoPlayer); onStateNormal(); } catch (InstantiationException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } public boolean isCurrentPlay() { return isCurrentJZVD() && JZUtils.dataSourceObjectsContainsUri(dataSourceObjects, JZMediaManager.getCurrentDataSource());//不仅正在播放的url不能一样,并且各个清晰度也不能一样 } public boolean isCurrentJZVD() { return JZVideoPlayerManager.getCurrentJzvd() != null && JZVideoPlayerManager.getCurrentJzvd() == this; } //退出全屏和小窗的方法 public void playOnThisJzvd() { Log.i(TAG, "playOnThisJzvd " + " [" + this.hashCode() + "] "); //1.清空全屏和小窗的jzvd currentState = JZVideoPlayerManager.getSecondFloor().currentState; currentUrlMapIndex = JZVideoPlayerManager.getSecondFloor().currentUrlMapIndex; clearFloatScreen(); //2.在本jzvd上播放 setState(currentState); addTextureView(); } //重力感应的时候调用的函数, public void autoFullscreen(float x) { if (isCurrentPlay() && currentState == CURRENT_STATE_PLAYING && currentScreen != SCREEN_WINDOW_FULLSCREEN && currentScreen != SCREEN_WINDOW_TINY) { if (x > 0) { JZUtils.setRequestedOrientation(getContext(), ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } else { JZUtils.setRequestedOrientation(getContext(), ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); } onEvent(JZUserAction.ON_ENTER_FULLSCREEN); startWindowFullscreen(); } } public void autoQuitFullscreen() { if ((System.currentTimeMillis() - lastAutoFullscreenTime) > 2000 && isCurrentPlay() && currentState == CURRENT_STATE_PLAYING && currentScreen == SCREEN_WINDOW_FULLSCREEN) { lastAutoFullscreenTime = System.currentTimeMillis(); backPress(); } } public void onEvent(int type) { if (JZ_USER_EVENT != null && isCurrentPlay() && dataSourceObjects != null) { JZ_USER_EVENT.onEvent(type, JZUtils.getCurrentFromDataSource(dataSourceObjects, currentUrlMapIndex), currentScreen, objects); } } public static void setMediaInterface(JZMediaInterface mediaInterface) { JZMediaManager.instance().jzMediaInterface = mediaInterface; } //TODO 是否有用 public void onSeekComplete() { } public void showWifiDialog(int event) { } public void showProgressDialog(float deltaX, String seekTime, long seekTimePosition, String totalTime, long totalTimeDuration) { } public void dismissProgressDialog() { } public void showVolumeDialog(float deltaY, int volumePercent) { } public void dismissVolumeDialog() { } public void showBrightnessDialog(int brightnessPercent) { } public void dismissBrightnessDialog() { } public static class JZAutoFullscreenListener implements SensorEventListener { @Override public void onSensorChanged(SensorEvent event) {//可以得到传感器实时测量出来的变化值 final float x = event.values[SensorManager.DATA_X]; float y = event.values[SensorManager.DATA_Y]; float z = event.values[SensorManager.DATA_Z]; //过滤掉用力过猛会有一个反向的大数值 if (((x > -15 && x < -10) || (x < 15 && x > 10)) && Math.abs(y) < 1.5) { if ((System.currentTimeMillis() - lastAutoFullscreenTime) > 2000) { if (JZVideoPlayerManager.getCurrentJzvd() != null) { JZVideoPlayerManager.getCurrentJzvd().autoFullscreen(x); } lastAutoFullscreenTime = System.currentTimeMillis(); } } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } } public class ProgressTimerTask extends TimerTask { @Override public void run() { if (currentState == CURRENT_STATE_PLAYING || currentState == CURRENT_STATE_PAUSE) { // Log.v(TAG, "onProgressUpdate " + "[" + this.hashCode() + "] "); mHandler.post(new Runnable() { @Override public void run() { long position = getCurrentPositionWhenPlaying(); long duration = getDuration(); int progress = (int) (position * 100 / (duration == 0 ? 1 : duration)); setProgressAndText(progress, position, duration); } }); } } } } ================================================ FILE: librarys/jiaozivideoplayer/src/main/java/cn/jzvd/JZVideoPlayerManager.java ================================================ package cn.jzvd; /** * Put JZVideoPlayer into layout * From a JZVideoPlayer to another JZVideoPlayer * Created by Nathen on 16/7/26. */ public class JZVideoPlayerManager { public static JZVideoPlayer FIRST_FLOOR_JZVD; public static JZVideoPlayer SECOND_FLOOR_JZVD; public static JZVideoPlayer getFirstFloor() { return FIRST_FLOOR_JZVD; } public static void setFirstFloor(JZVideoPlayer jzVideoPlayer) { FIRST_FLOOR_JZVD = jzVideoPlayer; } public static JZVideoPlayer getSecondFloor() { return SECOND_FLOOR_JZVD; } public static void setSecondFloor(JZVideoPlayer jzVideoPlayer) { SECOND_FLOOR_JZVD = jzVideoPlayer; } public static JZVideoPlayer getCurrentJzvd() { if (getSecondFloor() != null) { return getSecondFloor(); } return getFirstFloor(); } public static void completeAll() { if (SECOND_FLOOR_JZVD != null) { SECOND_FLOOR_JZVD.onCompletion(); SECOND_FLOOR_JZVD = null; } if (FIRST_FLOOR_JZVD != null) { FIRST_FLOOR_JZVD.onCompletion(); FIRST_FLOOR_JZVD = null; } } } ================================================ FILE: librarys/jiaozivideoplayer/src/main/java/cn/jzvd/JZVideoPlayerStandard.java ================================================ package cn.jzvd; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Color; import android.media.AudioManager; import android.util.AttributeSet; import android.util.DebugUtils; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.PopupWindow; import android.widget.ProgressBar; import android.widget.SeekBar; import android.widget.TextView; import android.widget.Toast; import java.text.SimpleDateFormat; import java.util.Date; import java.util.LinkedHashMap; import java.util.Timer; import java.util.TimerTask; /** * Created by Nathen * On 2016/04/18 16:15 */ public class JZVideoPlayerStandard extends JZVideoPlayer { protected static Timer DISMISS_CONTROL_VIEW_TIMER; public ImageView backButton; public ProgressBar bottomProgressBar, loadingProgressBar; public TextView titleTextView; public ImageView thumbImageView; public ImageView tinyBackImageView; public LinearLayout batteryTimeLayout; public ImageView batteryLevel; public TextView videoCurrentTime; public TextView replayTextView; public TextView clarity; public PopupWindow clarityPopWindow; public TextView mRetryBtn; public LinearLayout mRetryLayout; protected DismissControlViewTimerTask mDismissControlViewTimerTask; protected Dialog mProgressDialog; protected ProgressBar mDialogProgressBar; protected TextView mDialogSeekTime; protected TextView mDialogTotalTime; protected ImageView mDialogIcon; protected Dialog mVolumeDialog; protected ProgressBar mDialogVolumeProgressBar; protected TextView mDialogVolumeTextView; protected ImageView mDialogVolumeImageView; protected Dialog mBrightnessDialog; protected ProgressBar mDialogBrightnessProgressBar; protected TextView mDialogBrightnessTextView; private boolean brocasting = false; private BroadcastReceiver battertReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { int level = intent.getIntExtra("level", 0); int scale = intent.getIntExtra("scale", 100); int percent = level * 100 / scale; if (percent < 15) { batteryLevel.setBackgroundResource(R.drawable.jz_battery_level_10); } else if (percent >= 15 && percent < 40) { batteryLevel.setBackgroundResource(R.drawable.jz_battery_level_30); } else if (percent >= 40 && percent < 60) { batteryLevel.setBackgroundResource(R.drawable.jz_battery_level_50); } else if (percent >= 60 && percent < 80) { batteryLevel.setBackgroundResource(R.drawable.jz_battery_level_70); } else if (percent >= 80 && percent < 95) { batteryLevel.setBackgroundResource(R.drawable.jz_battery_level_90); } else if (percent >= 95 && percent <= 100) { batteryLevel.setBackgroundResource(R.drawable.jz_battery_level_100); } getContext().unregisterReceiver(battertReceiver); brocasting = false; } } }; public JZVideoPlayerStandard(Context context) { super(context); } public JZVideoPlayerStandard(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void init(Context context) { super.init(context); batteryTimeLayout = findViewById(R.id.battery_time_layout); bottomProgressBar = findViewById(R.id.bottom_progress); titleTextView = findViewById(R.id.title); backButton = findViewById(R.id.back); thumbImageView = findViewById(R.id.thumb); loadingProgressBar = findViewById(R.id.loading); tinyBackImageView = findViewById(R.id.back_tiny); batteryLevel = findViewById(R.id.battery_level); videoCurrentTime = findViewById(R.id.video_current_time); replayTextView = findViewById(R.id.replay_text); clarity = findViewById(R.id.clarity); mRetryBtn = findViewById(R.id.retry_btn); mRetryLayout = findViewById(R.id.retry_layout); thumbImageView.setOnClickListener(this); backButton.setOnClickListener(this); tinyBackImageView.setOnClickListener(this); clarity.setOnClickListener(this); mRetryBtn.setOnClickListener(this); } public void setUp(Object[] dataSourceObjects, int defaultUrlMapIndex, int screen, Object... objects) { super.setUp(dataSourceObjects, defaultUrlMapIndex, screen, objects); Log.d("titlevideo012", dataSourceObjects[0] + ""); if (objects.length != 0) titleTextView.setText(objects[0].toString()); if (currentScreen == SCREEN_WINDOW_FULLSCREEN) { fullscreenButton.setImageResource(R.drawable.jz_shrink); backButton.setVisibility(View.VISIBLE); tinyBackImageView.setVisibility(View.INVISIBLE); batteryTimeLayout.setVisibility(View.VISIBLE); if (((LinkedHashMap) dataSourceObjects[0]).size() == 1) { clarity.setVisibility(GONE); } else { clarity.setText(JZUtils.getKeyFromDataSource(dataSourceObjects, currentUrlMapIndex)); clarity.setVisibility(View.VISIBLE); } changeStartButtonSize((int) getResources().getDimension(R.dimen.jz_start_button_w_h_fullscreen)); } else if (currentScreen == SCREEN_WINDOW_NORMAL || currentScreen == SCREEN_WINDOW_LIST) { fullscreenButton.setImageResource(R.drawable.jz_enlarge); backButton.setVisibility(View.GONE); tinyBackImageView.setVisibility(View.INVISIBLE); changeStartButtonSize((int) getResources().getDimension(R.dimen.jz_start_button_w_h_normal)); batteryTimeLayout.setVisibility(View.GONE); clarity.setVisibility(View.GONE); } else if (currentScreen == SCREEN_WINDOW_TINY) { tinyBackImageView.setVisibility(View.VISIBLE); setAllControlsVisiblity(View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE); batteryTimeLayout.setVisibility(View.GONE); clarity.setVisibility(View.GONE); } setSystemTimeAndBattery(); if (tmp_test_back) { tmp_test_back = false; JZVideoPlayerManager.setFirstFloor(this); backPress(); } } public void changeStartButtonSize(int size) { ViewGroup.LayoutParams lp = startButton.getLayoutParams(); lp.height = size; lp.width = size; lp = loadingProgressBar.getLayoutParams(); lp.height = size; lp.width = size; } @Override public int getLayoutId() { return R.layout.jz_layout_standard; } @Override public void onStateNormal() { super.onStateNormal(); changeUiToNormal(); } @Override public void onStatePreparing() { super.onStatePreparing(); changeUiToPreparing(); } @Override public void onStatePreparingChangingUrl(int urlMapIndex, long seekToInAdvance) { super.onStatePreparingChangingUrl(urlMapIndex, seekToInAdvance); loadingProgressBar.setVisibility(VISIBLE); startButton.setVisibility(INVISIBLE); } @Override public void onStatePlaying() { super.onStatePlaying(); changeUiToPlayingClear(); } @Override public void onStatePause() { super.onStatePause(); changeUiToPauseShow(); cancelDismissControlViewTimer(); } @Override public void onStateError() { super.onStateError(); changeUiToError(); } @Override public void onStateAutoComplete() { super.onStateAutoComplete(); changeUiToComplete(); cancelDismissControlViewTimer(); bottomProgressBar.setProgress(100); } @Override public boolean onTouch(View v, MotionEvent event) { int id = v.getId(); if (id == R.id.surface_container) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: startDismissControlViewTimer(); if (mChangePosition) { long duration = getDuration(); int progress = (int) (mSeekTimePosition * 100 / (duration == 0 ? 1 : duration)); bottomProgressBar.setProgress(progress); } if (!mChangePosition && !mChangeVolume) { onEvent(JZUserActionStandard.ON_CLICK_BLANK); onClickUiToggle(); } break; } } else if (id == R.id.bottom_seek_progress) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: cancelDismissControlViewTimer(); break; case MotionEvent.ACTION_UP: startDismissControlViewTimer(); break; } } return super.onTouch(v, event); } @Override public void onClick(View v) { super.onClick(v); int i = v.getId(); if (i == R.id.thumb) { if (dataSourceObjects == null || JZUtils.getCurrentFromDataSource(dataSourceObjects, currentUrlMapIndex) == null) { Toast.makeText(getContext(), getResources().getString(R.string.no_url), Toast.LENGTH_SHORT).show(); return; } if (currentState == CURRENT_STATE_NORMAL) { if (!JZUtils.getCurrentFromDataSource(dataSourceObjects, currentUrlMapIndex).toString().startsWith("file") && !JZUtils.getCurrentFromDataSource(dataSourceObjects, currentUrlMapIndex).toString().startsWith("/") && !JZUtils.isWifiConnected(getContext()) && !WIFI_TIP_DIALOG_SHOWED) { showWifiDialog(JZUserActionStandard.ON_CLICK_START_THUMB); return; } onEvent(JZUserActionStandard.ON_CLICK_START_THUMB); startVideo(); } else if (currentState == CURRENT_STATE_AUTO_COMPLETE) { onClickUiToggle(); } } else if (i == R.id.surface_container) { startDismissControlViewTimer(); } else if (i == R.id.back) { backPress(); } else if (i == R.id.back_tiny) { if (JZVideoPlayerManager.getFirstFloor().currentScreen == JZVideoPlayer.SCREEN_WINDOW_LIST) { quitFullscreenOrTinyWindow(); } else { backPress(); } } else if (i == R.id.clarity) { LayoutInflater inflater = (LayoutInflater) getContext() .getSystemService(Context.LAYOUT_INFLATER_SERVICE); final LinearLayout layout = (LinearLayout) inflater.inflate(R.layout.jz_layout_clarity, null); OnClickListener mQualityListener = new OnClickListener() { public void onClick(View v) { int index = (int) v.getTag(); onStatePreparingChangingUrl(index, getCurrentPositionWhenPlaying()); clarity.setText(JZUtils.getKeyFromDataSource(dataSourceObjects, currentUrlMapIndex)); for (int j = 0; j < layout.getChildCount(); j++) {//设置点击之后的颜色 if (j == currentUrlMapIndex) { ((TextView) layout.getChildAt(j)).setTextColor(Color.parseColor("#fff85959")); } else { ((TextView) layout.getChildAt(j)).setTextColor(Color.parseColor("#ffffff")); } } if (clarityPopWindow != null) { clarityPopWindow.dismiss(); } } }; for (int j = 0; j < ((LinkedHashMap) dataSourceObjects[0]).size(); j++) { String key = JZUtils.getKeyFromDataSource(dataSourceObjects, j); TextView clarityItem = (TextView) View.inflate(getContext(), R.layout.jz_layout_clarity_item, null); clarityItem.setText(key); clarityItem.setTag(j); layout.addView(clarityItem, j); clarityItem.setOnClickListener(mQualityListener); if (j == currentUrlMapIndex) { clarityItem.setTextColor(Color.parseColor("#fff85959")); } } clarityPopWindow = new PopupWindow(layout, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, true); clarityPopWindow.setContentView(layout); clarityPopWindow.showAsDropDown(clarity); layout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); clarityPopWindow.update(clarity, -40, 46, Math.round(layout.getMeasuredWidth() * 2), layout.getMeasuredHeight()); } else if (i == R.id.retry_btn) { if (!JZUtils.getCurrentFromDataSource(dataSourceObjects, currentUrlMapIndex).toString().startsWith("file") && ! JZUtils.getCurrentFromDataSource(dataSourceObjects, currentUrlMapIndex).toString().startsWith("/") && !JZUtils.isWifiConnected(getContext()) && !WIFI_TIP_DIALOG_SHOWED) { showWifiDialog(JZUserAction.ON_CLICK_START_ICON); return; } initTextureView();//和开始播放的代码重复 addTextureView(); JZMediaManager.setDataSource(dataSourceObjects); JZMediaManager.setCurrentDataSource(JZUtils.getCurrentFromDataSource(dataSourceObjects, currentUrlMapIndex)); onStatePreparing(); onEvent(JZUserAction.ON_CLICK_START_ERROR); } } @Override public void showWifiDialog(int action) { super.showWifiDialog(action); AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); builder.setMessage(getResources().getString(R.string.tips_not_wifi)); builder.setPositiveButton(getResources().getString(R.string.tips_not_wifi_confirm), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); onEvent(JZUserActionStandard.ON_CLICK_START_THUMB); startVideo(); WIFI_TIP_DIALOG_SHOWED = true; } }); builder.setNegativeButton(getResources().getString(R.string.tips_not_wifi_cancel), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { dialog.dismiss(); } }); builder.create().show(); } @Override public void onStartTrackingTouch(SeekBar seekBar) { super.onStartTrackingTouch(seekBar); cancelDismissControlViewTimer(); } @Override public void onStopTrackingTouch(SeekBar seekBar) { super.onStopTrackingTouch(seekBar); if (currentState == CURRENT_STATE_PLAYING) { dissmissControlView(); } else { startDismissControlViewTimer(); } } public void onClickUiToggle() { if (bottomContainer.getVisibility() != View.VISIBLE) { setSystemTimeAndBattery(); clarity.setText(JZUtils.getKeyFromDataSource(dataSourceObjects, currentUrlMapIndex)); } if (currentState == CURRENT_STATE_PREPARING) { changeUiToPreparing(); if (bottomContainer.getVisibility() == View.VISIBLE) { } else { setSystemTimeAndBattery(); } } else if (currentState == CURRENT_STATE_PLAYING) { if (bottomContainer.getVisibility() == View.VISIBLE) { changeUiToPlayingClear(); } else { changeUiToPlayingShow(); } } else if (currentState == CURRENT_STATE_PAUSE) { if (bottomContainer.getVisibility() == View.VISIBLE) { changeUiToPauseClear(); } else { changeUiToPauseShow(); } } } public void setSystemTimeAndBattery() { SimpleDateFormat dateFormater = new SimpleDateFormat("HH:mm"); Date date = new Date(); videoCurrentTime.setText(dateFormater.format(date)); if (!brocasting) { getContext().registerReceiver( battertReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED) ); } } public void onCLickUiToggleToClear() { if (currentState == CURRENT_STATE_PREPARING) { if (bottomContainer.getVisibility() == View.VISIBLE) { changeUiToPreparing(); } else { } } else if (currentState == CURRENT_STATE_PLAYING) { if (bottomContainer.getVisibility() == View.VISIBLE) { changeUiToPlayingClear(); } else { } } else if (currentState == CURRENT_STATE_PAUSE) { if (bottomContainer.getVisibility() == View.VISIBLE) { changeUiToPauseClear(); } else { } } else if (currentState == CURRENT_STATE_AUTO_COMPLETE) { if (bottomContainer.getVisibility() == View.VISIBLE) { changeUiToComplete(); } else { } } } @Override public void setProgressAndText(int progress, long position, long duration) { super.setProgressAndText(progress, position, duration); if (progress != 0) bottomProgressBar.setProgress(progress); } @Override public void setBufferProgress(int bufferProgress) { super.setBufferProgress(bufferProgress); if (bufferProgress != 0) bottomProgressBar.setSecondaryProgress(bufferProgress); } @Override public void resetProgressAndTime() { super.resetProgressAndTime(); bottomProgressBar.setProgress(0); bottomProgressBar.setSecondaryProgress(0); } public void changeUiToNormal() { switch (currentScreen) { case SCREEN_WINDOW_NORMAL: case SCREEN_WINDOW_LIST: setAllControlsVisiblity(View.VISIBLE, View.INVISIBLE, View.VISIBLE, View.INVISIBLE, View.VISIBLE, View.INVISIBLE, View.INVISIBLE); updateStartImage(); break; case SCREEN_WINDOW_FULLSCREEN: setAllControlsVisiblity(View.VISIBLE, View.INVISIBLE, View.VISIBLE, View.INVISIBLE, View.VISIBLE, View.INVISIBLE, View.INVISIBLE); updateStartImage(); break; case SCREEN_WINDOW_TINY: break; } } public void changeUiToPreparing() { switch (currentScreen) { case SCREEN_WINDOW_NORMAL: case SCREEN_WINDOW_LIST: setAllControlsVisiblity(View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.VISIBLE, View.VISIBLE, View.INVISIBLE, View.INVISIBLE); updateStartImage(); break; case SCREEN_WINDOW_FULLSCREEN: setAllControlsVisiblity(View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.VISIBLE, View.VISIBLE, View.INVISIBLE, View.INVISIBLE); updateStartImage(); break; case SCREEN_WINDOW_TINY: break; } } public void changeUiToPlayingShow() { switch (currentScreen) { case SCREEN_WINDOW_NORMAL: case SCREEN_WINDOW_LIST: setAllControlsVisiblity(View.VISIBLE, View.VISIBLE, View.VISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE); updateStartImage(); break; case SCREEN_WINDOW_FULLSCREEN: setAllControlsVisiblity(View.VISIBLE, View.VISIBLE, View.VISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE); updateStartImage(); break; case SCREEN_WINDOW_TINY: break; } } public void changeUiToPlayingClear() { switch (currentScreen) { case SCREEN_WINDOW_NORMAL: case SCREEN_WINDOW_LIST: setAllControlsVisiblity(View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.VISIBLE, View.INVISIBLE); break; case SCREEN_WINDOW_FULLSCREEN: setAllControlsVisiblity(View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.VISIBLE, View.INVISIBLE); break; case SCREEN_WINDOW_TINY: break; } } public void changeUiToPauseShow() { switch (currentScreen) { case SCREEN_WINDOW_NORMAL: case SCREEN_WINDOW_LIST: setAllControlsVisiblity(View.VISIBLE, View.VISIBLE, View.VISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE); updateStartImage(); break; case SCREEN_WINDOW_FULLSCREEN: setAllControlsVisiblity(View.VISIBLE, View.VISIBLE, View.VISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE); updateStartImage(); break; case SCREEN_WINDOW_TINY: break; } } public void changeUiToPauseClear() { switch (currentScreen) { case SCREEN_WINDOW_NORMAL: case SCREEN_WINDOW_LIST: setAllControlsVisiblity(View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.VISIBLE, View.INVISIBLE); break; case SCREEN_WINDOW_FULLSCREEN: setAllControlsVisiblity(View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.VISIBLE, View.INVISIBLE); break; case SCREEN_WINDOW_TINY: break; } } public void changeUiToComplete() { switch (currentScreen) { case SCREEN_WINDOW_NORMAL: case SCREEN_WINDOW_LIST: setAllControlsVisiblity(View.VISIBLE, View.INVISIBLE, View.VISIBLE, View.INVISIBLE, View.VISIBLE, View.INVISIBLE, View.INVISIBLE); updateStartImage(); break; case SCREEN_WINDOW_FULLSCREEN: setAllControlsVisiblity(View.VISIBLE, View.INVISIBLE, View.VISIBLE, View.INVISIBLE, View.VISIBLE, View.INVISIBLE, View.INVISIBLE); updateStartImage(); break; case SCREEN_WINDOW_TINY: break; } } public void changeUiToError() { switch (currentScreen) { case SCREEN_WINDOW_NORMAL: case SCREEN_WINDOW_LIST: setAllControlsVisiblity(View.INVISIBLE, View.INVISIBLE, View.VISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.VISIBLE); updateStartImage(); break; case SCREEN_WINDOW_FULLSCREEN: setAllControlsVisiblity(View.INVISIBLE, View.INVISIBLE, View.VISIBLE, View.INVISIBLE, View.INVISIBLE, View.INVISIBLE, View.VISIBLE); updateStartImage(); break; case SCREEN_WINDOW_TINY: break; } } public void setAllControlsVisiblity(int topCon, int bottomCon, int startBtn, int loadingPro, int thumbImg, int bottomPro, int retryLayout) { topContainer.setVisibility(topCon); bottomContainer.setVisibility(bottomCon); startButton.setVisibility(startBtn); loadingProgressBar.setVisibility(loadingPro); thumbImageView.setVisibility(thumbImg); bottomProgressBar.setVisibility(bottomPro); mRetryLayout.setVisibility(retryLayout); } public void updateStartImage() { if (currentState == CURRENT_STATE_PLAYING) { startButton.setVisibility(VISIBLE); startButton.setImageResource(R.drawable.jz_click_pause_selector); replayTextView.setVisibility(INVISIBLE); } else if (currentState == CURRENT_STATE_ERROR) { startButton.setVisibility(INVISIBLE); replayTextView.setVisibility(INVISIBLE); } else if (currentState == CURRENT_STATE_AUTO_COMPLETE) { startButton.setVisibility(VISIBLE); startButton.setImageResource(R.drawable.jz_click_replay_selector); replayTextView.setVisibility(VISIBLE); } else { startButton.setImageResource(R.drawable.jz_click_play_selector); replayTextView.setVisibility(INVISIBLE); } } @Override public void showProgressDialog(float deltaX, String seekTime, long seekTimePosition, String totalTime, long totalTimeDuration) { super.showProgressDialog(deltaX, seekTime, seekTimePosition, totalTime, totalTimeDuration); if (mProgressDialog == null) { View localView = LayoutInflater.from(getContext()).inflate(R.layout.jz_dialog_progress, null); mDialogProgressBar = localView.findViewById(R.id.duration_progressbar); mDialogSeekTime = localView.findViewById(R.id.tv_current); mDialogTotalTime = localView.findViewById(R.id.tv_duration); mDialogIcon = localView.findViewById(R.id.duration_image_tip); mProgressDialog = createDialogWithView(localView); } if (!mProgressDialog.isShowing()) { mProgressDialog.show(); } mDialogSeekTime.setText(seekTime); mDialogTotalTime.setText(" / " + totalTime); mDialogProgressBar.setProgress(totalTimeDuration <= 0 ? 0 : (int) (seekTimePosition * 100 / totalTimeDuration)); if (deltaX > 0) { mDialogIcon.setBackgroundResource(R.drawable.jz_forward_icon); } else { mDialogIcon.setBackgroundResource(R.drawable.jz_backward_icon); } onCLickUiToggleToClear(); } @Override public void dismissProgressDialog() { super.dismissProgressDialog(); if (mProgressDialog != null) { mProgressDialog.dismiss(); } } @Override public void showVolumeDialog(float deltaY, int volumePercent) { super.showVolumeDialog(deltaY, volumePercent); if (mVolumeDialog == null) { View localView = LayoutInflater.from(getContext()).inflate(R.layout.jz_dialog_volume, null); mDialogVolumeImageView = localView.findViewById(R.id.volume_image_tip); mDialogVolumeTextView = localView.findViewById(R.id.tv_volume); mDialogVolumeProgressBar = localView.findViewById(R.id.volume_progressbar); mVolumeDialog = createDialogWithView(localView); } if (!mVolumeDialog.isShowing()) { mVolumeDialog.show(); } if (volumePercent <= 0) { mDialogVolumeImageView.setBackgroundResource(R.drawable.jz_close_volume); } else { mDialogVolumeImageView.setBackgroundResource(R.drawable.jz_add_volume); } if (volumePercent > 100) { volumePercent = 100; } else if (volumePercent < 0) { volumePercent = 0; } mDialogVolumeTextView.setText(volumePercent + "%"); mDialogVolumeProgressBar.setProgress(volumePercent); onCLickUiToggleToClear(); } @Override public void dismissVolumeDialog() { super.dismissVolumeDialog(); if (mVolumeDialog != null) { mVolumeDialog.dismiss(); } } @Override public void showBrightnessDialog(int brightnessPercent) { super.showBrightnessDialog(brightnessPercent); if (mBrightnessDialog == null) { View localView = LayoutInflater.from(getContext()).inflate(R.layout.jz_dialog_brightness, null); mDialogBrightnessTextView = localView.findViewById(R.id.tv_brightness); mDialogBrightnessProgressBar = localView.findViewById(R.id.brightness_progressbar); mBrightnessDialog = createDialogWithView(localView); } if (!mBrightnessDialog.isShowing()) { mBrightnessDialog.show(); } if (brightnessPercent > 100) { brightnessPercent = 100; } else if (brightnessPercent < 0) { brightnessPercent = 0; } mDialogBrightnessTextView.setText(brightnessPercent + "%"); mDialogBrightnessProgressBar.setProgress(brightnessPercent); onCLickUiToggleToClear(); } @Override public void dismissBrightnessDialog() { super.dismissBrightnessDialog(); if (mBrightnessDialog != null) { mBrightnessDialog.dismiss(); } } public Dialog createDialogWithView(View localView) { Dialog dialog = new Dialog(getContext(), R.style.jz_style_dialog_progress); dialog.setContentView(localView); Window window = dialog.getWindow(); window.addFlags(Window.FEATURE_ACTION_BAR); window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); window.setLayout(-2, -2); WindowManager.LayoutParams localLayoutParams = window.getAttributes(); localLayoutParams.gravity = Gravity.CENTER; window.setAttributes(localLayoutParams); return dialog; } public void startDismissControlViewTimer() { cancelDismissControlViewTimer(); DISMISS_CONTROL_VIEW_TIMER = new Timer(); mDismissControlViewTimerTask = new DismissControlViewTimerTask(); DISMISS_CONTROL_VIEW_TIMER.schedule(mDismissControlViewTimerTask, 2500); } public void cancelDismissControlViewTimer() { if (DISMISS_CONTROL_VIEW_TIMER != null) { DISMISS_CONTROL_VIEW_TIMER.cancel(); } if (mDismissControlViewTimerTask != null) { mDismissControlViewTimerTask.cancel(); } } @Override public void onAutoCompletion() { super.onAutoCompletion(); cancelDismissControlViewTimer(); } @Override public void onCompletion() { super.onCompletion(); cancelDismissControlViewTimer(); if (clarityPopWindow != null) { clarityPopWindow.dismiss(); } } public void dissmissControlView() { if (currentState != CURRENT_STATE_NORMAL && currentState != CURRENT_STATE_ERROR && currentState != CURRENT_STATE_AUTO_COMPLETE) { if (getContext() != null && getContext() instanceof Activity) { ((Activity) getContext()).runOnUiThread(new Runnable() { @Override public void run() { bottomContainer.setVisibility(View.INVISIBLE); topContainer.setVisibility(View.INVISIBLE); startButton.setVisibility(View.INVISIBLE); if (clarityPopWindow != null) { clarityPopWindow.dismiss(); } if (currentScreen != SCREEN_WINDOW_TINY) { bottomProgressBar.setVisibility(View.VISIBLE); } } }); } } } public class DismissControlViewTimerTask extends TimerTask { @Override public void run() { dissmissControlView(); } } } ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/anim/quit_fullscreen.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/anim/start_fullscreen.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/drawable/jz_bottom_progress.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/drawable/jz_bottom_seek_progress.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/drawable/jz_bottom_seek_thumb.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/drawable/jz_click_back_selector.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/drawable/jz_click_back_tiny_selector.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/drawable/jz_click_pause_selector.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/drawable/jz_click_play_selector.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/drawable/jz_click_replay_selector.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/drawable/jz_click_share_selector.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/drawable/jz_dialog_progress.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/drawable/jz_dialog_progress_bg.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/drawable/jz_loading.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/drawable/jz_seek_thumb_normal.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/drawable/jz_seek_thumb_pressed.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/drawable/jz_volume_progress_bg.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/drawable/retry_bg.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/layout/jz_dialog_brightness.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/layout/jz_dialog_progress.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/layout/jz_dialog_volume.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/layout/jz_layout_clarity.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/layout/jz_layout_clarity_item.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/layout/jz_layout_standard.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/values/colors.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/values/dimens.xml ================================================ 45dp 62dp ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/values/ids.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/values/strings.xml ================================================ You are currently using the mobile network, the player will continue to consume traffic Resume Stop play No url Replay ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/values/styles.xml ================================================ ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/values-es/strings.xml ================================================ Estás conectado a una red móvil, el reproductor utilizará tus datos si continuas Reproducir Cancelar No hay vídeo Volver a ver ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/values-pt/strings.xml ================================================ Você está usando a rede móvel, você deseja mesmo ver o vídeo? Continuar Parar Sem vídeo Replay ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/values-tr/strings.xml ================================================ Şu anda mobil veriyi kullanıyorsunuz, yüksek veri kaybına yol açabilir Devam Et Durdur URL Bulunamadı Tekrar ================================================ FILE: librarys/jiaozivideoplayer/src/main/res/values-zh/strings.xml ================================================ 您当前正在使用移动网络,继续播放将消耗流量 继续播放 停止播放 播放地址无效 重播 ================================================ FILE: librarys/jiaozivideoplayer/src/test/java/cn/jzvd/ExampleUnitTest.java ================================================ package cn.jzvd; import org.junit.Test; import static org.junit.Assert.assertEquals; /** * To work on unit tests, switch the Test Artifact in the Build Variants view. */ public class ExampleUnitTest { @Test public void addition_isCorrect() throws Exception { assertEquals(4, 2 + 2); } } ================================================ FILE: librarys/xrecyclerview/.gitignore ================================================ /build *.iml .idea ================================================ FILE: librarys/xrecyclerview/build.gradle ================================================ apply plugin: 'com.android.library' android { compileSdkVersion 25 buildToolsVersion '26.0.2' defaultConfig { minSdkVersion 11 targetSdkVersion 25 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:25.0.1' compile 'com.android.support:recyclerview-v7:25.0.1' compile 'com.android.support:design:23.1.0' } ================================================ FILE: librarys/xrecyclerview/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /Users/jianghejie/Library/Android/sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: librarys/xrecyclerview/src/androidTest/java/com/jcodecraeer/xrecyclerview/ApplicationTest.java ================================================ package com.jcodecraeer.xrecyclerview; import android.app.Application; import android.test.ApplicationTestCase; /** * Testing Fundamentals */ public class ApplicationTest extends ApplicationTestCase { public ApplicationTest() { super(Application.class); } } ================================================ FILE: librarys/xrecyclerview/src/main/AndroidManifest.xml ================================================ ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/AppBarStateChangeListener.java ================================================ package com.jcodecraeer.xrecyclerview; import android.support.design.widget.AppBarLayout; /** * Created by jianghejie on 16/6/19. */ public abstract class AppBarStateChangeListener implements AppBarLayout.OnOffsetChangedListener { public enum State { EXPANDED, COLLAPSED, IDLE } private State mCurrentState = State.IDLE; @Override public final void onOffsetChanged(AppBarLayout appBarLayout, int i) { if (i == 0) { if (mCurrentState != State.EXPANDED) { onStateChanged(appBarLayout, State.EXPANDED); } mCurrentState = State.EXPANDED; } else if (Math.abs(i) >= appBarLayout.getTotalScrollRange()) { if (mCurrentState != State.COLLAPSED) { onStateChanged(appBarLayout, State.COLLAPSED); } mCurrentState = State.COLLAPSED; } else { if (mCurrentState != State.IDLE) { onStateChanged(appBarLayout, State.IDLE); } mCurrentState = State.IDLE; } } public abstract void onStateChanged(AppBarLayout appBarLayout, State state); } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/ArrowRefreshHeader.java ================================================ package com.jcodecraeer.xrecyclerview; import android.animation.ValueAnimator; import android.content.Context; import android.os.Handler; import android.util.AttributeSet; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.RotateAnimation; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; import com.jcodecraeer.xrecyclerview.progressindicator.AVLoadingIndicatorView; import java.util.Date; public class ArrowRefreshHeader extends LinearLayout implements BaseRefreshHeader { private LinearLayout mContainer; private ImageView mArrowImageView; private SimpleViewSwitcher mProgressBar; private TextView mStatusTextView; private int mState = STATE_NORMAL; private TextView mHeaderTimeView; private Animation mRotateUpAnim; private Animation mRotateDownAnim; private static final int ROTATE_ANIM_DURATION = 180; public int mMeasuredHeight; public ArrowRefreshHeader(Context context) { super(context); initView(); } /** * @param context * @param attrs */ public ArrowRefreshHeader(Context context, AttributeSet attrs) { super(context, attrs); initView(); } private void initView() { // 初始情况,设置下拉刷新view高度为0 mContainer = (LinearLayout) LayoutInflater.from(getContext()).inflate( R.layout.listview_header, null); LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); lp.setMargins(0, 0, 0, 0); this.setLayoutParams(lp); this.setPadding(0, 0, 0, 0); addView(mContainer, new LayoutParams(LayoutParams.MATCH_PARENT, 0)); setGravity(Gravity.BOTTOM); mArrowImageView = (ImageView)findViewById(R.id.listview_header_arrow); mStatusTextView = (TextView)findViewById(R.id.refresh_status_textview); //init the progress view mProgressBar = (SimpleViewSwitcher)findViewById(R.id.listview_header_progressbar); AVLoadingIndicatorView progressView = new AVLoadingIndicatorView(getContext()); progressView.setIndicatorColor(0xffB5B5B5); progressView.setIndicatorId(ProgressStyle.BallSpinFadeLoader); mProgressBar.setView(progressView); mRotateUpAnim = new RotateAnimation(0.0f, -180.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION); mRotateUpAnim.setFillAfter(true); mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION); mRotateDownAnim.setFillAfter(true); mHeaderTimeView = (TextView)findViewById(R.id.last_refresh_time); measure(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT); mMeasuredHeight = getMeasuredHeight(); } public void setProgressStyle(int style) { if(style == ProgressStyle.SysProgress){ mProgressBar.setView(new ProgressBar(getContext(), null, android.R.attr.progressBarStyle)); }else{ AVLoadingIndicatorView progressView = new AVLoadingIndicatorView(this.getContext()); progressView.setIndicatorColor(0xffB5B5B5); progressView.setIndicatorId(style); mProgressBar.setView(progressView); } } public void setArrowImageView(int resid){ mArrowImageView.setImageResource(resid); } public void setState(int state) { if (state == mState) return ; if (state == STATE_REFRESHING) { // 显示进度 mArrowImageView.clearAnimation(); mArrowImageView.setVisibility(View.INVISIBLE); mProgressBar.setVisibility(View.VISIBLE); smoothScrollTo(mMeasuredHeight); } else if(state == STATE_DONE) { mArrowImageView.setVisibility(View.INVISIBLE); mProgressBar.setVisibility(View.INVISIBLE); } else { // 显示箭头图片 mArrowImageView.setVisibility(View.VISIBLE); mProgressBar.setVisibility(View.INVISIBLE); } switch(state){ case STATE_NORMAL: if (mState == STATE_RELEASE_TO_REFRESH) { mArrowImageView.startAnimation(mRotateDownAnim); } if (mState == STATE_REFRESHING) { mArrowImageView.clearAnimation(); } mStatusTextView.setText(R.string.listview_header_hint_normal); break; case STATE_RELEASE_TO_REFRESH: if (mState != STATE_RELEASE_TO_REFRESH) { mArrowImageView.clearAnimation(); mArrowImageView.startAnimation(mRotateUpAnim); mStatusTextView.setText(R.string.listview_header_hint_release); } break; case STATE_REFRESHING: mStatusTextView.setText(R.string.refreshing); break; case STATE_DONE: mStatusTextView.setText(R.string.refresh_done); break; default: } mState = state; } public int getState() { return mState; } @Override public void refreshComplete(){ mHeaderTimeView.setText(friendlyTime(new Date())); setState(STATE_DONE); new Handler().postDelayed(new Runnable(){ public void run() { reset(); } }, 200); } public void setVisibleHeight(int height) { if (height < 0) height = 0; LayoutParams lp = (LayoutParams) mContainer .getLayoutParams(); lp.height = height; mContainer.setLayoutParams(lp); } public int getVisibleHeight() { LayoutParams lp = (LayoutParams) mContainer.getLayoutParams(); return lp.height; } @Override public void onMove(float delta) { if(getVisibleHeight() > 0 || delta > 0) { setVisibleHeight((int) delta + getVisibleHeight()); if (mState <= STATE_RELEASE_TO_REFRESH) { // 未处于刷新状态,更新箭头 if (getVisibleHeight() > mMeasuredHeight) { setState(STATE_RELEASE_TO_REFRESH); }else { setState(STATE_NORMAL); } } } } @Override public boolean releaseAction() { boolean isOnRefresh = false; int height = getVisibleHeight(); if (height == 0) // not visible. isOnRefresh = false; if(getVisibleHeight() > mMeasuredHeight && mState < STATE_REFRESHING){ setState(STATE_REFRESHING); isOnRefresh = true; } // refreshing and header isn't shown fully. do nothing. if (mState == STATE_REFRESHING && height <= mMeasuredHeight) { //return; } if (mState != STATE_REFRESHING) { smoothScrollTo(0); } if (mState == STATE_REFRESHING) { int destHeight = mMeasuredHeight; smoothScrollTo(destHeight); } return isOnRefresh; } public void reset() { smoothScrollTo(0); new Handler().postDelayed(new Runnable() { public void run() { setState(STATE_NORMAL); } }, 500); } private void smoothScrollTo(int destHeight) { ValueAnimator animator = ValueAnimator.ofInt(getVisibleHeight(), destHeight); animator.setDuration(300).start(); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { setVisibleHeight((int) animation.getAnimatedValue()); } }); animator.start(); } public static String friendlyTime(Date time) { //获取time距离当前的秒数 int ct = (int)((System.currentTimeMillis() - time.getTime())/1000); if(ct == 0) { return "刚刚"; } if(ct > 0 && ct < 60) { return ct + "秒前"; } if(ct >= 60 && ct < 3600) { return Math.max(ct / 60,1) + "分钟前"; } if(ct >= 3600 && ct < 86400) return ct / 3600 + "小时前"; if(ct >= 86400 && ct < 2592000){ //86400 * 30 int day = ct / 86400 ; return day + "天前"; } if(ct >= 2592000 && ct < 31104000) { //86400 * 30 return ct / 2592000 + "月前"; } return ct / 31104000 + "年前"; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/BaseRefreshHeader.java ================================================ package com.jcodecraeer.xrecyclerview; /** * Created by jianghejie on 15/11/22. */ interface BaseRefreshHeader { int STATE_NORMAL = 0; int STATE_RELEASE_TO_REFRESH = 1; int STATE_REFRESHING = 2; int STATE_DONE = 3; void onMove(float delta); boolean releaseAction(); void refreshComplete(); } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/CustomFooterViewCallBack.java ================================================ package com.jcodecraeer.xrecyclerview; import android.view.View; /** * 作者:林冠宏 *

* My GitHub : https://github.com/af913337456/ *

* My Blog : http://www.cnblogs.com/linguanh/ *

* on 2017/11/8. */ public interface CustomFooterViewCallBack { void onLoadingMore(View yourFooterView); void onLoadMoreComplete(View yourFooterView); void onSetNoMore(View yourFooterView,boolean noMore); } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/ItemTouchHelperAdapter.java ================================================ package com.jcodecraeer.xrecyclerview; import android.support.v7.widget.RecyclerView; /** * Created by jianghejie on 16/6/20. */ public interface ItemTouchHelperAdapter { /** * Called when an item has been dragged far enough to trigger a move. This is called every time * an item is shifted, and not at the end of a "drop" event.
*
* Implementations should call {@link RecyclerView.Adapter#notifyItemMoved(int, int)} after * adjusting the underlying data to reflect this move. * * @param fromPosition The start position of the moved item. * @param toPosition Then resolved position of the moved item. * * @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder) * @see RecyclerView.ViewHolder#getAdapterPosition() */ void onItemMove(int fromPosition, int toPosition); /** * Called when an item has been dismissed by a swipe.
*
* Implementations should call {@link RecyclerView.Adapter#notifyItemRemoved(int)} after * adjusting the underlying data to reflect this removal. * * @param position The position of the item dismissed. * * @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder) * @see RecyclerView.ViewHolder#getAdapterPosition() */ void onItemDismiss(int position); } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/JellyView.java ================================================ package com.jcodecraeer.xrecyclerview; /** * Created by jianghejie on 15/11/22. */ import android.annotation.TargetApi; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.os.Build; import android.util.AttributeSet; import android.util.Log; import android.view.View; public class JellyView extends View implements BaseRefreshHeader{ Path path; Paint paint; private int minimumHeight = 0; private int jellyHeight =0; public JellyView(Context context) { super(context); init(); } public JellyView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public JellyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } @SuppressWarnings("unused") @TargetApi(Build.VERSION_CODES.LOLLIPOP) public JellyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(); } private void init() { if (isInEditMode()) { return; } path = new Path(); paint = new Paint(); paint.setColor(getContext().getResources().getColor(android.R.color.holo_blue_bright)); paint.setAntiAlias(true); } public void setJellyColor(int jellyColor) { paint.setColor(jellyColor); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); path.reset(); path.lineTo(0, minimumHeight); path.quadTo(getMeasuredWidth() / 2, minimumHeight + jellyHeight, getMeasuredWidth(), minimumHeight); path.lineTo(getMeasuredWidth(), 0); canvas.drawPath(path, paint); } @Override public void setMinimumHeight(int minimumHeight) { this.minimumHeight = minimumHeight; } public void setJellyHeight(int ribbonHeight) { this.jellyHeight = ribbonHeight; } @Override public int getMinimumHeight() { return minimumHeight; } public int getJellyHeight() { return jellyHeight; } @Override public void refreshComplete(){ } @Override public void onMove(float delta) { jellyHeight = jellyHeight + (int)delta; Log.i("jellyHeight", "delta = " + delta); this.invalidate(); } @Override public boolean releaseAction() { return false; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/LoadingMoreFooter.java ================================================ package com.jcodecraeer.xrecyclerview; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; import com.jcodecraeer.xrecyclerview.progressindicator.AVLoadingIndicatorView; public class LoadingMoreFooter extends LinearLayout { private SimpleViewSwitcher progressCon; public final static int STATE_LOADING = 0; public final static int STATE_COMPLETE = 1; public final static int STATE_NOMORE = 2; private TextView mText; private String loadingHint; private String noMoreHint; private String loadingDoneHint; public LoadingMoreFooter(Context context) { super(context); initView(); } /** * @param context * @param attrs */ public LoadingMoreFooter(Context context, AttributeSet attrs) { super(context, attrs); initView(); } public void setLoadingHint(String hint) { loadingHint = hint; } public void setNoMoreHint(String hint) { noMoreHint = hint; } public void setLoadingDoneHint(String hint) { loadingDoneHint = hint; } public void initView(){ setGravity(Gravity.CENTER); setLayoutParams(new RecyclerView.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); progressCon = new SimpleViewSwitcher(getContext()); progressCon.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); AVLoadingIndicatorView progressView = new AVLoadingIndicatorView(this.getContext()); progressView.setIndicatorColor(0xffB5B5B5); progressView.setIndicatorId(ProgressStyle.BallSpinFadeLoader); progressCon.setView(progressView); addView(progressCon); mText = new TextView(getContext()); mText.setText(getContext().getString(R.string.listview_loading)); if(loadingHint == null || loadingHint.equals("")){ loadingHint = (String)getContext().getText(R.string.listview_loading); } if(noMoreHint == null || noMoreHint.equals("")){ noMoreHint = (String)getContext().getText(R.string.nomore_loading); } if(loadingDoneHint == null || loadingDoneHint.equals("")){ loadingDoneHint = (String)getContext().getText(R.string.loading_done); } LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); layoutParams.setMargins( (int)getResources().getDimension(R.dimen.textandiconmargin),0,0,0 ); mText.setLayoutParams(layoutParams); addView(mText); } public void setProgressStyle(int style) { if(style == ProgressStyle.SysProgress){ progressCon.setView(new ProgressBar(getContext(), null, android.R.attr.progressBarStyle)); }else{ AVLoadingIndicatorView progressView = new AVLoadingIndicatorView(this.getContext()); progressView.setIndicatorColor(0xffB5B5B5); progressView.setIndicatorId(style); progressCon.setView(progressView); } } public void setState(int state) { switch(state) { case STATE_LOADING: progressCon.setVisibility(View.VISIBLE); mText.setText(loadingHint); this.setVisibility(View.VISIBLE); break; case STATE_COMPLETE: mText.setText(loadingDoneHint); this.setVisibility(View.GONE); break; case STATE_NOMORE: mText.setText(noMoreHint); progressCon.setVisibility(View.GONE); this.setVisibility(View.VISIBLE); break; } } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/ProgressStyle.java ================================================ package com.jcodecraeer.xrecyclerview; /** * Created by jianghejie on 15/11/23. */ public class ProgressStyle { public static final int SysProgress=-1; public static final int BallPulse=0; public static final int BallGridPulse=1; public static final int BallClipRotate=2; public static final int BallClipRotatePulse=3; public static final int SquareSpin=4; public static final int BallClipRotateMultiple=5; public static final int BallPulseRise=6; public static final int BallRotate=7; public static final int CubeTransition=8; public static final int BallZigZag=9; public static final int BallZigZagDeflect=10; public static final int BallTrianglePath=11; public static final int BallScale=12; public static final int LineScale=13; public static final int LineScaleParty=14; public static final int BallScaleMultiple=15; public static final int BallPulseSync=16; public static final int BallBeat=17; public static final int LineScalePulseOut=18; public static final int LineScalePulseOutRapid=19; public static final int BallScaleRipple=20; public static final int BallScaleRippleMultiple=21; public static final int BallSpinFadeLoader=22; public static final int LineSpinFadeLoader=23; public static final int TriangleSkewSpin=24; public static final int Pacman=25; public static final int BallGridBeat=26; public static final int SemiCircleSpin=27; } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/SimpleItemTouchHelperCallback.java ================================================ package com.jcodecraeer.xrecyclerview; import android.graphics.Canvas; import android.graphics.Color; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.helper.ItemTouchHelper; import android.view.View; /** * Created by jianghejie on 16/6/20. */ public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback { public static final float ALPHA_FULL = 1.0f; private final ItemTouchHelperAdapter mAdapter; private XRecyclerView mXrecyclerView; public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter, XRecyclerView recyclerView) { mAdapter = adapter; this.mXrecyclerView = recyclerView; } @Override public boolean isLongPressDragEnabled() { return true; } @Override public boolean isItemViewSwipeEnabled() { return true; } @Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { // Enable drag and swipe in both directions final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; return makeMovementFlags(dragFlags, swipeFlags); } @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) { if (source.getItemViewType() != target.getItemViewType()) { return false; } // Notify the adapter of the move mAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition()); return true; } @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int i) { // Notify the adapter of the dismissal mAdapter.onItemDismiss(viewHolder.getAdapterPosition()); } @Override public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); // Fade out the view as it is swiped out of the parent's bounds if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { View itemView = viewHolder.itemView; final float alpha = ALPHA_FULL - Math.abs(dX) / (float) itemView.getWidth(); itemView.setAlpha(alpha); } } @Override public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) { // Let the view holder know that this item is being moved or dragged viewHolder.itemView.setBackgroundColor(Color.LTGRAY); } super.onSelectedChanged(viewHolder, actionState); } @Override public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { super.clearView(recyclerView, viewHolder); viewHolder.itemView.setAlpha(ALPHA_FULL); viewHolder.itemView.setBackgroundColor(0); } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/SimpleViewSwitcher.java ================================================ package com.jcodecraeer.xrecyclerview; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; /** * Created by jianghejie on 15/11/22. */ public class SimpleViewSwitcher extends ViewGroup { public SimpleViewSwitcher(Context context) { super(context); } public SimpleViewSwitcher(Context context, AttributeSet attrs) { this(context, attrs, 0); } public SimpleViewSwitcher(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int childCount = this.getChildCount(); int maxHeight = 0; int maxWidth = 0; for (int i = 0; i < childCount; i++) { View child = this.getChildAt(i); this.measureChild(child, widthMeasureSpec, heightMeasureSpec); int cw = child.getMeasuredWidth(); // int ch = child.getMeasuredHeight(); maxWidth = child.getMeasuredWidth(); maxHeight = child.getMeasuredHeight(); } setMeasuredDimension(maxWidth, maxHeight); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != View.GONE) { child.layout(0, 0, r - l, b - t); } } } public void setView(View view) { if (this.getChildCount() != 0){ this.removeViewAt(0); } this.addView(view,0); } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/XRecyclerView.java ================================================ package com.jcodecraeer.xrecyclerview; import android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.support.design.widget.AppBarLayout; import android.support.design.widget.CoordinatorLayout; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGridLayoutManager; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; import java.util.ArrayList; import java.util.List; public class XRecyclerView extends RecyclerView { private boolean isLoadingData = false; private boolean isNoMore = false; private int mRefreshProgressStyle = ProgressStyle.SysProgress; private int mLoadingMoreProgressStyle = ProgressStyle.SysProgress; private ArrayList mHeaderViews = new ArrayList<>(); private WrapAdapter mWrapAdapter; private float mLastY = -1; private static final float DRAG_RATE = 3; private CustomFooterViewCallBack footerViewCallBack; private LoadingListener mLoadingListener; private ArrowRefreshHeader mRefreshHeader; private boolean pullRefreshEnabled = true; private boolean loadingMoreEnabled = true; //下面的ItemViewType是保留值(ReservedItemViewType),如果用户的adapter与它们重复将会强制抛出异常。不过为了简化,我们检测到重复时对用户的提示是ItemViewType必须小于10000 private static final int TYPE_REFRESH_HEADER = 10000;//设置一个很大的数字,尽可能避免和用户的adapter冲突 private static final int TYPE_FOOTER = 10001; private static final int HEADER_INIT_INDEX = 10002; private static List sHeaderTypes = new ArrayList<>();//每个header必须有不同的type,不然滚动的时候顺序会变化 private int mPageCount = 0; //adapter没有数据的时候显示,类似于listView的emptyView private View mEmptyView; private View mFootView; private final RecyclerView.AdapterDataObserver mDataObserver = new DataObserver(); private AppBarStateChangeListener.State appbarState = AppBarStateChangeListener.State.EXPANDED; // limit number to call load more // 控制多出多少条的时候调用 onLoadMore private int limitNumberToCallLoadMore = 1; public XRecyclerView(Context context) { this(context, null); } public XRecyclerView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public XRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { if (pullRefreshEnabled) { mRefreshHeader = new ArrowRefreshHeader(getContext()); mRefreshHeader.setProgressStyle(mRefreshProgressStyle); } LoadingMoreFooter footView = new LoadingMoreFooter(getContext()); footView.setProgressStyle(mLoadingMoreProgressStyle); mFootView = footView; mFootView.setVisibility(GONE); } public LoadingMoreFooter getDefaultFootView(){ if(mFootView == null){ return null; } if(mFootView instanceof LoadingMoreFooter){ return ((LoadingMoreFooter) mFootView); } return null; } // set the number to control call load more,see the demo on linearActivity public void setLimitNumberToCallLoadMore(int limitNumberToCallLoadMore) { this.limitNumberToCallLoadMore = limitNumberToCallLoadMore; } public View getFootView(){ return mFootView; } public void setFootViewText(String loading, String noMore) { if(mFootView instanceof LoadingMoreFooter){ ((LoadingMoreFooter) mFootView).setLoadingHint(loading); ((LoadingMoreFooter) mFootView).setNoMoreHint(noMore); } } public void addHeaderView(View view) { sHeaderTypes.add(HEADER_INIT_INDEX + mHeaderViews.size()); mHeaderViews.add(view); if (mWrapAdapter != null) { mWrapAdapter.notifyDataSetChanged(); } } //根据header的ViewType判断是哪个header private View getHeaderViewByType(int itemType) { if(!isHeaderType(itemType)) { return null; } return mHeaderViews.get(itemType - HEADER_INIT_INDEX); } //判断一个type是否为HeaderType private boolean isHeaderType(int itemViewType) { return mHeaderViews.size() > 0 && sHeaderTypes.contains(itemViewType); } //判断是否是XRecyclerView保留的itemViewType private boolean isReservedItemViewType(int itemViewType) { if(itemViewType == TYPE_REFRESH_HEADER || itemViewType == TYPE_FOOTER || sHeaderTypes.contains(itemViewType)) { return true; } else { return false; } } @SuppressWarnings("all") public void setFootView(@NonNull final View view,@NonNull CustomFooterViewCallBack footerViewCallBack) { if(view == null || footerViewCallBack == null){ return; } mFootView = view; this.footerViewCallBack = footerViewCallBack; } public void loadMoreComplete() { isLoadingData = false; if (mFootView instanceof LoadingMoreFooter) { ((LoadingMoreFooter) mFootView).setState(LoadingMoreFooter.STATE_COMPLETE); } else { if(footerViewCallBack != null){ footerViewCallBack.onLoadMoreComplete(mFootView); } } } public void setNoMore(boolean noMore){ isLoadingData = false; isNoMore = noMore; if (mFootView instanceof LoadingMoreFooter) { ((LoadingMoreFooter) mFootView).setState(isNoMore ? LoadingMoreFooter.STATE_NOMORE:LoadingMoreFooter.STATE_COMPLETE); } else { if(footerViewCallBack != null){ footerViewCallBack.onSetNoMore(mFootView,noMore); } } } public void refresh() { if (pullRefreshEnabled && mLoadingListener != null) { mRefreshHeader.setState(ArrowRefreshHeader.STATE_REFRESHING); mLoadingListener.onRefresh(); } } public void reset(){ setNoMore(false); loadMoreComplete(); refreshComplete(); } public void refreshComplete() { mRefreshHeader.refreshComplete(); setNoMore(false); } public void setRefreshHeader(ArrowRefreshHeader refreshHeader) { mRefreshHeader = refreshHeader; } public void setPullRefreshEnabled(boolean enabled) { pullRefreshEnabled = enabled; } public void setLoadingMoreEnabled(boolean enabled) { loadingMoreEnabled = enabled; if (!enabled) { if (mFootView instanceof LoadingMoreFooter) { ((LoadingMoreFooter)mFootView).setState(LoadingMoreFooter.STATE_COMPLETE); } } } public void setRefreshProgressStyle(int style) { mRefreshProgressStyle = style; if (mRefreshHeader != null) { mRefreshHeader.setProgressStyle(style); } } public void setLoadingMoreProgressStyle(int style) { mLoadingMoreProgressStyle = style; if (mFootView instanceof LoadingMoreFooter) { ((LoadingMoreFooter) mFootView).setProgressStyle(style); } } public void setArrowImageView(int resId) { if (mRefreshHeader != null) { mRefreshHeader.setArrowImageView(resId); } } public void setEmptyView(View emptyView) { this.mEmptyView = emptyView; mDataObserver.onChanged(); } public View getEmptyView() { return mEmptyView; } @Override public void setAdapter(Adapter adapter) { mWrapAdapter = new WrapAdapter(adapter); super.setAdapter(mWrapAdapter); adapter.registerAdapterDataObserver(mDataObserver); mDataObserver.onChanged(); } //避免用户自己调用getAdapter() 引起的ClassCastException @Override public Adapter getAdapter() { if(mWrapAdapter != null) return mWrapAdapter.getOriginalAdapter(); else return null; } @Override public void setLayoutManager(LayoutManager layout) { super.setLayoutManager(layout); if(mWrapAdapter != null){ if (layout instanceof GridLayoutManager) { final GridLayoutManager gridManager = ((GridLayoutManager) layout); gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { return (mWrapAdapter.isHeader(position) || mWrapAdapter.isFooter(position) || mWrapAdapter.isRefreshHeader(position)) ? gridManager.getSpanCount() : 1; } }); } } } /** ===================== try to adjust the position for XR when you call those functions below ====================== */ // which cause "Called attach on a child which is not detached" exception info. // {reason analyze @link:http://www.cnblogs.com/linguanh/p/5348510.html} // by lgh on 2017-11-13 23:55 // example: listData.remove(position); You can also see a demo on LinearActivity public void notifyItemRemoved(List listData,int position) { if(mWrapAdapter.adapter == null) return; int adjPos = position + getHeaders_includingRefreshCount(); mWrapAdapter.adapter.notifyItemRemoved(adjPos); if(adjPos != listData.size()){ // call this just for the reset the position for the list data mWrapAdapter.adapter.notifyItemRangeChanged(adjPos, listData.size() - adjPos,new Object()); } } public void notifyItemInserted(int position) { if(mWrapAdapter.adapter == null) return; int adjPos = position + getHeaders_includingRefreshCount(); mWrapAdapter.adapter.notifyItemInserted(adjPos); } public void notifyItemChanged(int position) { if(mWrapAdapter.adapter == null) return; int adjPos = position + getHeaders_includingRefreshCount(); mWrapAdapter.adapter.notifyItemChanged(adjPos); } public void notifyItemChanged(int position,Object o) { if(mWrapAdapter.adapter == null) return; int adjPos = position + getHeaders_includingRefreshCount(); mWrapAdapter.adapter.notifyItemChanged(adjPos,o); } private int getHeaders_includingRefreshCount(){ return mWrapAdapter.getHeadersCount()+1; } /** ======================================================= end ======================================================= */ @Override public void onScrollStateChanged(int state) { super.onScrollStateChanged(state); if (state == RecyclerView.SCROLL_STATE_IDLE && mLoadingListener != null && !isLoadingData && loadingMoreEnabled) { LayoutManager layoutManager = getLayoutManager(); int lastVisibleItemPosition; if (layoutManager instanceof GridLayoutManager) { lastVisibleItemPosition = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition(); } else if (layoutManager instanceof StaggeredGridLayoutManager) { int[] into = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()]; ((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(into); lastVisibleItemPosition = findMax(into); } else { lastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition(); } int adjAdapterItemCount = layoutManager.getItemCount()+getHeaders_includingRefreshCount(); if ( layoutManager.getChildCount() > 0 && lastVisibleItemPosition >= adjAdapterItemCount - limitNumberToCallLoadMore && adjAdapterItemCount >= layoutManager.getChildCount() && !isNoMore && mRefreshHeader.getState() < ArrowRefreshHeader.STATE_REFRESHING ) { isLoadingData = true; if (mFootView instanceof LoadingMoreFooter) { ((LoadingMoreFooter) mFootView).setState(LoadingMoreFooter.STATE_LOADING); } else { if(footerViewCallBack != null){ footerViewCallBack.onLoadingMore(mFootView); } } mLoadingListener.onLoadMore(); } } } @Override public boolean onTouchEvent(MotionEvent ev) { if (mLastY == -1) { mLastY = ev.getRawY(); } switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mLastY = ev.getRawY(); break; case MotionEvent.ACTION_MOVE: final float deltaY = ev.getRawY() - mLastY; mLastY = ev.getRawY(); if (isOnTop() && pullRefreshEnabled && appbarState == AppBarStateChangeListener.State.EXPANDED) { mRefreshHeader.onMove(deltaY / DRAG_RATE); if (mRefreshHeader.getVisibleHeight() > 0 && mRefreshHeader.getState() < ArrowRefreshHeader.STATE_REFRESHING) { return false; } } break; default: mLastY = -1; // reset if (isOnTop() && pullRefreshEnabled && appbarState == AppBarStateChangeListener.State.EXPANDED) { if (mRefreshHeader.releaseAction()) { if (mLoadingListener != null) { mLoadingListener.onRefresh(); } } } break; } return super.onTouchEvent(ev); } private int findMax(int[] lastPositions) { int max = lastPositions[0]; for (int value : lastPositions) { if (value > max) { max = value; } } return max; } private boolean isOnTop() { if (mRefreshHeader.getParent() != null) { return true; } else { return false; } } private class DataObserver extends RecyclerView.AdapterDataObserver { @Override public void onChanged() { if (mWrapAdapter != null) { mWrapAdapter.notifyDataSetChanged(); } if (mWrapAdapter != null && mEmptyView != null) { int emptyCount = 1 + mWrapAdapter.getHeadersCount(); if (loadingMoreEnabled) { emptyCount++; } if (mWrapAdapter.getItemCount() == emptyCount) { mEmptyView.setVisibility(View.VISIBLE); XRecyclerView.this.setVisibility(View.GONE); } else { mEmptyView.setVisibility(View.GONE); XRecyclerView.this.setVisibility(View.VISIBLE); } } } @Override public void onItemRangeInserted(int positionStart, int itemCount) { mWrapAdapter.notifyItemRangeInserted(positionStart, itemCount); } @Override public void onItemRangeChanged(int positionStart, int itemCount) { mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount); } @Override public void onItemRangeChanged(int positionStart, int itemCount, Object payload) { mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount, payload); } @Override public void onItemRangeRemoved(int positionStart, int itemCount) { mWrapAdapter.notifyItemRangeRemoved(positionStart, itemCount); } @Override public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { mWrapAdapter.notifyItemMoved(fromPosition, toPosition); } }; private class WrapAdapter extends RecyclerView.Adapter { private RecyclerView.Adapter adapter; public WrapAdapter(RecyclerView.Adapter adapter) { this.adapter = adapter; } public RecyclerView.Adapter getOriginalAdapter(){ return this.adapter; } public boolean isHeader(int position) { return position >= 1 && position < mHeaderViews.size() + 1; } public boolean isFooter(int position) { if(loadingMoreEnabled) { return position == getItemCount() - 1; }else { return false; } } public boolean isRefreshHeader(int position) { return position == 0; } public int getHeadersCount() { return mHeaderViews.size(); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == TYPE_REFRESH_HEADER) { return new SimpleViewHolder(mRefreshHeader); } else if (isHeaderType(viewType)) { return new SimpleViewHolder(getHeaderViewByType(viewType)); } else if (viewType == TYPE_FOOTER) { return new SimpleViewHolder(mFootView); } return adapter.onCreateViewHolder(parent, viewType); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (isHeader(position) || isRefreshHeader(position)) { return; } int adjPosition = position - (getHeadersCount() + 1); int adapterCount; if (adapter != null) { adapterCount = adapter.getItemCount(); if (adjPosition < adapterCount) { adapter.onBindViewHolder(holder, adjPosition); } } } // some times we need to override this @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position,List payloads) { if (isHeader(position) || isRefreshHeader(position)) { return; } int adjPosition = position - (getHeadersCount() + 1); int adapterCount; if (adapter != null) { adapterCount = adapter.getItemCount(); if (adjPosition < adapterCount) { if(payloads.isEmpty()){ adapter.onBindViewHolder(holder, adjPosition); } else{ adapter.onBindViewHolder(holder, adjPosition,payloads); } } } } @Override public int getItemCount() { int adjLen = (loadingMoreEnabled?2:1); if (adapter != null) { return getHeadersCount() + adapter.getItemCount() + adjLen; } else { return getHeadersCount() + adjLen; } } @Override public int getItemViewType(int position) { int adjPosition = position - (getHeadersCount() + 1); if (isRefreshHeader(position)) { return TYPE_REFRESH_HEADER; } if (isHeader(position)) { position = position - 1; return sHeaderTypes.get(position); } if (isFooter(position)) { return TYPE_FOOTER; } int adapterCount; if (adapter != null) { adapterCount = adapter.getItemCount(); if (adjPosition < adapterCount) { int type = adapter.getItemViewType(adjPosition); if(isReservedItemViewType(type)) { throw new IllegalStateException("XRecyclerView require itemViewType in adapter should be less than 10000 " ); } return type; } } return 0; } @Override public long getItemId(int position) { if (adapter != null && position >= getHeadersCount() + 1) { int adjPosition = position - (getHeadersCount() + 1); if (adjPosition < adapter.getItemCount()) { return adapter.getItemId(adjPosition); } } return -1; } @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); RecyclerView.LayoutManager manager = recyclerView.getLayoutManager(); if (manager instanceof GridLayoutManager) { final GridLayoutManager gridManager = ((GridLayoutManager) manager); gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { return (isHeader(position) || isFooter(position) || isRefreshHeader(position)) ? gridManager.getSpanCount() : 1; } }); } adapter.onAttachedToRecyclerView(recyclerView); } @Override public void onDetachedFromRecyclerView(RecyclerView recyclerView) { adapter.onDetachedFromRecyclerView(recyclerView); } @Override public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { super.onViewAttachedToWindow(holder); ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); if (lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams && (isHeader(holder.getLayoutPosition()) ||isRefreshHeader(holder.getLayoutPosition()) || isFooter(holder.getLayoutPosition()))) { StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp; p.setFullSpan(true); } adapter.onViewAttachedToWindow(holder); } @Override public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) { adapter.onViewDetachedFromWindow(holder); } @Override public void onViewRecycled(RecyclerView.ViewHolder holder) { adapter.onViewRecycled(holder); } @Override public boolean onFailedToRecycleView(RecyclerView.ViewHolder holder) { return adapter.onFailedToRecycleView(holder); } @Override public void unregisterAdapterDataObserver(AdapterDataObserver observer) { adapter.unregisterAdapterDataObserver(observer); } @Override public void registerAdapterDataObserver(AdapterDataObserver observer) { adapter.registerAdapterDataObserver(observer); } private class SimpleViewHolder extends RecyclerView.ViewHolder { public SimpleViewHolder(View itemView) { super(itemView); } } } public void setLoadingListener(LoadingListener listener) { mLoadingListener = listener; } public interface LoadingListener { void onRefresh(); void onLoadMore(); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); //解决和CollapsingToolbarLayout冲突的问题 AppBarLayout appBarLayout = null; ViewParent p = getParent(); while (p != null) { if (p instanceof CoordinatorLayout) { break; } p = p.getParent(); } if(p instanceof CoordinatorLayout) { CoordinatorLayout coordinatorLayout = (CoordinatorLayout)p; final int childCount = coordinatorLayout.getChildCount(); for (int i = childCount - 1; i >= 0; i--) { final View child = coordinatorLayout.getChildAt(i); if(child instanceof AppBarLayout) { appBarLayout = (AppBarLayout)child; break; } } if(appBarLayout != null) { appBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() { @Override public void onStateChanged(AppBarLayout appBarLayout, State state) { appbarState = state; } }); } } } public class DividerItemDecoration extends RecyclerView.ItemDecoration { private Drawable mDivider; private int mOrientation; /** * Sole constructor. Takes in a {@link Drawable} to be used as the interior * divider. * * @param divider A divider {@code Drawable} to be drawn on the RecyclerView */ public DividerItemDecoration(Drawable divider) { mDivider = divider; } /** * Draws horizontal or vertical dividers onto the parent RecyclerView. * * @param canvas The {@link Canvas} onto which dividers will be drawn * @param parent The RecyclerView onto which dividers are being added * @param state The current RecyclerView.State of the RecyclerView */ @Override public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) { if (mOrientation == LinearLayoutManager.HORIZONTAL) { drawHorizontalDividers(canvas, parent); } else if (mOrientation == LinearLayoutManager.VERTICAL) { drawVerticalDividers(canvas, parent); } } /** * Determines the size and location of offsets between items in the parent * RecyclerView. * * @param outRect The {@link Rect} of offsets to be added around the child * view * @param view The child view to be decorated with an offset * @param parent The RecyclerView onto which dividers are being added * @param state The current RecyclerView.State of the RecyclerView */ @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); if (parent.getChildAdapterPosition(view) <= mWrapAdapter.getHeadersCount() + 1) { return; } mOrientation = ((LinearLayoutManager) parent.getLayoutManager()).getOrientation(); if (mOrientation == LinearLayoutManager.HORIZONTAL) { outRect.left = mDivider.getIntrinsicWidth(); } else if (mOrientation == LinearLayoutManager.VERTICAL) { outRect.top = mDivider.getIntrinsicHeight(); } } /** * Adds dividers to a RecyclerView with a LinearLayoutManager or its * subclass oriented horizontally. * * @param canvas The {@link Canvas} onto which horizontal dividers will be * drawn * @param parent The RecyclerView onto which horizontal dividers are being * added */ private void drawHorizontalDividers(Canvas canvas, RecyclerView parent) { int parentTop = parent.getPaddingTop(); int parentBottom = parent.getHeight() - parent.getPaddingBottom(); int childCount = parent.getChildCount(); for (int i = 0; i < childCount - 1; i++) { View child = parent.getChildAt(i); RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); int parentLeft = child.getRight() + params.rightMargin; int parentRight = parentLeft + mDivider.getIntrinsicWidth(); mDivider.setBounds(parentLeft, parentTop, parentRight, parentBottom); mDivider.draw(canvas); } } /** * Adds dividers to a RecyclerView with a LinearLayoutManager or its * subclass oriented vertically. * * @param canvas The {@link Canvas} onto which vertical dividers will be * drawn * @param parent The RecyclerView onto which vertical dividers are being * added */ private void drawVerticalDividers(Canvas canvas, RecyclerView parent) { int parentLeft = parent.getPaddingLeft(); int parentRight = parent.getWidth() - parent.getPaddingRight(); int childCount = parent.getChildCount(); for (int i = 0; i < childCount - 1; i++) { View child = parent.getChildAt(i); RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); int parentTop = child.getBottom() + params.bottomMargin; int parentBottom = parentTop + mDivider.getIntrinsicHeight(); mDivider.setBounds(parentLeft, parentTop, parentRight, parentBottom); mDivider.draw(canvas); } } } /** add by LinGuanHong below */ private int scrollDyCounter = 0; @Override public void scrollToPosition(int position) { super.scrollToPosition(position); /** if we scroll to position 0, the scrollDyCounter should be reset */ if(position == 0){ scrollDyCounter = 0; } } @Override public void onScrolled(int dx, int dy) { super.onScrolled(dx, dy); if(scrollAlphaChangeListener == null){ return; } int height = scrollAlphaChangeListener.setLimitHeight(); scrollDyCounter = scrollDyCounter + dy; if (scrollDyCounter <= 0) { scrollAlphaChangeListener.onAlphaChange(0); }else if(scrollDyCounter <= height && scrollDyCounter > 0){ float scale = (float) scrollDyCounter / height; /** 255/height = x/255 */ float alpha = (255 * scale); scrollAlphaChangeListener.onAlphaChange((int) alpha); }else { scrollAlphaChangeListener.onAlphaChange(255); } } private ScrollAlphaChangeListener scrollAlphaChangeListener; public void setScrollAlphaChangeListener( ScrollAlphaChangeListener scrollAlphaChangeListener ){ this.scrollAlphaChangeListener = scrollAlphaChangeListener; } public interface ScrollAlphaChangeListener{ void onAlphaChange(int alpha); /** you can handle the alpha insert it */ int setLimitHeight(); /** set a height for the begging of the alpha start to change */ } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/AVLoadingIndicatorView.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator; import android.annotation.TargetApi; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.os.Build; import android.support.annotation.IntDef; import android.util.AttributeSet; import android.view.View; import com.jcodecraeer.xrecyclerview.R; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallBeatIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallClipRotateIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallClipRotateMultipleIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallClipRotatePulseIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallGridBeatIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallGridPulseIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallPulseIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallPulseRiseIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallPulseSyncIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallRotateIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallScaleIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallScaleMultipleIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallScaleRippleIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallScaleRippleMultipleIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallSpinFadeLoaderIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallTrianglePathIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallZigZagDeflectIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallZigZagIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BaseIndicatorController; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.CubeTransitionIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.LineScaleIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.LineScalePartyIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.LineScalePulseOutIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.LineScalePulseOutRapidIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.LineSpinFadeLoaderIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.PacmanIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.SemiCircleSpinIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.SquareSpinIndicator; import com.jcodecraeer.xrecyclerview.progressindicator.indicator.TriangleSkewSpinIndicator; /** * Created by Jack on 2015/10/15 * .BallPulse, .BallGridPulse, .BallClipRotate, .BallClipRotatePulse, .SquareSpin, .BallClipRotateMultiple, .BallPulseRise, .BallRotate, .CubeTransition, .BallZigZag, .BallZigZagDeflect, .BallTrianglePath, .BallScale, .LineScale, .LineScaleParty, .BallScaleMultiple, .BallPulseSync, .BallBeat, .LineScalePulseOut, .LineScalePulseOutRapid, .BallScaleRipple, .BallScaleRippleMultiple, .BallSpinFadeLoader, .LineSpinFadeLoader, .TriangleSkewSpin, .Pacman, .BallGridBeat, .SemiCircleSpin * */ public class AVLoadingIndicatorView extends View{ //indicators public static final int BallPulse=0; public static final int BallGridPulse=1; public static final int BallClipRotate=2; public static final int BallClipRotatePulse=3; public static final int SquareSpin=4; public static final int BallClipRotateMultiple=5; public static final int BallPulseRise=6; public static final int BallRotate=7; public static final int CubeTransition=8; public static final int BallZigZag=9; public static final int BallZigZagDeflect=10; public static final int BallTrianglePath=11; public static final int BallScale=12; public static final int LineScale=13; public static final int LineScaleParty=14; public static final int BallScaleMultiple=15; public static final int BallPulseSync=16; public static final int BallBeat=17; public static final int LineScalePulseOut=18; public static final int LineScalePulseOutRapid=19; public static final int BallScaleRipple=20; public static final int BallScaleRippleMultiple=21; public static final int BallSpinFadeLoader=22; public static final int LineSpinFadeLoader=23; public static final int TriangleSkewSpin=24; public static final int Pacman=25; public static final int BallGridBeat=26; public static final int SemiCircleSpin=27; @IntDef(flag = true, value = { BallPulse, BallGridPulse, BallClipRotate, BallClipRotatePulse, SquareSpin, BallClipRotateMultiple, BallPulseRise, BallRotate, CubeTransition, BallZigZag, BallZigZagDeflect, BallTrianglePath, BallScale, LineScale, LineScaleParty, BallScaleMultiple, BallPulseSync, BallBeat, LineScalePulseOut, LineScalePulseOutRapid, BallScaleRipple, BallScaleRippleMultiple, BallSpinFadeLoader, LineSpinFadeLoader, TriangleSkewSpin, Pacman, BallGridBeat, SemiCircleSpin }) public @interface Indicator{} //Sizes (with defaults in DP) public static final int DEFAULT_SIZE=30; //attrs int mIndicatorId; int mIndicatorColor; Paint mPaint; BaseIndicatorController mIndicatorController; private boolean mHasAnimation; public AVLoadingIndicatorView(Context context) { super(context); init(null, 0); } public AVLoadingIndicatorView(Context context, AttributeSet attrs) { super(context, attrs); init(attrs, 0); } public AVLoadingIndicatorView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(attrs, defStyleAttr); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public AVLoadingIndicatorView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(attrs, defStyleAttr); } private void init(AttributeSet attrs, int defStyle) { TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.AVLoadingIndicatorView); mIndicatorId=a.getInt(R.styleable.AVLoadingIndicatorView_indicator, BallPulse); mIndicatorColor=a.getColor(R.styleable.AVLoadingIndicatorView_indicator_color, Color.WHITE); a.recycle(); mPaint=new Paint(); mPaint.setColor(mIndicatorColor); mPaint.setStyle(Paint.Style.FILL); mPaint.setAntiAlias(true); applyIndicator(); } public void setIndicatorId(int indicatorId){ mIndicatorId = indicatorId; applyIndicator(); } public void setIndicatorColor(int color){ mIndicatorColor = color; mPaint.setColor(mIndicatorColor); this.invalidate(); } private void applyIndicator(){ switch (mIndicatorId){ case BallPulse: mIndicatorController=new BallPulseIndicator(); break; case BallGridPulse: mIndicatorController=new BallGridPulseIndicator(); break; case BallClipRotate: mIndicatorController=new BallClipRotateIndicator(); break; case BallClipRotatePulse: mIndicatorController=new BallClipRotatePulseIndicator(); break; case SquareSpin: mIndicatorController=new SquareSpinIndicator(); break; case BallClipRotateMultiple: mIndicatorController=new BallClipRotateMultipleIndicator(); break; case BallPulseRise: mIndicatorController=new BallPulseRiseIndicator(); break; case BallRotate: mIndicatorController=new BallRotateIndicator(); break; case CubeTransition: mIndicatorController=new CubeTransitionIndicator(); break; case BallZigZag: mIndicatorController=new BallZigZagIndicator(); break; case BallZigZagDeflect: mIndicatorController=new BallZigZagDeflectIndicator(); break; case BallTrianglePath: mIndicatorController=new BallTrianglePathIndicator(); break; case BallScale: mIndicatorController=new BallScaleIndicator(); break; case LineScale: mIndicatorController=new LineScaleIndicator(); break; case LineScaleParty: mIndicatorController=new LineScalePartyIndicator(); break; case BallScaleMultiple: mIndicatorController=new BallScaleMultipleIndicator(); break; case BallPulseSync: mIndicatorController=new BallPulseSyncIndicator(); break; case BallBeat: mIndicatorController=new BallBeatIndicator(); break; case LineScalePulseOut: mIndicatorController=new LineScalePulseOutIndicator(); break; case LineScalePulseOutRapid: mIndicatorController=new LineScalePulseOutRapidIndicator(); break; case BallScaleRipple: mIndicatorController=new BallScaleRippleIndicator(); break; case BallScaleRippleMultiple: mIndicatorController=new BallScaleRippleMultipleIndicator(); break; case BallSpinFadeLoader: mIndicatorController=new BallSpinFadeLoaderIndicator(); break; case LineSpinFadeLoader: mIndicatorController=new LineSpinFadeLoaderIndicator(); break; case TriangleSkewSpin: mIndicatorController=new TriangleSkewSpinIndicator(); break; case Pacman: mIndicatorController=new PacmanIndicator(); break; case BallGridBeat: mIndicatorController=new BallGridBeatIndicator(); break; case SemiCircleSpin: mIndicatorController=new SemiCircleSpinIndicator(); break; } mIndicatorController.setTarget(this); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = measureDimension(dp2px(DEFAULT_SIZE), widthMeasureSpec); int height = measureDimension(dp2px(DEFAULT_SIZE), heightMeasureSpec); setMeasuredDimension(width, height); } private int measureDimension(int defaultSize,int measureSpec){ int result = defaultSize; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { result = specSize; } else if (specMode == MeasureSpec.AT_MOST) { result = Math.min(defaultSize, specSize); } else { result = defaultSize; } return result; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); drawIndicator(canvas); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if (!mHasAnimation){ mHasAnimation=true; applyAnimation(); } } @Override public void setVisibility(int v) { if (getVisibility() != v) { super.setVisibility(v); if (v == GONE || v == INVISIBLE) { mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.END); } else { mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.START); } } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.CANCEL); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.START); } void drawIndicator(Canvas canvas){ mIndicatorController.draw(canvas, mPaint); } void applyAnimation(){ mIndicatorController.initAnimation(); } private int dp2px(int dpValue) { return (int) getContext().getResources().getDisplayMetrics().density * dpValue; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/BallBeatIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/19. */ public class BallBeatIndicator extends com.jcodecraeer.xrecyclerview.progressindicator.indicator.BaseIndicatorController { public static final float SCALE=1.0f; public static final int ALPHA=255; private float[] scaleFloats=new float[]{SCALE, SCALE, SCALE}; int[] alphas=new int[]{ALPHA, ALPHA, ALPHA,}; @Override public void draw(Canvas canvas, Paint paint) { float circleSpacing=4; float radius=(getWidth()-circleSpacing*2)/6; float x = getWidth()/ 2-(radius*2+circleSpacing); float y=getHeight() / 2; for (int i = 0; i < 3; i++) { canvas.save(); float translateX=x+(radius*2)*i+circleSpacing*i; canvas.translate(translateX, y); canvas.scale(scaleFloats[i], scaleFloats[i]); paint.setAlpha(alphas[i]); canvas.drawCircle(0, 0, radius, paint); canvas.restore(); } } @Override public List createAnimation() { List animators=new ArrayList<>(); int[] delays=new int[]{350,0,350}; for (int i = 0; i < 3; i++) { final int index=i; ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.75f,1); scaleAnim.setDuration(700); scaleAnim.setRepeatCount(-1); scaleAnim.setStartDelay(delays[i]); scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { scaleFloats[index] = (float) animation.getAnimatedValue(); postInvalidate(); } }); scaleAnim.start(); ValueAnimator alphaAnim=ValueAnimator.ofInt(255,51,255); alphaAnim.setDuration(700); alphaAnim.setRepeatCount(-1); alphaAnim.setStartDelay(delays[i]); alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { alphas[index] = (int) animation.getAnimatedValue(); postInvalidate(); } }); alphaAnim.start(); animators.add(scaleAnim); animators.add(alphaAnim); } return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/BallClipRotateIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/16. */ public class BallClipRotateIndicator extends BaseIndicatorController { float scaleFloat=1,degrees; @Override public void draw(Canvas canvas, Paint paint) { paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(3); float circleSpacing=12; float x = (getWidth()) / 2; float y=(getHeight()) / 2; canvas.translate(x, y); canvas.scale(scaleFloat, scaleFloat); canvas.rotate(degrees); RectF rectF=new RectF(-x+circleSpacing,-y+circleSpacing,0+x-circleSpacing,0+y-circleSpacing); canvas.drawArc(rectF, -45, 270, false, paint); } @Override public List createAnimation() { List animators=new ArrayList<>(); ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.6f,0.5f,1); scaleAnim.setDuration(750); scaleAnim.setRepeatCount(-1); scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { scaleFloat = (float) animation.getAnimatedValue(); postInvalidate(); } }); scaleAnim.start(); ValueAnimator rotateAnim=ValueAnimator.ofFloat(0,180,360); rotateAnim.setDuration(750); rotateAnim.setRepeatCount(-1); rotateAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { degrees = (float) animation.getAnimatedValue(); postInvalidate(); } }); rotateAnim.start(); animators.add(scaleAnim); animators.add(rotateAnim); return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/BallClipRotateMultipleIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/17. */ public class BallClipRotateMultipleIndicator extends BaseIndicatorController{ float scaleFloat=1,degrees; @Override public void draw(Canvas canvas, Paint paint) { paint.setStrokeWidth(3); paint.setStyle(Paint.Style.STROKE); float circleSpacing=12; float x=getWidth()/2; float y=getHeight()/2; canvas.save(); canvas.translate(x, y); canvas.scale(scaleFloat, scaleFloat); canvas.rotate(degrees); //draw two big arc float[] bStartAngles=new float[]{135,-45}; for (int i = 0; i < 2; i++) { RectF rectF=new RectF(-x+circleSpacing,-y+circleSpacing,x-circleSpacing,y-circleSpacing); canvas.drawArc(rectF, bStartAngles[i], 90, false, paint); } canvas.restore(); canvas.translate(x, y); canvas.scale(scaleFloat, scaleFloat); canvas.rotate(-degrees); //draw two small arc float[] sStartAngles=new float[]{225,45}; for (int i = 0; i < 2; i++) { RectF rectF=new RectF(-x/1.8f+circleSpacing,-y/1.8f+circleSpacing,x/1.8f-circleSpacing,y/1.8f-circleSpacing); canvas.drawArc(rectF, sStartAngles[i], 90, false, paint); } } @Override public List createAnimation() { List animators=new ArrayList<>(); ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.6f,1); scaleAnim.setDuration(1000); scaleAnim.setRepeatCount(-1); scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { scaleFloat = (float) animation.getAnimatedValue(); postInvalidate(); } }); scaleAnim.start(); ValueAnimator rotateAnim=ValueAnimator.ofFloat(0, 180,360); rotateAnim.setDuration(1000); rotateAnim.setRepeatCount(-1); rotateAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { degrees = (float) animation.getAnimatedValue(); postInvalidate(); } }); rotateAnim.start(); animators.add(scaleAnim); animators.add(rotateAnim); return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/BallClipRotatePulseIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/16. */ public class BallClipRotatePulseIndicator extends BaseIndicatorController { float scaleFloat1,scaleFloat2,degrees; @Override public void draw(Canvas canvas, Paint paint) { float circleSpacing=12; float x=getWidth()/2; float y=getHeight()/2; //draw fill circle canvas.save(); canvas.translate(x, y); canvas.scale(scaleFloat1, scaleFloat1); paint.setStyle(Paint.Style.FILL); canvas.drawCircle(0, 0, x / 2.5f, paint); canvas.restore(); canvas.translate(x, y); canvas.scale(scaleFloat2, scaleFloat2); canvas.rotate(degrees); paint.setStrokeWidth(3); paint.setStyle(Paint.Style.STROKE); //draw two arc float[] startAngles=new float[]{225,45}; for (int i = 0; i < 2; i++) { RectF rectF=new RectF(-x+circleSpacing,-y+circleSpacing,x-circleSpacing,y-circleSpacing); canvas.drawArc(rectF, startAngles[i], 90, false, paint); } } @Override public List createAnimation() { ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.3f,1); scaleAnim.setDuration(1000); scaleAnim.setRepeatCount(-1); scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { scaleFloat1 = (float) animation.getAnimatedValue(); postInvalidate(); } }); scaleAnim.start(); ValueAnimator scaleAnim2=ValueAnimator.ofFloat(1,0.6f,1); scaleAnim2.setDuration(1000); scaleAnim2.setRepeatCount(-1); scaleAnim2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { scaleFloat2 = (float) animation.getAnimatedValue(); postInvalidate(); } }); scaleAnim2.start(); ValueAnimator rotateAnim=ValueAnimator.ofFloat(0, 180,360); rotateAnim.setDuration(1000); rotateAnim.setRepeatCount(-1); rotateAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { degrees = (float) animation.getAnimatedValue(); postInvalidate(); } }); rotateAnim.start(); List animators=new ArrayList<>(); animators.add(scaleAnim); animators.add(scaleAnim2); animators.add(rotateAnim); return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/BallGridBeatIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/20. */ public class BallGridBeatIndicator extends BaseIndicatorController { public static final int ALPHA=255; int[] alphas=new int[]{ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA}; @Override public void draw(Canvas canvas, Paint paint) { float circleSpacing=4; float radius=(getWidth()-circleSpacing*4)/6; float x = getWidth()/ 2-(radius*2+circleSpacing); float y = getWidth()/ 2-(radius*2+circleSpacing); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { canvas.save(); float translateX=x+(radius*2)*j+circleSpacing*j; float translateY=y+(radius*2)*i+circleSpacing*i; canvas.translate(translateX, translateY); paint.setAlpha(alphas[3 * i + j]); canvas.drawCircle(0, 0, radius, paint); canvas.restore(); } } } @Override public List createAnimation() { List animators=new ArrayList<>(); int[] durations={960, 930, 1190, 1130, 1340, 940, 1200, 820, 1190}; int[] delays= {360, 400, 680, 410, 710, -150, -120, 10, 320}; for (int i = 0; i < 9; i++) { final int index=i; ValueAnimator alphaAnim=ValueAnimator.ofInt(255, 168,255); alphaAnim.setDuration(durations[i]); alphaAnim.setRepeatCount(-1); alphaAnim.setStartDelay(delays[i]); alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { alphas[index] = (int) animation.getAnimatedValue(); postInvalidate(); } }); alphaAnim.start(); animators.add(alphaAnim); } return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/BallGridPulseIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/16. */ public class BallGridPulseIndicator extends BaseIndicatorController{ public static final int ALPHA=255; public static final float SCALE=1.0f; int[] alphas=new int[]{ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA}; float[] scaleFloats=new float[]{SCALE, SCALE, SCALE, SCALE, SCALE, SCALE, SCALE, SCALE, SCALE}; @Override public void draw(Canvas canvas, Paint paint) { float circleSpacing=4; float radius=(getWidth()-circleSpacing*4)/6; float x = getWidth()/ 2-(radius*2+circleSpacing); float y = getWidth()/ 2-(radius*2+circleSpacing); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { canvas.save(); float translateX=x+(radius*2)*j+circleSpacing*j; float translateY=y+(radius*2)*i+circleSpacing*i; canvas.translate(translateX, translateY); canvas.scale(scaleFloats[3 * i + j], scaleFloats[3 * i + j]); paint.setAlpha(alphas[3 * i + j]); canvas.drawCircle(0, 0, radius, paint); canvas.restore(); } } } @Override public List createAnimation() { List animators=new ArrayList<>(); int[] durations={720, 1020, 1280, 1420, 1450, 1180, 870, 1450, 1060}; int[] delays= {-60, 250, -170, 480, 310, 30, 460, 780, 450}; for (int i = 0; i < 9; i++) { final int index=i; ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.5f,1); scaleAnim.setDuration(durations[i]); scaleAnim.setRepeatCount(-1); scaleAnim.setStartDelay(delays[i]); scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { scaleFloats[index] = (float) animation.getAnimatedValue(); postInvalidate(); } }); scaleAnim.start(); ValueAnimator alphaAnim=ValueAnimator.ofInt(255, 210, 122, 255); alphaAnim.setDuration(durations[i]); alphaAnim.setRepeatCount(-1); alphaAnim.setStartDelay(delays[i]); alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { alphas[index] = (int) animation.getAnimatedValue(); postInvalidate(); } }); alphaAnim.start(); animators.add(scaleAnim); animators.add(alphaAnim); } return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/BallPulseIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/16. */ public class BallPulseIndicator extends BaseIndicatorController{ public static final float SCALE=1.0f; //scale x ,y private float[] scaleFloats=new float[]{SCALE, SCALE, SCALE}; @Override public void draw(Canvas canvas, Paint paint) { float circleSpacing=4; float radius=(Math.min(getWidth(),getHeight())-circleSpacing*2)/6; float x = getWidth()/ 2-(radius*2+circleSpacing); float y=getHeight() / 2; for (int i = 0; i < 3; i++) { canvas.save(); float translateX=x+(radius*2)*i+circleSpacing*i; canvas.translate(translateX, y); canvas.scale(scaleFloats[i], scaleFloats[i]); canvas.drawCircle(0, 0, radius, paint); canvas.restore(); } } @Override public List createAnimation() { List animators=new ArrayList<>(); int[] delays=new int[]{120,240,360}; for (int i = 0; i < 3; i++) { final int index=i; ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.3f,1); scaleAnim.setDuration(750); scaleAnim.setRepeatCount(-1); scaleAnim.setStartDelay(delays[i]); scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { scaleFloats[index] = (float) animation.getAnimatedValue(); postInvalidate(); } }); scaleAnim.start(); animators.add(scaleAnim); } return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/BallPulseRiseIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.graphics.Canvas; import android.graphics.Paint; import android.view.animation.LinearInterpolator; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/17. */ public class BallPulseRiseIndicator extends BaseIndicatorController{ @Override public void draw(Canvas canvas, Paint paint) { float radius=getWidth()/10; canvas.drawCircle(getWidth()/4,radius*2,radius,paint); canvas.drawCircle(getWidth()*3/4,radius*2,radius,paint); canvas.drawCircle(radius,getHeight()-2*radius,radius,paint); canvas.drawCircle(getWidth()/2,getHeight()-2*radius,radius,paint); canvas.drawCircle(getWidth()-radius,getHeight()-2*radius,radius,paint); } @Override public List createAnimation() { PropertyValuesHolder rotation6=PropertyValuesHolder.ofFloat("rotationX",0,360); ObjectAnimator animator=ObjectAnimator.ofPropertyValuesHolder(getTarget(), rotation6); animator.setInterpolator(new LinearInterpolator()); animator.setRepeatCount(-1); animator.setDuration(1500); animator.start(); List animators=new ArrayList<>(); animators.add(animator); return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/BallPulseSyncIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/19. */ public class BallPulseSyncIndicator extends BaseIndicatorController { float[] translateYFloats=new float[3]; @Override public void draw(Canvas canvas, Paint paint) { float circleSpacing=4; float radius=(getWidth()-circleSpacing*2)/6; float x = getWidth()/ 2-(radius*2+circleSpacing); for (int i = 0; i < 3; i++) { canvas.save(); float translateX=x+(radius*2)*i+circleSpacing*i; canvas.translate(translateX, translateYFloats[i]); canvas.drawCircle(0, 0, radius, paint); canvas.restore(); } } @Override public List createAnimation() { List animators=new ArrayList<>(); float circleSpacing=4; float radius=(getWidth()-circleSpacing*2)/6; int[] delays=new int[]{70,140,210}; for (int i = 0; i < 3; i++) { final int index=i; ValueAnimator scaleAnim=ValueAnimator.ofFloat(getHeight()/2,getHeight()/2-radius*2,getHeight()/2); scaleAnim.setDuration(600); scaleAnim.setRepeatCount(-1); scaleAnim.setStartDelay(delays[i]); scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { translateYFloats[index] = (float) animation.getAnimatedValue(); postInvalidate(); } }); scaleAnim.start(); animators.add(scaleAnim); } return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/BallRotateIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/17. */ public class BallRotateIndicator extends BaseIndicatorController{ float scaleFloat=0.5f; @Override public void draw(Canvas canvas, Paint paint) { float radius=getWidth()/10; float x = getWidth()/ 2; float y=getHeight()/2; canvas.save(); canvas.translate(x - radius * 2 - radius, y); canvas.scale(scaleFloat, scaleFloat); canvas.drawCircle(0, 0, radius, paint); canvas.restore(); canvas.save(); canvas.translate(x, y); canvas.scale(scaleFloat, scaleFloat); canvas.drawCircle(0, 0, radius, paint); canvas.restore(); canvas.save(); canvas.translate(x + radius * 2 + radius, y); canvas.scale(scaleFloat, scaleFloat); canvas.drawCircle(0,0,radius, paint); canvas.restore(); } @Override public List createAnimation() { List animators=new ArrayList<>(); ValueAnimator scaleAnim=ValueAnimator.ofFloat(0.5f,1,0.5f); scaleAnim.setDuration(1000); scaleAnim.setRepeatCount(-1); scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { scaleFloat = (float) animation.getAnimatedValue(); postInvalidate(); } }); scaleAnim.start(); ObjectAnimator rotateAnim=ObjectAnimator.ofFloat(getTarget(),"rotation",0,180,360); rotateAnim.setDuration(1000); rotateAnim.setRepeatCount(-1); rotateAnim.start(); animators.add(scaleAnim); animators.add(rotateAnim); return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/BallScaleIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; import android.view.animation.LinearInterpolator; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/19. */ public class BallScaleIndicator extends BaseIndicatorController { float scale=1; int alpha=255; @Override public void draw(Canvas canvas, Paint paint) { float circleSpacing=4; paint.setAlpha(alpha); canvas.scale(scale,scale,getWidth()/2,getHeight()/2); paint.setAlpha(alpha); canvas.drawCircle(getWidth()/2,getHeight()/2,getWidth()/2-circleSpacing,paint); } @Override public List createAnimation() { List animators=new ArrayList<>(); ValueAnimator scaleAnim=ValueAnimator.ofFloat(0,1); scaleAnim.setInterpolator(new LinearInterpolator()); scaleAnim.setDuration(1000); scaleAnim.setRepeatCount(-1); scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { scale = (float) animation.getAnimatedValue(); postInvalidate(); } }); scaleAnim.start(); ValueAnimator alphaAnim=ValueAnimator.ofInt(255, 0); alphaAnim.setInterpolator(new LinearInterpolator()); alphaAnim.setDuration(1000); alphaAnim.setRepeatCount(-1); alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { alpha = (int) animation.getAnimatedValue(); postInvalidate(); } }); alphaAnim.start(); animators.add(scaleAnim); animators.add(alphaAnim); return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/BallScaleMultipleIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; import android.view.animation.LinearInterpolator; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/19. */ public class BallScaleMultipleIndicator extends BaseIndicatorController { float[] scaleFloats=new float[]{1,1,1}; int[] alphaInts=new int[]{255,255,255}; @Override public void draw(Canvas canvas, Paint paint) { float circleSpacing=4; for (int i = 0; i < 3; i++) { paint.setAlpha(alphaInts[i]); canvas.scale(scaleFloats[i],scaleFloats[i],getWidth()/2,getHeight()/2); canvas.drawCircle(getWidth()/2,getHeight()/2,getWidth()/2-circleSpacing,paint); } } @Override public List createAnimation() { List animators=new ArrayList<>(); long[] delays=new long[]{0, 200, 400}; for (int i = 0; i < 3; i++) { final int index=i; ValueAnimator scaleAnim=ValueAnimator.ofFloat(0,1); scaleAnim.setInterpolator(new LinearInterpolator()); scaleAnim.setDuration(1000); scaleAnim.setRepeatCount(-1); scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { scaleFloats[index] = (float) animation.getAnimatedValue(); postInvalidate(); } }); scaleAnim.setStartDelay(delays[i]); scaleAnim.start(); ValueAnimator alphaAnim=ValueAnimator.ofInt(255,0); alphaAnim.setInterpolator(new LinearInterpolator()); alphaAnim.setDuration(1000); alphaAnim.setRepeatCount(-1); alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { alphaInts[index] = (int) animation.getAnimatedValue(); postInvalidate(); } }); scaleAnim.setStartDelay(delays[i]); alphaAnim.start(); animators.add(scaleAnim); animators.add(alphaAnim); } return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/BallScaleRippleIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; import android.view.animation.LinearInterpolator; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/19. */ public class BallScaleRippleIndicator extends BallScaleIndicator { @Override public void draw(Canvas canvas, Paint paint) { paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(3); super.draw(canvas, paint); } @Override public List createAnimation() { List animators=new ArrayList<>(); ValueAnimator scaleAnim=ValueAnimator.ofFloat(0,1); scaleAnim.setInterpolator(new LinearInterpolator()); scaleAnim.setDuration(1000); scaleAnim.setRepeatCount(-1); scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { scale = (float) animation.getAnimatedValue(); postInvalidate(); } }); scaleAnim.start(); ValueAnimator alphaAnim=ValueAnimator.ofInt(0, 255); alphaAnim.setInterpolator(new LinearInterpolator()); alphaAnim.setDuration(1000); alphaAnim.setRepeatCount(-1); alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { alpha = (int) animation.getAnimatedValue(); postInvalidate(); } }); alphaAnim.start(); animators.add(scaleAnim); animators.add(alphaAnim); return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/BallScaleRippleMultipleIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; import android.view.animation.LinearInterpolator; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/19. */ public class BallScaleRippleMultipleIndicator extends BallScaleMultipleIndicator{ @Override public void draw(Canvas canvas, Paint paint) { paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(3); super.draw(canvas, paint); } @Override public List createAnimation() { List animators=new ArrayList<>(); long[] delays=new long[]{0, 200, 400}; for (int i = 0; i < 3; i++) { final int index=i; ValueAnimator scaleAnim=ValueAnimator.ofFloat(0,1); scaleAnim.setInterpolator(new LinearInterpolator()); scaleAnim.setDuration(1000); scaleAnim.setRepeatCount(-1); scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { scaleFloats[index] = (float) animation.getAnimatedValue(); postInvalidate(); } }); scaleAnim.setStartDelay(delays[i]); scaleAnim.start(); ValueAnimator alphaAnim=ValueAnimator.ofInt(0,255); scaleAnim.setInterpolator(new LinearInterpolator()); alphaAnim.setDuration(1000); alphaAnim.setRepeatCount(-1); alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { alphaInts[index] = (int) animation.getAnimatedValue(); postInvalidate(); } }); scaleAnim.setStartDelay(delays[i]); alphaAnim.start(); animators.add(scaleAnim); animators.add(alphaAnim); } return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/BallSpinFadeLoaderIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/20. */ public class BallSpinFadeLoaderIndicator extends BaseIndicatorController { public static final float SCALE=1.0f; public static final int ALPHA=255; float[] scaleFloats=new float[]{SCALE, SCALE, SCALE, SCALE, SCALE, SCALE, SCALE, SCALE}; int[] alphas=new int[]{ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA}; @Override public void draw(Canvas canvas, Paint paint) { float radius=getWidth()/10; for (int i = 0; i < 8; i++) { canvas.save(); Point point=circleAt(getWidth(),getHeight(),getWidth()/2-radius,i*(Math.PI/4)); canvas.translate(point.x,point.y); canvas.scale(scaleFloats[i],scaleFloats[i]); paint.setAlpha(alphas[i]); canvas.drawCircle(0,0,radius,paint); canvas.restore(); } } /** * 圆O的圆心为(a,b),半径为R,点A与到X轴的为角α. *则点A的坐标为(a+R*cosα,b+R*sinα) * @param width * @param height * @param radius * @param angle * @return */ Point circleAt(int width,int height,float radius,double angle){ float x= (float) (width/2+radius*(Math.cos(angle))); float y= (float) (height/2+radius*(Math.sin(angle))); return new Point(x,y); } @Override public List createAnimation() { List animators=new ArrayList<>(); int[] delays= {0, 120, 240, 360, 480, 600, 720, 780, 840}; for (int i = 0; i < 8; i++) { final int index=i; ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.4f,1); scaleAnim.setDuration(1000); scaleAnim.setRepeatCount(-1); scaleAnim.setStartDelay(delays[i]); scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { scaleFloats[index] = (float) animation.getAnimatedValue(); postInvalidate(); } }); scaleAnim.start(); ValueAnimator alphaAnim=ValueAnimator.ofInt(255, 77, 255); alphaAnim.setDuration(1000); alphaAnim.setRepeatCount(-1); alphaAnim.setStartDelay(delays[i]); alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { alphas[index] = (int) animation.getAnimatedValue(); postInvalidate(); } }); alphaAnim.start(); animators.add(scaleAnim); animators.add(alphaAnim); } return animators; } final class Point{ public float x; public float y; public Point(float x, float y){ this.x=x; this.y=y; } } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/BallTrianglePathIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; import android.view.animation.LinearInterpolator; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/19. */ public class BallTrianglePathIndicator extends BaseIndicatorController { float[] translateX=new float[3],translateY=new float[3]; @Override public void draw(Canvas canvas, Paint paint) { paint.setStrokeWidth(3); paint.setStyle(Paint.Style.STROKE); for (int i = 0; i < 3; i++) { canvas.save(); canvas.translate(translateX[i], translateY[i]); canvas.drawCircle(0, 0, getWidth() / 10, paint); canvas.restore(); } } @Override public List createAnimation() { List animators=new ArrayList<>(); float startX=getWidth()/5; float startY=getWidth()/5; for (int i = 0; i < 3; i++) { final int index=i; ValueAnimator translateXAnim=ValueAnimator.ofFloat(getWidth()/2,getWidth()-startX,startX,getWidth()/2); if (i==1){ translateXAnim=ValueAnimator.ofFloat(getWidth()-startX,startX,getWidth()/2,getWidth()-startX); }else if (i==2){ translateXAnim=ValueAnimator.ofFloat(startX,getWidth()/2,getWidth()-startX,startX); } ValueAnimator translateYAnim=ValueAnimator.ofFloat(startY,getHeight()-startY,getHeight()-startY,startY); if (i==1){ translateYAnim=ValueAnimator.ofFloat(getHeight()-startY,getHeight()-startY,startY,getHeight()-startY); }else if (i==2){ translateYAnim=ValueAnimator.ofFloat(getHeight()-startY,startY,getHeight()-startY,getHeight()-startY); } translateXAnim.setDuration(2000); translateXAnim.setInterpolator(new LinearInterpolator()); translateXAnim.setRepeatCount(-1); translateXAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { translateX [index]= (float) animation.getAnimatedValue(); postInvalidate(); } }); translateXAnim.start(); translateYAnim.setDuration(2000); translateYAnim.setInterpolator(new LinearInterpolator()); translateYAnim.setRepeatCount(-1); translateYAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { translateY [index]= (float) animation.getAnimatedValue(); postInvalidate(); } }); translateYAnim.start(); animators.add(translateXAnim); animators.add(translateYAnim); } return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/BallZigZagDeflectIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import android.view.animation.LinearInterpolator; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/19. */ public class BallZigZagDeflectIndicator extends com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallZigZagIndicator { @Override public List createAnimation() { List animators=new ArrayList<>(); float startX=getWidth()/6; float startY=getWidth()/6; for (int i = 0; i < 2; i++) { final int index=i; ValueAnimator translateXAnim=ValueAnimator.ofFloat(startX,getWidth()-startX,startX,getWidth()-startX,startX); if (i==1){ translateXAnim=ValueAnimator.ofFloat(getWidth()-startX,startX,getWidth()-startX,startX,getWidth()-startX); } ValueAnimator translateYAnim=ValueAnimator.ofFloat(startY,startY,getHeight()-startY,getHeight()-startY,startY); if (i==1){ translateYAnim=ValueAnimator.ofFloat(getHeight()-startY,getHeight()-startY,startY,startY,getHeight()-startY); } translateXAnim.setDuration(2000); translateXAnim.setInterpolator(new LinearInterpolator()); translateXAnim.setRepeatCount(-1); translateXAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { translateX [index]= (float) animation.getAnimatedValue(); postInvalidate(); } }); translateXAnim.start(); translateYAnim.setDuration(2000); translateYAnim.setInterpolator(new LinearInterpolator()); translateYAnim.setRepeatCount(-1); translateYAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { translateY [index]= (float) animation.getAnimatedValue(); postInvalidate(); } }); translateYAnim.start(); animators.add(translateXAnim); animators.add(translateYAnim); } return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/BallZigZagIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; import android.view.animation.LinearInterpolator; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/19. */ public class BallZigZagIndicator extends BaseIndicatorController { float[] translateX=new float[2],translateY=new float[2]; @Override public void draw(Canvas canvas, Paint paint) { for (int i = 0; i < 2; i++) { canvas.save(); canvas.translate(translateX[i], translateY[i]); canvas.drawCircle(0, 0, getWidth() / 10, paint); canvas.restore(); } } @Override public List createAnimation() { List animators=new ArrayList<>(); float startX=getWidth()/6; float startY=getWidth()/6; for (int i = 0; i < 2; i++) { final int index=i; ValueAnimator translateXAnim=ValueAnimator.ofFloat(startX,getWidth()-startX,getWidth()/2,startX); if (i==1){ translateXAnim=ValueAnimator.ofFloat(getWidth()-startX,startX,getWidth()/2,getWidth()-startX); } ValueAnimator translateYAnim=ValueAnimator.ofFloat(startY,startY,getHeight()/2,startY); if (i==1){ translateYAnim=ValueAnimator.ofFloat(getHeight()-startY,getHeight()-startY,getHeight()/2,getHeight()-startY); } translateXAnim.setDuration(1000); translateXAnim.setInterpolator(new LinearInterpolator()); translateXAnim.setRepeatCount(-1); translateXAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { translateX[index] = (float) animation.getAnimatedValue(); postInvalidate(); } }); translateXAnim.start(); translateYAnim.setDuration(1000); translateYAnim.setInterpolator(new LinearInterpolator()); translateYAnim.setRepeatCount(-1); translateYAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { translateY[index] = (float) animation.getAnimatedValue(); postInvalidate(); } }); translateYAnim.start(); animators.add(translateXAnim); animators.add(translateYAnim); } return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/BaseIndicatorController.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.graphics.Canvas; import android.graphics.Paint; import android.view.View; import java.util.List; /** * Created by Jack on 2015/10/15. */ public abstract class BaseIndicatorController { private View mTarget; private List mAnimators; public void setTarget(View target){ this.mTarget=target; } public View getTarget(){ return mTarget; } public int getWidth(){ return mTarget.getWidth(); } public int getHeight(){ return mTarget.getHeight(); } public void postInvalidate(){ mTarget.postInvalidate(); } /** * draw indicator * @param canvas * @param paint */ public abstract void draw(Canvas canvas,Paint paint); /** * create animation or animations */ public abstract List createAnimation(); public void initAnimation(){ mAnimators=createAnimation(); } /** * make animation to start or end when target * view was be Visible or Gone or Invisible. * make animation to cancel when target view * be onDetachedFromWindow. * @param animStatus */ public void setAnimationStatus(AnimStatus animStatus){ if (mAnimators==null){ return; } int count=mAnimators.size(); for (int i = 0; i < count; i++) { Animator animator=mAnimators.get(i); boolean isRunning=animator.isRunning(); switch (animStatus){ case START: if (!isRunning){ animator.start(); } break; case END: if (isRunning){ animator.end(); } break; case CANCEL: if (isRunning){ animator.cancel(); } break; } } } public enum AnimStatus{ START,END,CANCEL } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/CubeTransitionIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import android.view.animation.LinearInterpolator; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/18. */ public class CubeTransitionIndicator extends BaseIndicatorController { float[] translateX=new float[2],translateY=new float[2]; float degrees,scaleFloat=1.0f; @Override public void draw(Canvas canvas, Paint paint) { float rWidth=getWidth()/5; float rHeight=getHeight()/5; for (int i = 0; i < 2; i++) { canvas.save(); canvas.translate(translateX[i], translateY[i]); canvas.rotate(degrees); canvas.scale(scaleFloat,scaleFloat); RectF rectF=new RectF(-rWidth/2,-rHeight/2,rWidth/2,rHeight/2); canvas.drawRect(rectF,paint); canvas.restore(); } } @Override public List createAnimation() { List animators=new ArrayList<>(); float startX=getWidth()/5; float startY=getHeight()/5; for (int i = 0; i < 2; i++) { final int index=i; translateX[index]=startX; ValueAnimator translationXAnim=ValueAnimator.ofFloat(startX,getWidth()-startX,getWidth()-startX, startX,startX); if (i==1){ translationXAnim=ValueAnimator.ofFloat(getWidth()-startX,startX,startX, getWidth()-startX,getWidth()-startX); } translationXAnim.setInterpolator(new LinearInterpolator()); translationXAnim.setDuration(1600); translationXAnim.setRepeatCount(-1); translationXAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { translateX[index] = (float) animation.getAnimatedValue(); postInvalidate(); } }); translationXAnim.start(); translateY[index]=startY; ValueAnimator translationYAnim=ValueAnimator.ofFloat(startY,startY,getHeight()-startY,getHeight()- startY,startY); if (i==1){ translationYAnim=ValueAnimator.ofFloat(getHeight()-startY,getHeight()-startY,startY,startY,getHeight()-startY); } translationYAnim.setDuration(1600); translationYAnim.setInterpolator(new LinearInterpolator()); translationYAnim.setRepeatCount(-1); translationYAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { translateY[index] = (float) animation.getAnimatedValue(); postInvalidate(); } }); translationYAnim.start(); animators.add(translationXAnim); animators.add(translationYAnim); } ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.5f,1,0.5f,1); scaleAnim.setDuration(1600); scaleAnim.setInterpolator(new LinearInterpolator()); scaleAnim.setRepeatCount(-1); scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { scaleFloat = (float) animation.getAnimatedValue(); postInvalidate(); } }); scaleAnim.start(); ValueAnimator rotateAnim=ValueAnimator.ofFloat(0,180,360,1.5f*360,2*360); rotateAnim.setDuration(1600); rotateAnim.setInterpolator(new LinearInterpolator()); rotateAnim.setRepeatCount(-1); rotateAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { degrees = (float) animation.getAnimatedValue(); postInvalidate(); } }); rotateAnim.start(); animators.add(scaleAnim); animators.add(rotateAnim); return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/LineScaleIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/19. */ public class LineScaleIndicator extends BaseIndicatorController { public static final float SCALE=1.0f; float[] scaleYFloats=new float[]{SCALE, SCALE, SCALE, SCALE, SCALE,}; @Override public void draw(Canvas canvas, Paint paint) { float translateX=getWidth()/11; float translateY=getHeight()/2; for (int i = 0; i < 5; i++) { canvas.save(); canvas.translate((2 + i * 2) * translateX - translateX / 2, translateY); canvas.scale(SCALE, scaleYFloats[i]); RectF rectF=new RectF(-translateX/2,-getHeight()/2.5f,translateX/2,getHeight()/2.5f); canvas.drawRoundRect(rectF, 5, 5, paint); canvas.restore(); } } @Override public List createAnimation() { List animators=new ArrayList<>(); long[] delays=new long[]{100,200,300,400,500}; for (int i = 0; i < 5; i++) { final int index=i; ValueAnimator scaleAnim=ValueAnimator.ofFloat(1, 0.4f, 1); scaleAnim.setDuration(1000); scaleAnim.setRepeatCount(-1); scaleAnim.setStartDelay(delays[i]); scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { scaleYFloats[index] = (float) animation.getAnimatedValue(); postInvalidate(); } }); scaleAnim.start(); animators.add(scaleAnim); } return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/LineScalePartyIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/19. */ public class LineScalePartyIndicator extends BaseIndicatorController { public static final float SCALE=1.0f; float[] scaleFloats=new float[]{SCALE, SCALE, SCALE, SCALE, SCALE,}; @Override public void draw(Canvas canvas, Paint paint) { float translateX=getWidth()/9; float translateY=getHeight()/2; for (int i = 0; i < 4; i++) { canvas.save(); canvas.translate((2 + i * 2) * translateX - translateX / 2, translateY); canvas.scale(scaleFloats[i], scaleFloats[i]); RectF rectF=new RectF(-translateX/2,-getHeight()/2.5f,translateX/2,getHeight()/2.5f); canvas.drawRoundRect(rectF,5,5,paint); canvas.restore(); } } @Override public List createAnimation() { List animators=new ArrayList<>(); long[] durations=new long[]{1260, 430, 1010, 730}; long[] delays=new long[]{770, 290, 280, 740}; for (int i = 0; i < 4; i++) { final int index=i; ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.4f,1); scaleAnim.setDuration(durations[i]); scaleAnim.setRepeatCount(-1); scaleAnim.setStartDelay(delays[i]); scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { scaleFloats[index] = (float) animation.getAnimatedValue(); postInvalidate(); } }); scaleAnim.start(); animators.add(scaleAnim); } return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/LineScalePulseOutIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/19. */ public class LineScalePulseOutIndicator extends LineScaleIndicator { @Override public List createAnimation() { List animators=new ArrayList<>(); long[] delays=new long[]{500,250,0,250,500}; for (int i = 0; i < 5; i++) { final int index=i; ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.3f,1); scaleAnim.setDuration(900); scaleAnim.setRepeatCount(-1); scaleAnim.setStartDelay(delays[i]); scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { scaleYFloats[index] = (float) animation.getAnimatedValue(); postInvalidate(); } }); scaleAnim.start(); animators.add(scaleAnim); } return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/LineScalePulseOutRapidIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/19. */ public class LineScalePulseOutRapidIndicator extends LineScaleIndicator { @Override public List createAnimation() { List animators=new ArrayList<>(); long[] delays=new long[]{400,200,0,200,400}; for (int i = 0; i < 5; i++) { final int index=i; ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.4f,1); scaleAnim.setDuration(1000); scaleAnim.setRepeatCount(-1); scaleAnim.setStartDelay(delays[i]); scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { scaleYFloats[index] = (float) animation.getAnimatedValue(); postInvalidate(); } }); scaleAnim.start(); animators.add(scaleAnim); } return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/LineSpinFadeLoaderIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; /** * Created by Jack on 2015/10/24. * Email:81813780@qq.com */ public class LineSpinFadeLoaderIndicator extends BallSpinFadeLoaderIndicator { @Override public void draw(Canvas canvas, Paint paint) { float radius=getWidth()/10; for (int i = 0; i < 8; i++) { canvas.save(); Point point=circleAt(getWidth(),getHeight(),getWidth()/2.5f-radius,i*(Math.PI/4)); canvas.translate(point.x, point.y); canvas.scale(scaleFloats[i], scaleFloats[i]); canvas.rotate(i*45); paint.setAlpha(alphas[i]); RectF rectF=new RectF(-radius,-radius/1.5f,1.5f*radius,radius/1.5f); canvas.drawRoundRect(rectF,5,5,paint); canvas.restore(); } } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/PacmanIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import android.view.animation.LinearInterpolator; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/16. */ public class PacmanIndicator extends BaseIndicatorController{ private float translateX; private int alpha; private float degrees1,degrees2; @Override public void draw(Canvas canvas, Paint paint) { drawPacman(canvas,paint); drawCircle(canvas,paint); } private void drawPacman(Canvas canvas,Paint paint){ float x=getWidth()/2; float y=getHeight()/2; canvas.save(); canvas.translate(x, y); canvas.rotate(degrees1); paint.setAlpha(255); RectF rectF1=new RectF(-x/1.7f,-y/1.7f,x/1.7f,y/1.7f); canvas.drawArc(rectF1, 0, 270, true, paint); canvas.restore(); canvas.save(); canvas.translate(x, y); canvas.rotate(degrees2); paint.setAlpha(255); RectF rectF2=new RectF(-x/1.7f,-y/1.7f,x/1.7f,y/1.7f); canvas.drawArc(rectF2,90,270,true,paint); canvas.restore(); } private void drawCircle(Canvas canvas, Paint paint) { float radius=getWidth()/11; paint.setAlpha(alpha); canvas.drawCircle(translateX, getHeight() / 2, radius, paint); } @Override public List createAnimation() { List animators=new ArrayList<>(); float startT=getWidth()/11; ValueAnimator translationAnim=ValueAnimator.ofFloat(getWidth()-startT,getWidth()/2); translationAnim.setDuration(650); translationAnim.setInterpolator(new LinearInterpolator()); translationAnim.setRepeatCount(-1); translationAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { translateX = (float) animation.getAnimatedValue(); postInvalidate(); } }); translationAnim.start(); ValueAnimator alphaAnim=ValueAnimator.ofInt(255,122); alphaAnim.setDuration(650); alphaAnim.setRepeatCount(-1); alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { alpha = (int) animation.getAnimatedValue(); postInvalidate(); } }); alphaAnim.start(); ValueAnimator rotateAnim1=ValueAnimator.ofFloat(0, 45, 0); rotateAnim1.setDuration(650); rotateAnim1.setRepeatCount(-1); rotateAnim1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { degrees1 = (float) animation.getAnimatedValue(); postInvalidate(); } }); rotateAnim1.start(); ValueAnimator rotateAnim2=ValueAnimator.ofFloat(0,-45,0); rotateAnim2.setDuration(650); rotateAnim2.setRepeatCount(-1); rotateAnim2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { degrees2 = (float) animation.getAnimatedValue(); postInvalidate(); } }); rotateAnim2.start(); animators.add(translationAnim); animators.add(alphaAnim); animators.add(rotateAnim1); animators.add(rotateAnim2); return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/SemiCircleSpinIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ObjectAnimator; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/20. */ public class SemiCircleSpinIndicator extends BaseIndicatorController { @Override public void draw(Canvas canvas, Paint paint) { RectF rectF=new RectF(0,0,getWidth(),getHeight()); canvas.drawArc(rectF,-60,120,false,paint); } @Override public List createAnimation() { List animators=new ArrayList<>(); ObjectAnimator rotateAnim=ObjectAnimator.ofFloat(getTarget(),"rotation",0,180,360); rotateAnim.setDuration(600); rotateAnim.setRepeatCount(-1); rotateAnim.start(); animators.add(rotateAnim); return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/SquareSpinIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import android.view.animation.LinearInterpolator; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/16. */ public class SquareSpinIndicator extends BaseIndicatorController { @Override public void draw(Canvas canvas, Paint paint) { canvas.drawRect(new RectF(getWidth()/5,getHeight()/5,getWidth()*4/5,getHeight()*4/5),paint); } @Override public List createAnimation() { List animators=new ArrayList<>(); PropertyValuesHolder rotation5=PropertyValuesHolder.ofFloat("rotationX",0,180,180,0,0); PropertyValuesHolder rotation6=PropertyValuesHolder.ofFloat("rotationY",0,0,180,180,0); ObjectAnimator animator=ObjectAnimator.ofPropertyValuesHolder(getTarget(), rotation6,rotation5); animator.setInterpolator(new LinearInterpolator()); animator.setRepeatCount(-1); animator.setDuration(2500); animator.start(); animators.add(animator); return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/progressindicator/indicator/TriangleSkewSpinIndicator.java ================================================ package com.jcodecraeer.xrecyclerview.progressindicator.indicator; import android.animation.Animator; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.view.animation.LinearInterpolator; import java.util.ArrayList; import java.util.List; /** * Created by Jack on 2015/10/20. */ public class TriangleSkewSpinIndicator extends BaseIndicatorController { @Override public void draw(Canvas canvas, Paint paint) { Path path=new Path(); path.moveTo(getWidth()/5,getHeight()*4/5); path.lineTo(getWidth()*4/5, getHeight()*4/5); path.lineTo(getWidth()/2,getHeight()/5); path.close(); canvas.drawPath(path, paint); } @Override public List createAnimation() { List animators=new ArrayList<>(); PropertyValuesHolder rotation5=PropertyValuesHolder.ofFloat("rotationX",0,180,180,0,0); PropertyValuesHolder rotation6=PropertyValuesHolder.ofFloat("rotationY",0,0,180,180,0); ObjectAnimator animator=ObjectAnimator.ofPropertyValuesHolder(getTarget(), rotation6,rotation5); animator.setInterpolator(new LinearInterpolator()); animator.setRepeatCount(-1); animator.setDuration(2500); animator.start(); animators.add(animator); return animators; } } ================================================ FILE: librarys/xrecyclerview/src/main/res/drawable/progressloading.xml ================================================ ================================================ FILE: librarys/xrecyclerview/src/main/res/drawable-hdpi/progressbar.xml ================================================ ================================================ FILE: librarys/xrecyclerview/src/main/res/layout/listview_footer.xml ================================================ ================================================ FILE: librarys/xrecyclerview/src/main/res/layout/listview_header.xml ================================================ ================================================ FILE: librarys/xrecyclerview/src/main/res/layout/pull_to_refresh_head.xml ================================================ ================================================ FILE: librarys/xrecyclerview/src/main/res/values/attrs.xml ================================================ ================================================ FILE: librarys/xrecyclerview/src/main/res/values/dimens.xml ================================================ 10dp ================================================ FILE: librarys/xrecyclerview/src/main/res/values/strings.xml ================================================ pull to refresh release to start refresh loading... no more to be loaded refreshing... refresh done loading done last update: ================================================ FILE: librarys/xrecyclerview/src/main/res/values-zh/strings.xml ================================================ 下拉刷新 释放立即刷新 正在加载... 没有了 正在刷新... 刷新完成 加载完成 上次更新时间: ================================================ FILE: librarys/zmenu/.gitignore ================================================ /build ================================================ FILE: librarys/zmenu/build.gradle ================================================ apply plugin: 'com.android.library' android { compileSdkVersion 26 buildToolsVersion '26.0.2' defaultConfig { minSdkVersion 15 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:26.1.0' compile 'com.android.support:design:26.1.0' compile 'com.facebook.rebound:rebound:0.3.8' testCompile 'junit:junit:4.12' } ================================================ FILE: librarys/zmenu/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in G:\Android\sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: librarys/zmenu/src/androidTest/java/com/example/zmenu/ExampleInstrumentedTest.java ================================================ package com.example.zmenu; import android.content.Context; import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.*; /** * Instrumentation test, which will execute on an Android device. * * @see Testing documentation */ @RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest { @Test public void useAppContext() throws Exception { // Context of the app under test. Context appContext = InstrumentationRegistry.getTargetContext(); assertEquals("com.example.zmenu.test", appContext.getPackageName()); } } ================================================ FILE: librarys/zmenu/src/main/AndroidManifest.xml ================================================ ================================================ FILE: librarys/zmenu/src/main/java/com/example/zmenu/FloatButton.java ================================================ package com.example.zmenu; import android.content.Context; import android.support.design.widget.FloatingActionButton; import android.util.AttributeSet; import com.facebook.rebound.SimpleSpringListener; import com.facebook.rebound.Spring; import com.facebook.rebound.SpringSystem; /** * Created by xmuSistone. */ public class FloatButton extends FloatingActionButton { private Spring springX, springY; private SimpleSpringListener followerListenerX, followerListenerY; // 此为跟踪的回调,当前面一个view移动的时候,此为后面的view,需要更新endValue public FloatButton(Context context) { this(context, null); } public FloatButton(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FloatButton(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); SpringSystem mSpringSystem = SpringSystem.create(); springX = mSpringSystem.createSpring(); springY = mSpringSystem.createSpring(); springX.addListener(new SimpleSpringListener() { @Override public void onSpringUpdate(Spring spring) { int xPos = (int) spring.getCurrentValue(); setScreenX(xPos); } }); springY.addListener(new SimpleSpringListener() { @Override public void onSpringUpdate(Spring spring) { int yPos = (int) spring.getCurrentValue(); setScreenY(yPos); } }); followerListenerX = new SimpleSpringListener() { @Override public void onSpringUpdate(Spring spring) { int xPos = (int) spring.getCurrentValue(); springX.setEndValue(xPos); } }; followerListenerY = new SimpleSpringListener() { @Override public void onSpringUpdate(Spring spring) { int yPos = (int) spring.getCurrentValue(); springY.setEndValue(yPos); } }; } private void setScreenX(int screenX) { this.offsetLeftAndRight(screenX - getLeft()); } private void setScreenY(int screenY) { this.offsetTopAndBottom(screenY - getTop()); } /** * 顶部ImageView强行停止动画 */ public void stopAnimation() { springX.setAtRest(); springY.setAtRest(); } /** * 只为最顶部的view调用,触点松开后,回归原点 * @param xPos * @param yPos */ public void onRelease(int xPos, int yPos) { setCurrentSpringPos(getLeft(), getTop()); setEndValue(xPos, yPos); } /** * 设置当前spring位置 */ public void setCurrentSpringPos(int xPos, int yPos) { springX.setCurrentValue(xPos); springY.setCurrentValue(yPos); } public Spring getSpringX() { return springX; } public Spring getSpringY() { return springY; } public SimpleSpringListener getFollowerListenerX() { return followerListenerX; } public SimpleSpringListener getFollowerListenerY() { return followerListenerY; } public void setEndValue(int x, int y) { springX.setEndValue(x); springY.setEndValue(y); } //设置阴影为0 @Override public void setElevation(float elevation) { super.setElevation(0); } } ================================================ FILE: librarys/zmenu/src/main/java/com/example/zmenu/PUtils.java ================================================ package com.example.zmenu; import java.util.ArrayList; import java.util.List; /** * Created by Administrator on 2017/12/1 0001. */ public class PUtils { private List imageList; private List colorList; private List viewList; private int marginRight, marginBottom; private boolean isVisible; private static volatile PUtils instance; public static PUtils getInstance() { if (instance == null) { synchronized (PUtils.class) { if (instance == null) { instance = new PUtils(); } } } return instance; } public void setImagesAndColors(List imagelist , List colorlist) { instance.imageList = imagelist; instance.colorList = colorlist; } public void setMargin(int marginRight, int marginBottom) { instance.marginRight = marginRight; instance.marginBottom = marginBottom; } public void setVisible(boolean isVisible) { getInstance().isVisible = isVisible; } public boolean getVisible() { return getInstance().isVisible; } public static List getImages() { return getInstance().imageList; } public static List getColors() { return getInstance().colorList; } public int getMarginRight() { return getInstance().marginRight; } public int getMarginBottom(){ return getInstance().marginBottom; } public void setViewList(List viewList) { instance.viewList = viewList; } public List getViewList() { return getInstance().viewList; } } ================================================ FILE: librarys/zmenu/src/main/java/com/example/zmenu/SnakeButtonLayout.java ================================================ package com.example.zmenu; import android.content.Context; import android.os.Build; import android.support.v4.view.ViewCompat; import android.support.v4.widget.ViewDragHelper; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.RelativeLayout; import java.util.ArrayList; import java.util.List; public class SnakeButtonLayout extends RelativeLayout { private List imageList; private List colorList; private List viewList = new ArrayList<>(); public ViewDragHelper mDragHelper; public ViewController controller; public FloatButton topView; public FloatButton topFollowView; public int marginRight = 0, marginBottom = 0; public onTopViewClickListener onTopViewClickListener; public long upTime = 0, downTime = 0; public boolean isClickable = false; public boolean isVisible = false; public interface onTopViewClickListener { void onclick(); } public SnakeButtonLayout(Context context) { super(context, null); } public SnakeButtonLayout(Context context, AttributeSet attrs) { super(context, attrs); marginRight = PUtils.getInstance().getMarginRight(); marginBottom = PUtils.getInstance().getMarginBottom(); isVisible = PUtils.getInstance().getVisible(); mDragHelper = ViewDragHelper.create(this, 10f, new MyViewDragCallBack()); controller = ViewController.getInstance(); } @Override protected void onFinishInflate() { super.onFinishInflate(); initImagesAndColors(); int len = imageList.size(); for (int i = 0; i < len; i++) { FloatButton floatButton = new FloatButton(getContext()); floatButton.setImageResource(imageList.get(i)); floatButton.setBackgroundTintList(getResources().getColorStateList(colorList.get(i))); if (!isVisible) { floatButton.hide(); } //添加到主布局中去 LayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); lp.setMargins(0, 0, marginRight, marginBottom); lp.addRule(ALIGN_PARENT_BOTTOM); lp.addRule(ALIGN_PARENT_RIGHT); viewList.add(floatButton); Log.d("rules", "restore"); addView(floatButton, lp); //获取顶部的view if (i == len - 1) { topView = floatButton; } if (i == len - 2) { topFollowView = floatButton; } } PUtils.getInstance().setViewList(viewList); controller.init(viewList); } public void initImagesAndColors() { this.imageList = new ArrayList<>(); this.colorList = new ArrayList<>(); if (PUtils.getImages() != null) { this.imageList = PUtils.getImages(); } else { this.imageList.add(R.drawable.image1); this.imageList.add(R.drawable.image2); } if (PUtils.getColors() != null) { this.colorList = PUtils.getColors(); } else { this.colorList.add(R.color.background1); this.colorList.add(R.color.background2); } } public class MyViewDragCallBack extends ViewDragHelper.Callback { //捕捉topview @Override public boolean tryCaptureView(View child, int pointerId) { downTime = System.currentTimeMillis(); Log.d("catchview", "1"); if (child == topView) { topView.stopAnimation(); return true; } return false; } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { topFollowView.setEndValue(left, top); } @Override public int clampViewPositionVertical(View child, int top, int dy) { return top; } @Override public int clampViewPositionHorizontal(View child, int left, int dx) { return left; } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { upTime = System.currentTimeMillis(); //拖拽 < 250ms 触发点击事件 if ((upTime - downTime) < 250L && isClickable == true) { onTopViewClickListener.onclick(); } controller.onRelease(topView); } @Override public int getViewHorizontalDragRange(View child) { return getMeasuredWidth()-child.getMeasuredWidth(); } @Override public int getViewVerticalDragRange(View child) { return getMeasuredHeight()-child.getMeasuredHeight(); } } //设置是否可点击 public void setClickable(boolean isClickable) { this.isClickable = isClickable; } /*实时刷新 保持平滑状态 */ @Override public void computeScroll() { if (mDragHelper.continueSettling(true)) { ViewCompat.postInvalidateOnAnimation(this); } } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return mDragHelper.shouldInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { try { mDragHelper.processTouchEvent(event); } catch (Exception exception) { exception.printStackTrace(); } if ( event.getX() > topView.getLeft() && event.getX() < topView.getRight() && event.getY() > topView.getTop() && event.getY() < topView.getBottom() ) { return true; } return false; } public void setOnTopViewClickListener(onTopViewClickListener listener) { this.onTopViewClickListener = listener; } /*@Override public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { mDragHelper.abort(); } return super.dispatchTouchEvent(ev); }*/ @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); controller.setOriginPos(topView.getLeft(), topView.getTop()); } } ================================================ FILE: librarys/zmenu/src/main/java/com/example/zmenu/ViewController.java ================================================ package com.example.zmenu; import android.util.Log; import java.util.List; /** * Created by Administrator on 2017/12/2 0002. */ public class ViewController { public int resetPosX,resetPosY; public List imageViewList; public ViewController() { } public static ViewController getInstance() { return new ViewController(); } public void init(List list) { Log.d("text1", "11"); imageViewList = list; for (int i = 1; i < list.size(); i++) { Log.d("text1", "12"); FloatButton view1 = list.get(i - 1); FloatButton view2 = list.get(i); view2.getSpringX().addListener(view1.getFollowerListenerX()); view2.getSpringY().addListener(view1.getFollowerListenerY()); } } /** * 设置view最初的原始位置 */ public void setOriginPos(int xPos, int yPos) { resetPosX = xPos; resetPosY = yPos; int len = imageViewList.size(); for (int i = 0; i < len; i++) { imageViewList.get(i).setCurrentSpringPos(xPos, yPos); } } public void onRelease(FloatButton topView) { topView.onRelease(resetPosX, resetPosY); } } ================================================ FILE: librarys/zmenu/src/main/res/values/colors.xml ================================================ #1c574c #00d21c ================================================ FILE: librarys/zmenu/src/main/res/values/strings.xml ================================================ zmenu ================================================ FILE: librarys/zmenu/src/test/java/com/example/zmenu/ExampleUnitTest.java ================================================ package com.example.zmenu; import org.junit.Test; import static org.junit.Assert.*; /** * Example local unit test, which will execute on the development machine (host). * * @see Testing documentation */ public class ExampleUnitTest { @Test public void addition_isCorrect() throws Exception { assertEquals(4, 2 + 2); } } ================================================ FILE: settings.gradle ================================================ include ':app', ':librarys:http', ':librarys:jiaozivideoplayer', ':librarys:xrecyclerview', ':librarys:zmenu'