├── .gitignore ├── .idea ├── .gitignore ├── .name ├── compiler.xml ├── inspectionProfiles │ └── Project_Default.xml ├── jarRepositories.xml └── misc.xml ├── LICENSE ├── Label_README.md ├── README.md ├── TAB_README.md ├── TAB_README3_0.md ├── appx ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── zhengsr │ │ └── tabhelper │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── zhengsr │ │ │ └── tabhelper │ │ │ ├── App.java │ │ │ ├── CommonUtils.java │ │ │ ├── MainActivity.java │ │ │ ├── activity │ │ │ ├── BaseActivity.java │ │ │ ├── CountActivity.java │ │ │ ├── LabelActivity.java │ │ │ ├── LabelShowMoreActivity.java │ │ │ ├── NetTestActivity.java │ │ │ ├── TabActivity.java │ │ │ ├── TabNoViewPagerActivity.java │ │ │ └── VerticalTabActivity.java │ │ │ ├── bean │ │ │ ├── ArticleData.java │ │ │ ├── BaseResponse.java │ │ │ ├── NaviBean.java │ │ │ ├── NaviChildrenBean.java │ │ │ ├── PageDataInfo.java │ │ │ └── SystematicBean.java │ │ │ ├── fragment │ │ │ ├── BaseFragment.java │ │ │ ├── CusFragment.java │ │ │ ├── RecyclerFragment.java │ │ │ └── TestFragment.java │ │ │ ├── rx │ │ │ ├── HttpCreate.java │ │ │ └── HttpServerApi.java │ │ │ └── utils │ │ │ └── RxUtils.java │ └── res │ │ ├── color │ │ └── color_selector.xml │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── ic_launcher_background.xml │ │ ├── select_tag.xml │ │ ├── shape_bg.xml │ │ ├── shape_red_radius.xml │ │ ├── shape_round.xml │ │ ├── shape_round_ff.xml │ │ ├── shape_round_trans.xml │ │ ├── shape_search.xml │ │ ├── shape_search_select.xml │ │ └── shape_showmore.xml │ │ ├── layout │ │ ├── activity_count.xml │ │ ├── activity_label.xml │ │ ├── activity_label_show_more.xml │ │ ├── activity_main.xml │ │ ├── activity_net_test.xml │ │ ├── activity_tab.xml │ │ ├── activity_tab_no_view_pager.xml │ │ ├── activity_vertical_tab.xml │ │ ├── handup.xml │ │ ├── item_article_recy_layout.xml │ │ ├── item_color_msg.xml │ │ ├── item_msg.xml │ │ ├── item_navi_detail.xml │ │ ├── item_search_layout.xml │ │ ├── item_tab.xml │ │ ├── item_tab_text.xml │ │ ├── item_test.xml │ │ ├── item_text_width_match.xml │ │ ├── item_textview.xml │ │ ├── item_textview_navi.xml │ │ ├── recycler_layout.xml │ │ ├── show_more.xml │ │ ├── tab_text_layout.xml │ │ └── test_fragment.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── bg_man.jpg │ │ ├── delete.png │ │ ├── handup.png │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ └── more.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── zhengsr │ └── tabhelper │ └── ExampleUnitTest.java ├── build.gradle ├── gif ├── alipay.jpg ├── label.gif ├── label_showmore.gif ├── tab_click.gif ├── tab_vertical.gif ├── tab_viewpager.gif ├── tab_visual_count.png └── wechat.png ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── tablibx ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src ├── androidTest └── java │ └── com │ └── zhengsr │ └── tablib │ └── ExampleInstrumentedTest.java ├── main ├── AndroidManifest.xml ├── java │ └── com │ │ └── zhengsr │ │ └── tablib │ │ ├── FlowConstants.java │ │ ├── bean │ │ ├── BaseLabelItem.java │ │ ├── LabelBean.java │ │ ├── TabBean.java │ │ ├── TabConfig.java │ │ ├── TabTypeEvaluator.java │ │ ├── TabValue.java │ │ └── TextConfig.java │ │ ├── callback │ │ ├── FlowListener.java │ │ └── FlowListenerAdapter.java │ │ ├── utils │ │ ├── AttrsUtils.java │ │ ├── DisplayUtil.java │ │ └── ViewPagerHelperUtils.java │ │ └── view │ │ ├── TabColorTextView.java │ │ ├── action │ │ ├── BViewPager.java │ │ ├── BaseAction.java │ │ ├── BaseVpAction.java │ │ ├── ColorAction.java │ │ ├── RectAction.java │ │ ├── ResAction.java │ │ ├── RoundAction.java │ │ └── TriAction.java │ │ ├── adapter │ │ ├── BaseFlowAdapter.java │ │ ├── LabelFlowAdapter.java │ │ ├── TabFlowAdapter.java │ │ └── TemplateAdapter.java │ │ └── flow │ │ ├── LabelFlowLayout.java │ │ ├── TabFlowLayout.java │ │ ├── TabVpFlowLayout.java │ │ └── base │ │ ├── AbsFlowLayout.java │ │ ├── FlowLayout.java │ │ └── ScrollFlowLayout.java └── res │ └── values │ ├── attrs.xml │ └── strings.xml └── test └── java └── com └── zhengsr └── tablib └── ExampleUnitTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.aar 4 | *.ap_ 5 | *.aab 6 | 7 | # Files for the ART/Dalvik VM 8 | *.dex 9 | 10 | # Java class files 11 | *.class 12 | 13 | # Generated files 14 | bin/ 15 | gen/ 16 | out/ 17 | # Uncomment the following line in case you need and you don't have the release build type files in your app 18 | # release/ 19 | 20 | # Gradle files 21 | .gradle/ 22 | build/ 23 | 24 | # Local configuration file (sdk path, etc) 25 | local.properties 26 | 27 | # Proguard folder generated by Eclipse 28 | proguard/ 29 | 30 | # Log Files 31 | *.log 32 | 33 | # Android Studio Navigation editor temp files 34 | .navigation/ 35 | 36 | # Android Studio captures folder 37 | captures/ 38 | 39 | # IntelliJ 40 | *.iml 41 | .idea/workspace.xml 42 | .idea/tasks.xml 43 | .idea/gradle.xml 44 | .idea/assetWizardSettings.xml 45 | .idea/dictionaries 46 | .idea/libraries 47 | # Android Studio 3 in .gitignore file. 48 | .idea/caches 49 | .idea/modules.xml 50 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 51 | .idea/navEditor.xml 52 | 53 | # Keystore files 54 | # Uncomment the following lines if you do not want to check your keystore files in. 55 | #*.jks 56 | #*.keystore 57 | 58 | # External native build folder generated in Android Studio 2.2 and later 59 | .externalNativeBuild 60 | .cxx/ 61 | 62 | # Google Services (e.g. APIs or Firebase) 63 | # google-services.json 64 | 65 | # Freeline 66 | freeline.py 67 | freeline/ 68 | freeline_project_description.json 69 | 70 | # fastlane 71 | fastlane/report.xml 72 | fastlane/Preview.html 73 | fastlane/screenshots 74 | fastlane/test_output 75 | fastlane/readme.md 76 | 77 | # Version control 78 | vcs.xml 79 | 80 | # lint 81 | lint/intermediates/ 82 | lint/generated/ 83 | lint/outputs/ 84 | lint/tmp/ 85 | # lint/reports/ 86 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | TabHelper -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 36 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 22 | 23 | 24 | 25 | 26 | 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FlowHelper 2 | FlowHelper 可以帮助您迅速构建Tab,比如热搜、搜索记录、与ViewPager搭配的工具类; 3 | 4 | **注意注意注意!!!** 5 | **提问题的时候,请遵循以下标准** 6 | 7 | - **现象: 操作步骤,应用场景** 8 | - **对应代码: 贴图或者贴代码** 9 | - **机型或版本: 可选** 10 | 11 | **后面对描述不清的问题,不予理会,精力有限,感谢理解** 12 | 13 | **具体原理可参考着四篇文章:** 14 | 15 | **如果你也想自己写一个,可以参考以下几篇文章** 16 | 17 | [实现一个可定制化的TabFlowLayout(一) -- 测量与布局](https://blog.csdn.net/u011418943/article/details/103804677) 18 | 19 | [实现一个可定制化的TabFlowLayout(二) -- 实现滚动和平滑过渡](https://blog.csdn.net/u011418943/article/details/103807920) 20 | 21 | [实现一个可定制化的TabFlowLayout(三) -- 动态数据添加与常用接口封装](https://blog.csdn.net/u011418943/article/details/103817967) 22 | 23 | [实现一个可定制化的TabFlowLayout(四) -- 与ViewPager 结合,实现炫酷效果](https://blog.csdn.net/u011418943/article/details/103851359) 24 | 25 | [实现一个可定制化的TabFlowLayout -- 原理篇](https://juejin.im/post/5e365f52f265da3e3d511d65) 26 | 27 | [实现一个可定制化的TabFlowLayout -- 说明文档](https://juejin.im/post/5e2f9dc7e51d4558836e3f99) 28 | 29 | 30 | [FlowLayout 和 Recyclerview 实现双联表联动](https://blog.csdn.net/u011418943/article/details/104083568) 31 | 32 | 如果您也想快速实现 **Banner 轮播图**,可以使用这个库 https://github.com/LillteZheng/ViewPagerHelper 33 | 34 | **工程实际使用 - 玩Android 客户端 : https://github.com/LillteZheng/WanAndroid** 35 | 36 | 37 | [![](https://jitpack.io/v/LillteZheng/FlowHelper.svg)](https://jitpack.io/#LillteZheng/FlowHelper) 38 | ![](https://img.shields.io/github/stars/LillteZheng/FlowHelper.svg) 39 | ![](https://img.shields.io/github/forks/LillteZheng/FlowHelper.svg) 40 | [![](https://img.shields.io/badge/%E4%BD%9C%E8%80%85-%E9%83%91%E5%B0%91%E9%94%90-green.svg)](https://blog.csdn.net/u011418943) 41 | 42 | ## 使用 43 | 在buid.gradle (新版as在setting.gradle) 44 | ``` 45 | allprojects { 46 | repositories { 47 | ... 48 | maven { url 'https://jitpack.io' } 49 | 50 | } 51 | } 52 | ``` 53 | 54 | 55 | **如果你的工程的是androidx且想支持ViewPager2,可以关联tablibx库** 56 | ``` 57 | implementation 'com.github.LillteZheng:FlowHelper:v2.3' 58 | ``` 59 | **support可以关联以下连接,请尽快切到androidx,support包不再维护** 60 | ``` 61 | implementation 'com.github.LillteZheng.FlowHelper:tablib:v1.29' 62 | ``` 63 | 64 | 65 | **不一定有时间处理,如果工程有不满足或bug,可以修改后提mr** 66 | 67 | 68 | ## TabFlowLayout 效果图 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 |
没有结合ViewPager结合ViewPager
81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 |
竖直效果
91 | 92 | **目前TabFlowLayout 支持以下效果:** 93 | - **矩形** 94 | - **三角形** 95 | - **圆角** 96 | - **shape 或者 bitmap 等资源** 97 | - **自定义功能** 98 | - **放大Item效果,与上述效果可共用** 99 | - **颜色渐变效果,需要使用 TabColorTextView 控件,与上述效果可共用,只支持有viewpager 的情况** 100 | - **竖直效果,需要设置 tab_orientation = vertical** 101 | - **宽度均分** 102 | 103 | [TabFlowLayout 使用说明](https://github.com/LillteZheng/FlowHelper/blob/feature_3.0/TAB_README3_0.md) 104 | 105 | ## LabelFlowLayout 效果图 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 |
LabelFlowLayoutLabelFlowLayout 显示更多
118 | 119 | 120 | **LabelFlowLayout 支持以下效果:** 121 | - **单选** 122 | - **多选** 123 | - **长按** 124 | - **显示更多** 125 | - **收起** 126 | 127 | 128 | [LabelFlowLayout 使用说明](https://github.com/LillteZheng/FlowHelper/blob/master/Label_README.md) 129 | 130 | 131 | **其实TabFlowLayout也可以支持底部导航栏,但其实没必要,可以参考这个库 https://github.com/LillteZheng/CusBottomHelper** 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 |
底部凸起结合ViewPager
143 | 144 | 145 | 146 | ## 版本信息: 147 | - v2.5 : 修复TabLabelLayout 在调用 resetStatus,第一个无法点击的问题。并增加 BaseLabelItem,Bean 类继承它,可实现换行 148 | - v2.3 : 修改TabVpFlowLayout 快速点击时,TabColorTextView 还有残留,和 tab 没有转移过去的问题 149 | - v2.0 : 内置部分控件,减少接入成本,并优化一些bug,和关闭demo ,viewpager 内存泄露的问题 150 | - v1.37 : 增加 tab_width_equals_text ,让 rect 根据 text 的长度变化,修复 TabColorTextView 加粗不起作用的问题 151 | - v1.32 : 修复res和round,tab_margin_x 不起作用的问题 152 | - v1.30 : 重构分离了ViewPager和非ViewPager的情况,并处理数据增加减少时,notifyDataChange()导致布局混乱的问题 153 | - v1.291: 修复notifyDataChange部分场景不起作用的问题,小重构了参数配置 154 | - v1.29 : 修复添加了tabWidth,round和res第一次不起作用的问题 155 | - v1.28 : 1. 修复底部条跳动的问题;2. 修复TabColorText不能设置padding的问题 156 | - v1.27 : 修复 tab_color 不起作用的问题 157 | - v1.26 : 增加 ViewPager2 158 | .... 159 | 160 | ## QQ群 161 | 为方便大家交流,创建了一个qq群,群号216618259 162 | 163 | 164 | 165 | 166 | ## 如果该项目对您有帮助,赞赏一下吧 ^_^ 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 |
赞赏名单方式
*头微信
*变微信
184 | 185 | 186 | 187 | ## 参考 188 | 189 | 本工程参考以下优秀项目: 190 | 191 | [鸿洋的 flowLayout](https://github.com/hongyangAndroid/FlowLayout) 192 | 193 | [Flyco的 TabLayout](https://github.com/H07000223/FlycoTabLayout) 194 | 195 | 196 | 197 | 198 | -------------------------------------------------------------------------------- /appx/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /appx/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 29 5 | 6 | defaultConfig { 7 | applicationId "com.zhengsr.tabhelper" 8 | minSdkVersion 19 9 | targetSdkVersion 29 10 | versionCode 1 11 | versionName "1.0" 12 | 13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 14 | } 15 | 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | } 23 | 24 | dependencies { 25 | implementation fileTree(dir: "libs", include: ["*.jar"]) 26 | implementation 'androidx.appcompat:appcompat:1.2.0' 27 | implementation 'androidx.constraintlayout:constraintlayout:2.0.1' 28 | testImplementation 'junit:junit:4.12' 29 | androidTestImplementation 'androidx.test.ext:junit:1.1.2' 30 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' 31 | 32 | implementation project(path: ':tablibx') 33 | //implementation 'com.github.LillteZheng:FlowHelper:v1.34' 34 | implementation 'me.yokeyword:fragmentationx:1.0.2' 35 | implementation 'androidx.cardview:cardview:1.0.0' 36 | implementation 'androidx.viewpager2:viewpager2:1.0.0' 37 | implementation 'com.squareup.retrofit2:retrofit:2.5.0' 38 | implementation 'com.squareup.retrofit2:converter-scalars:2.5.0' 39 | 40 | implementation 'io.reactivex.rxjava2:rxjava:2.2.10' 41 | implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' 42 | implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0' 43 | implementation 'com.alibaba:fastjson:1.1.71.android' 44 | implementation 'org.ligboy.retrofit2:converter-fastjson-android:2.1.0' 45 | debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7' 46 | implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4' 47 | implementation 'com.github.weikaiyun.SFragmentation:fragmentation:1.8.4' 48 | } 49 | -------------------------------------------------------------------------------- /appx/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /appx/src/androidTest/java/com/zhengsr/tabhelper/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.zhengsr.tabhelper; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | assertEquals("com.exceedshare.appx", appContext.getPackageName()); 25 | } 26 | } -------------------------------------------------------------------------------- /appx/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /appx/src/main/java/com/zhengsr/tabhelper/App.java: -------------------------------------------------------------------------------- 1 | package com.zhengsr.tabhelper; 2 | 3 | import android.app.Application; 4 | 5 | import com.weikaiyun.fragmentation.Fragmentation; 6 | 7 | /** 8 | * @author by zhengshaorui 2022/2/26 9 | * describe: 10 | */ 11 | public class App extends Application { 12 | @Override 13 | public void onCreate() { 14 | super.onCreate(); 15 | Fragmentation.builder() // 设置 栈视图 模式为 (默认)悬浮球模式 SHAKE: 摇一摇唤出 NONE:隐藏, 仅在Debug环境生效 16 | .stackViewMode(Fragmentation.BUBBLE) 17 | .debug(BuildConfig.DEBUG) // 实际场景建议.debug(BuildConfig.DEBUG) 18 | .animation(R.anim.v_fragment_enter, R.anim.v_fragment_pop_exit, R.anim.v_fragment_pop_enter, R.anim.v_fragment_exit) //设置默认动画 19 | .install(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /appx/src/main/java/com/zhengsr/tabhelper/CommonUtils.java: -------------------------------------------------------------------------------- 1 | package com.zhengsr.tabhelper; 2 | 3 | import android.graphics.Color; 4 | import android.graphics.drawable.Drawable; 5 | import android.graphics.drawable.GradientDrawable; 6 | 7 | import java.util.Random; 8 | 9 | /** 10 | * @author by zhengshaorui on 2019/10/8 11 | * Describe: 12 | */ 13 | public class CommonUtils { 14 | /** 15 | * Tab colors 16 | */ 17 | public static final int[] TAB_COLORS = new int[]{ 18 | Color.parseColor("#90C5F0"), 19 | Color.parseColor("#91CED5"), 20 | Color.parseColor("#F88F55"), 21 | Color.parseColor("#C0AFD0"), 22 | Color.parseColor("#E78F8F"), 23 | Color.parseColor("#67CCB7"), 24 | Color.parseColor("#F6BC7E"), 25 | Color.parseColor("#3399ff") 26 | }; 27 | public static int randomTagColor() { 28 | int randomNum = new Random().nextInt(); 29 | int position = randomNum % TAB_COLORS.length; 30 | if (position < 0) { 31 | position = -position; 32 | } 33 | return TAB_COLORS[position]; 34 | } 35 | 36 | public static Drawable getColorDrawable(int radius){ 37 | GradientDrawable drawable = new GradientDrawable(); 38 | drawable.setColor(randomTagColor()); 39 | drawable.setCornerRadius(radius); 40 | return drawable; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /appx/src/main/java/com/zhengsr/tabhelper/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhengsr.tabhelper; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.widget.TextView; 7 | 8 | import androidx.appcompat.app.AppCompatActivity; 9 | import androidx.fragment.app.Fragment; 10 | import androidx.fragment.app.FragmentManager; 11 | import androidx.fragment.app.FragmentPagerAdapter; 12 | import androidx.viewpager.widget.ViewPager; 13 | 14 | import com.zhengsr.tabhelper.activity.BaseActivity; 15 | import com.zhengsr.tabhelper.activity.CountActivity; 16 | import com.zhengsr.tabhelper.activity.LabelActivity; 17 | import com.zhengsr.tabhelper.activity.LabelShowMoreActivity; 18 | import com.zhengsr.tabhelper.activity.NetTestActivity; 19 | import com.zhengsr.tabhelper.activity.TabActivity; 20 | import com.zhengsr.tabhelper.activity.TabNoViewPagerActivity; 21 | import com.zhengsr.tabhelper.activity.VerticalTabActivity; 22 | import com.zhengsr.tabhelper.fragment.TestFragment; 23 | 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | 27 | public class MainActivity extends BaseActivity { 28 | private List mFragments = new ArrayList<>(); 29 | @Override 30 | protected void onCreate(Bundle savedInstanceState) { 31 | super.onCreate(savedInstanceState); 32 | setContentView(R.layout.activity_main); 33 | TextView textView = findViewById(R.id.text); 34 | textView.setTextColor(getResources().getColor(R.color.color_selector)); 35 | } 36 | 37 | 38 | public void tablayout(View view) { 39 | startActivity(new Intent(this, TabActivity.class)); 40 | } 41 | 42 | public void tablayout2(View view) { 43 | startActivity(new Intent(this, TabNoViewPagerActivity.class)); 44 | } 45 | public void tab_count(View view) { 46 | startActivity(new Intent(this, CountActivity.class)); 47 | } 48 | 49 | public void labelflow(View view) { 50 | startActivity(new Intent(this, LabelActivity.class)); 51 | } 52 | 53 | public void tablayout3(View view) { 54 | startActivity(new Intent(this, NetTestActivity.class)); 55 | } 56 | 57 | public void tablayout4(View view) { 58 | startActivity(new Intent(this,VerticalTabActivity.class)); 59 | } 60 | 61 | public void labelflowshomore(View view) { 62 | startActivity(new Intent(this, LabelShowMoreActivity.class)); 63 | } 64 | 65 | /** 66 | * viewpager adapter 67 | */ 68 | class CusAdapter extends FragmentPagerAdapter { 69 | 70 | public CusAdapter(FragmentManager fm) { 71 | super(fm); 72 | } 73 | 74 | @Override 75 | public Fragment getItem(int position) { 76 | return mFragments.get(position); 77 | } 78 | 79 | @Override 80 | public int getCount() { 81 | return mFragments.size(); 82 | } 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /appx/src/main/java/com/zhengsr/tabhelper/activity/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhengsr.tabhelper.activity; 2 | 3 | import me.yokeyword.fragmentation.SupportActivity; 4 | 5 | /** 6 | * @author by zhengshaorui 2022/2/26 7 | * describe: 8 | */ 9 | public class BaseActivity extends SupportActivity { 10 | } 11 | -------------------------------------------------------------------------------- /appx/src/main/java/com/zhengsr/tabhelper/activity/CountActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhengsr.tabhelper.activity; 2 | 3 | import android.os.Bundle; 4 | import android.view.View; 5 | 6 | import androidx.annotation.NonNull; 7 | import androidx.annotation.Nullable; 8 | import androidx.appcompat.app.AppCompatActivity; 9 | import androidx.fragment.app.Fragment; 10 | import androidx.fragment.app.FragmentActivity; 11 | import androidx.viewpager2.adapter.FragmentStateAdapter; 12 | import androidx.viewpager2.widget.ViewPager2; 13 | 14 | import com.zhengsr.tabhelper.R; 15 | import com.zhengsr.tabhelper.fragment.CusFragment; 16 | import com.zhengsr.tablib.view.adapter.TabFlowAdapter; 17 | import com.zhengsr.tablib.view.flow.TabVpFlowLayout; 18 | 19 | import java.util.ArrayList; 20 | import java.util.Arrays; 21 | import java.util.List; 22 | 23 | /** 24 | * @author by zhengshaorui 2021/4/22 16:31 25 | * describe: 26 | */ 27 | public class CountActivity extends BaseActivity { 28 | private List mTitle = new ArrayList<>(Arrays.asList("test1","test2")); 29 | private List mFragments = new ArrayList<>(); 30 | private ViewPager2 mViewPager; 31 | @Override 32 | protected void onCreate(@Nullable Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | setContentView(R.layout.activity_count); 35 | mViewPager = findViewById(R.id.viewpager2); 36 | for (String s : mTitle) { 37 | mFragments.add(CusFragment.newInStance(s)); 38 | } 39 | mViewPager.setAdapter(new CusAdapter2(this)); 40 | rectFlow(); 41 | } 42 | 43 | private void rectFlow(){ 44 | final TabVpFlowLayout flowLayout = findViewById(R.id.rectflow); 45 | // flowLayout.setViewPager(mViewPager,R.id.item_text,getResources().getColor(R.color.unselect),Color.WHITE); 46 | flowLayout.setViewPager(mViewPager); 47 | flowLayout.setAdapter(new TabFlowAdapter(mTitle)); 48 | 49 | 50 | 51 | 52 | } 53 | 54 | class CusAdapter2 extends FragmentStateAdapter { 55 | 56 | public CusAdapter2(@NonNull FragmentActivity fragmentActivity) { 57 | super(fragmentActivity); 58 | } 59 | 60 | @NonNull 61 | @Override 62 | public Fragment createFragment(int position) { 63 | return mFragments.get(position); 64 | } 65 | 66 | @Override 67 | public int getItemCount() { 68 | return mFragments.size(); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /appx/src/main/java/com/zhengsr/tabhelper/activity/LabelActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhengsr.tabhelper.activity; 2 | 3 | import android.graphics.Color; 4 | import android.icu.text.CaseMap; 5 | import android.os.Bundle; 6 | import android.service.quicksettings.Tile; 7 | import android.view.View; 8 | import android.widget.Toast; 9 | 10 | import androidx.appcompat.app.AppCompatActivity; 11 | 12 | import com.zhengsr.tabhelper.CommonUtils; 13 | import com.zhengsr.tabhelper.R; 14 | import com.zhengsr.tablib.bean.BaseLabelItem; 15 | import com.zhengsr.tablib.view.adapter.LabelFlowAdapter; 16 | import com.zhengsr.tablib.view.flow.LabelFlowLayout; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Arrays; 20 | import java.util.List; 21 | 22 | public class LabelActivity extends BaseActivity { 23 | private List mTitle = new ArrayList<>(Arrays.asList("新闻", "娱乐", "学习", "测试后", "新闻", "娱乐", "学习")); 24 | private List mTitle2 = new ArrayList<>(Arrays.asList("Life is like an ocean Only strong willed ".split(" "))); 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_label); 30 | singleFlow(); 31 | searchFlow(); 32 | multiFlow(); 33 | canLongFlow(); 34 | } 35 | 36 | private void singleFlow() { 37 | LabelFlowLayout flowLayout = findViewById(R.id.singleflow); 38 | List datas = new ArrayList(); 39 | for (int i = 0; i < 20; i++) { 40 | SingleBean bean = new SingleBean(); 41 | bean.name = "测试 " + i; 42 | if (i == 0 || i == 3 || i == 10) { 43 | bean.isHeader = true; 44 | bean.name = "Header"; 45 | } 46 | datas.add(bean); 47 | } 48 | final LabelFlowAdapter adapter; 49 | flowLayout.setAdapter(adapter = new LabelFlowAdapter(R.layout.item_textview, datas) { 50 | @Override 51 | public void bindView(View view, SingleBean data, int position) { 52 | setText(view, R.id.item_text, data.name) 53 | .setTextColor(view, R.id.item_text, getResources().getColor(R.color.unselect)); 54 | } 55 | 56 | 57 | @Override 58 | public void onItemSelectState(View view, boolean isSelected) { 59 | super.onItemSelectState(view, isSelected); 60 | if (isSelected) { 61 | setTextColor(view, R.id.item_text, Color.BLACK); 62 | } else { 63 | setTextColor(view, R.id.item_text, getResources().getColor(R.color.unselect)); 64 | } 65 | } 66 | }); 67 | 68 | findViewById(R.id.update).setOnClickListener(new View.OnClickListener() { 69 | @Override 70 | public void onClick(View view) { 71 | mTitle.clear(); 72 | mTitle.addAll(mTitle2); 73 | adapter.notifyDataChanged(); 74 | } 75 | }); 76 | 77 | // flowLayout.setSelects(6); 78 | 79 | } 80 | 81 | class SingleBean extends BaseLabelItem { 82 | public String name; 83 | } 84 | 85 | private void searchFlow() { 86 | LabelFlowLayout flowLayout = findViewById(R.id.search_flow); 87 | flowLayout.setAdapter(new LabelFlowAdapter(R.layout.item_textview, mTitle) { 88 | @Override 89 | public void bindView(View view, String data, int position) { 90 | setText(view, R.id.item_text, data) 91 | .setTextColor(view, R.id.item_text, Color.WHITE); 92 | view.setBackground(CommonUtils.getColorDrawable(10)); 93 | } 94 | }); 95 | 96 | } 97 | 98 | private void multiFlow() { 99 | LabelFlowLayout flowLayout = findViewById(R.id.multiflow); 100 | flowLayout.setMaxSelectCount(3); 101 | flowLayout.setAdapter(new LabelFlowAdapter(R.layout.item_textview, mTitle2) { 102 | @Override 103 | public void bindView(View view, String data, int position) { 104 | setText(view, R.id.item_text, data); 105 | } 106 | 107 | 108 | @Override 109 | public void onReachMaxCount(List ids, int count) { 110 | super.onReachMaxCount(ids, count); 111 | Toast.makeText(LabelActivity.this, "最多只能选中 " + count + " 个" + " 已选中坐标: " + ids, Toast.LENGTH_SHORT).show(); 112 | } 113 | 114 | 115 | }); 116 | 117 | //选中默认数据 118 | flowLayout.setSelects(2, 3, 5); 119 | 120 | } 121 | 122 | private void canLongFlow() { 123 | LabelFlowLayout flowLayout = findViewById(R.id.longflow); 124 | flowLayout.setAdapter(new LabelFlowAdapter(R.layout.item_search_layout, mTitle2) { 125 | @Override 126 | public void bindView(View view, String data, int position) { 127 | setText(view, R.id.search_msg_tv, data) 128 | .addChildrenClick(view, R.id.search_delete_iv, position); 129 | } 130 | 131 | @Override 132 | public void onItemSelectState(View view, boolean isSelected) { 133 | super.onItemSelectState(view, isSelected); 134 | if (!isSelected) { 135 | view.setBackgroundResource(R.drawable.shape_search); 136 | setVisible(view, R.id.search_delete_iv, false); 137 | } 138 | } 139 | 140 | @Override 141 | public void onItemClick(View view, String data, int position) { 142 | super.onItemClick(view, data, position); 143 | Toast.makeText(LabelActivity.this, "点击了: " + data, Toast.LENGTH_SHORT).show(); 144 | } 145 | 146 | @Override 147 | public void onItemChildClick(View childView, int position) { 148 | super.onItemChildClick(childView, position); 149 | if (childView.getId() == R.id.search_delete_iv) { 150 | mTitle2.remove(position); 151 | notifyDataChanged(); 152 | } 153 | } 154 | 155 | @Override 156 | public boolean onItemLongClick(View view, int position) { 157 | /** 158 | * 置所有view 的 select 为 false 159 | */ 160 | resetStatus(); 161 | view.setBackgroundResource(R.drawable.shape_search_select); 162 | setVisible(view, R.id.search_delete_iv, true); 163 | return super.onItemLongClick(view, position); 164 | } 165 | 166 | 167 | }); 168 | } 169 | 170 | 171 | public void test(View view) { 172 | 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /appx/src/main/java/com/zhengsr/tabhelper/activity/LabelShowMoreActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhengsr.tabhelper.activity; 2 | 3 | import android.graphics.Color; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.widget.Toast; 7 | 8 | import androidx.appcompat.app.AppCompatActivity; 9 | 10 | import com.zhengsr.tabhelper.R; 11 | import com.zhengsr.tablib.bean.LabelBean; 12 | import com.zhengsr.tablib.view.adapter.LabelFlowAdapter; 13 | import com.zhengsr.tablib.view.flow.LabelFlowLayout; 14 | 15 | import java.util.ArrayList; 16 | import java.util.Arrays; 17 | import java.util.List; 18 | 19 | public class LabelShowMoreActivity extends BaseActivity { 20 | 21 | private List mTitle = new ArrayList<>(Arrays.asList("Life is like an ocean Only strong willed people can reach the other side ".split(" "))); 22 | 23 | @Override 24 | protected void onCreate(Bundle savedInstanceState) { 25 | super.onCreate(savedInstanceState); 26 | setContentView(R.layout.activity_label_show_more); 27 | 28 | LabelFlowLayout flowLayout = findViewById(R.id.labelflow); 29 | 30 | //自定义属性 31 | LabelBean bean = new LabelBean(); 32 | bean.showLines = 2; 33 | bean.showMoreLayoutId = R.layout.show_more; 34 | bean.showMoreColor = Color.WHITE; 35 | bean.handUpLayoutId = R.layout.handup; 36 | 37 | flowLayout.setLabelBean(bean); 38 | flowLayout.setAdapter(new LabelFlowAdapter(R.layout.item_textview,mTitle) { 39 | @Override 40 | public void bindView(View view, String data, int position) { 41 | setDefaultText(view,data) 42 | .setDefaultTextColor(view, Color.BLACK); 43 | } 44 | @Override 45 | public void onItemSelectState(View view, boolean isSelected) { 46 | super.onItemSelectState(view, isSelected); 47 | if (isSelected){ 48 | setDefaultTextColor(view, getResources().getColor(R.color.colorPrimary)); 49 | }else{ 50 | setDefaultTextColor(view,Color.BLACK); 51 | } 52 | } 53 | 54 | @Override 55 | public void onShowMoreClick(View view) { 56 | super.onShowMoreClick(view); 57 | Toast.makeText(LabelShowMoreActivity.this, "显示全部", Toast.LENGTH_SHORT).show(); 58 | } 59 | 60 | @Override 61 | public void onHandUpClick(View view) { 62 | super.onHandUpClick(view); 63 | Toast.makeText(LabelShowMoreActivity.this, "收起", Toast.LENGTH_SHORT).show(); 64 | } 65 | }); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /appx/src/main/java/com/zhengsr/tabhelper/activity/NetTestActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhengsr.tabhelper.activity; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.os.Bundle; 5 | import android.util.Log; 6 | import android.view.View; 7 | 8 | import androidx.fragment.app.Fragment; 9 | import androidx.fragment.app.FragmentManager; 10 | import androidx.fragment.app.FragmentPagerAdapter; 11 | import androidx.viewpager.widget.ViewPager; 12 | 13 | import com.zhengsr.tabhelper.R; 14 | import com.zhengsr.tabhelper.bean.BaseResponse; 15 | import com.zhengsr.tabhelper.bean.NaviChildrenBean; 16 | import com.zhengsr.tabhelper.bean.SystematicBean; 17 | import com.zhengsr.tabhelper.fragment.RecyclerFragment; 18 | import com.zhengsr.tabhelper.rx.HttpCreate; 19 | import com.zhengsr.tablib.bean.TabConfig; 20 | import com.zhengsr.tablib.view.adapter.TabFlowAdapter; 21 | import com.zhengsr.tablib.view.flow.TabVpFlowLayout; 22 | 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | import io.reactivex.android.schedulers.AndroidSchedulers; 27 | import io.reactivex.observers.ResourceObserver; 28 | import io.reactivex.schedulers.Schedulers; 29 | import me.yokeyword.fragmentation.SupportActivity; 30 | 31 | public class NetTestActivity extends BaseActivity { 32 | private static final String TAG = "NetTestActivity"; 33 | private ViewPager mViewPager; 34 | 35 | @SuppressLint("CheckResult") 36 | @Override 37 | protected void onCreate(Bundle savedInstanceState) { 38 | super.onCreate(savedInstanceState); 39 | setContentView(R.layout.activity_net_test); 40 | 41 | final TabVpFlowLayout flowLayout = findViewById(R.id.tabflow); 42 | mViewPager = findViewById(R.id.viewpager); 43 | 44 | mViewPager.setOffscreenPageLimit(3); 45 | final List titles = new ArrayList<>(); 46 | final List fragments = new ArrayList<>(); 47 | 48 | 49 | final TabFlowAdapter adapter ; 50 | 51 | 52 | TabConfig config = new TabConfig.Builder() 53 | .setViewPager(mViewPager) 54 | .setTextId(R.id.item_text) 55 | .setDefaultPos(2) 56 | .setVisibleCount(4) 57 | .build(); 58 | 59 | flowLayout.setAdapter(config,adapter = new TabFlowAdapter(R.layout.item_tab,titles) { 60 | 61 | @Override 62 | public void bindView(View view, String data, int position) { 63 | setDefaultText(view,data); 64 | } 65 | }); 66 | 67 | 68 | HttpCreate.getServer().getTreeKnowledge() 69 | .subscribeOn(Schedulers.io()) 70 | .observeOn(AndroidSchedulers.mainThread()) 71 | .subscribeWith(new ResourceObserver>>() { 72 | @Override 73 | public void onNext(BaseResponse> baseResponse) { 74 | List data = baseResponse.getData(); 75 | // 可以通过 page 获取不同的参数 76 | int page = 1; 77 | for (NaviChildrenBean child : data.get(page).getChildren()) { 78 | String title = child.getName().replaceAll("&","和"); 79 | titles.add(title); 80 | fragments.add(RecyclerFragment.newInstance(child)); 81 | } 82 | mViewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(),fragments)); 83 | //刷新数据 84 | // adapter.notifyDataChanged(); 85 | adapter.notifyDataChanged(); 86 | } 87 | 88 | @Override 89 | public void onError(Throwable e) { 90 | Log.d(TAG, "zsr - onError: "+e); 91 | } 92 | 93 | @Override 94 | public void onComplete() { 95 | 96 | } 97 | }); 98 | 99 | 100 | 101 | 102 | } 103 | 104 | public void test(View view) { 105 | recreate(); 106 | } 107 | 108 | class ViewPagerAdapter extends FragmentPagerAdapter { 109 | List fragments; 110 | public ViewPagerAdapter(FragmentManager fm, List fragments) { 111 | super(fm); 112 | this.fragments = fragments; 113 | } 114 | 115 | @Override 116 | public Fragment getItem(int i) { 117 | return fragments.get(i); 118 | } 119 | 120 | @Override 121 | public int getCount() { 122 | return fragments.size(); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /appx/src/main/java/com/zhengsr/tabhelper/bean/BaseResponse.java: -------------------------------------------------------------------------------- 1 | package com.zhengsr.tabhelper.bean; 2 | 3 | public class BaseResponse { 4 | //自行去定义 5 | public static final int SUCCESS = 0; 6 | private T data; 7 | private int errorCode; 8 | private String errorMsg; 9 | 10 | public T getData() { 11 | return data; 12 | } 13 | 14 | public int getErrorCode() { 15 | return errorCode; 16 | } 17 | 18 | public String getErrorMsg() { 19 | return errorMsg; 20 | } 21 | 22 | public void setData(T data) { 23 | this.data = data; 24 | } 25 | 26 | public void setErrorCode(int errorCode) { 27 | this.errorCode = errorCode; 28 | } 29 | 30 | public void setErrorMsg(String errorMsg) { 31 | this.errorMsg = errorMsg; 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return "BaseResponse{" + 37 | "data=" + data + 38 | ", errorCode=" + errorCode + 39 | ", errorMsg='" + errorMsg + '\'' + 40 | '}'; 41 | } 42 | } -------------------------------------------------------------------------------- /appx/src/main/java/com/zhengsr/tabhelper/bean/NaviChildrenBean.java: -------------------------------------------------------------------------------- 1 | package com.zhengsr.tabhelper.bean; 2 | 3 | import java.io.Serializable; 4 | import java.util.List; 5 | 6 | /** 7 | * @author by zhengshaorui on 2019/10/8 8 | * Describe: 9 | */ 10 | public class NaviChildrenBean implements Serializable { 11 | /** 12 | * children : [] 13 | * courseId : 13 14 | * id : 60 15 | * name : Android Studio相关 16 | * order : 1000 17 | * parentChapterId : 150 18 | * userControlSetTop : false 19 | * visible : 1 20 | */ 21 | 22 | private int courseId; 23 | private int id; 24 | private String name; 25 | private int order; 26 | private int parentChapterId; 27 | private boolean userControlSetTop; 28 | private int visible; 29 | private List children; 30 | 31 | public int getCourseId() { 32 | return courseId; 33 | } 34 | 35 | public void setCourseId(int courseId) { 36 | this.courseId = courseId; 37 | } 38 | 39 | public int getId() { 40 | return id; 41 | } 42 | 43 | public void setId(int id) { 44 | this.id = id; 45 | } 46 | 47 | public String getName() { 48 | return name; 49 | } 50 | 51 | public void setName(String name) { 52 | this.name = name; 53 | } 54 | 55 | public int getOrder() { 56 | return order; 57 | } 58 | 59 | public void setOrder(int order) { 60 | this.order = order; 61 | } 62 | 63 | public int getParentChapterId() { 64 | return parentChapterId; 65 | } 66 | 67 | public void setParentChapterId(int parentChapterId) { 68 | this.parentChapterId = parentChapterId; 69 | } 70 | 71 | public boolean isUserControlSetTop() { 72 | return userControlSetTop; 73 | } 74 | 75 | public void setUserControlSetTop(boolean userControlSetTop) { 76 | this.userControlSetTop = userControlSetTop; 77 | } 78 | 79 | public int getVisible() { 80 | return visible; 81 | } 82 | 83 | public void setVisible(int visible) { 84 | this.visible = visible; 85 | } 86 | 87 | public List getChildren() { 88 | return children; 89 | } 90 | 91 | public void setChildren(List children) { 92 | this.children = children; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /appx/src/main/java/com/zhengsr/tabhelper/bean/PageDataInfo.java: -------------------------------------------------------------------------------- 1 | package com.zhengsr.tabhelper.bean; 2 | 3 | /** 4 | * @author by zhengshaorui on 2019/10/8 5 | * Describe: 6 | */ 7 | public class PageDataInfo { 8 | /** 9 | * curPage : 1 10 | * datas : [] 11 | * offset : 0 12 | * over : false 13 | * pageCount : 377 14 | * size : 20 15 | * total : 7522 16 | */ 17 | private int curPage; 18 | private int offset; 19 | private boolean over; 20 | private int pageCount; 21 | private int size; 22 | private int total; 23 | private T datas; 24 | 25 | public int getCurPage() { 26 | return curPage; 27 | } 28 | 29 | public void setCurPage(int curPage) { 30 | this.curPage = curPage; 31 | } 32 | 33 | public int getOffset() { 34 | return offset; 35 | } 36 | 37 | public void setOffset(int offset) { 38 | this.offset = offset; 39 | } 40 | 41 | public boolean isOver() { 42 | return over; 43 | } 44 | 45 | public void setOver(boolean over) { 46 | this.over = over; 47 | } 48 | 49 | public int getPageCount() { 50 | return pageCount; 51 | } 52 | 53 | public void setPageCount(int pageCount) { 54 | this.pageCount = pageCount; 55 | } 56 | 57 | public int getSize() { 58 | return size; 59 | } 60 | 61 | public void setSize(int size) { 62 | this.size = size; 63 | } 64 | 65 | public int getTotal() { 66 | return total; 67 | } 68 | 69 | public void setTotal(int total) { 70 | this.total = total; 71 | } 72 | 73 | public T getDatas() { 74 | return datas; 75 | } 76 | 77 | public void setDatas(T datas) { 78 | this.datas = datas; 79 | } 80 | 81 | 82 | } 83 | -------------------------------------------------------------------------------- /appx/src/main/java/com/zhengsr/tabhelper/bean/SystematicBean.java: -------------------------------------------------------------------------------- 1 | package com.zhengsr.tabhelper.bean; 2 | 3 | import java.io.Serializable; 4 | import java.util.List; 5 | 6 | /** 7 | * @author by zhengshaorui on 2019/10/8 8 | * Describe: 9 | */ 10 | public class SystematicBean implements Serializable { 11 | 12 | /** 13 | * children : [{"children":[],"courseId":13,"id":60,"name":"Android Studio相关","order":1000,"parentChapterId":150,"userControlSetTop":false,"visible":1},{"children":[],"courseId":13,"id":169,"name":"gradle","order":1001,"parentChapterId":150,"userControlSetTop":false,"visible":1},{"children":[],"courseId":13,"id":269,"name":"官方发布","order":1002,"parentChapterId":150,"userControlSetTop":false,"visible":1}] 14 | * courseId : 13 15 | * id : 150 16 | * name : 开发环境 17 | * order : 1 18 | * parentChapterId : 0 19 | * userControlSetTop : false 20 | * visible : 1 21 | */ 22 | 23 | private int courseId; 24 | private int id; 25 | private String name; 26 | private int order; 27 | private int parentChapterId; 28 | private boolean userControlSetTop; 29 | private int visible; 30 | private List children; 31 | /** 32 | * 拿到所有child的字符 33 | */ 34 | public String childAppendString; 35 | 36 | public int getCourseId() { 37 | return courseId; 38 | } 39 | 40 | public void setCourseId(int courseId) { 41 | this.courseId = courseId; 42 | } 43 | 44 | public int getId() { 45 | return id; 46 | } 47 | 48 | public void setId(int id) { 49 | this.id = id; 50 | } 51 | 52 | public String getName() { 53 | return name; 54 | } 55 | 56 | public void setName(String name) { 57 | this.name = name; 58 | } 59 | 60 | public int getOrder() { 61 | return order; 62 | } 63 | 64 | public void setOrder(int order) { 65 | this.order = order; 66 | } 67 | 68 | public int getParentChapterId() { 69 | return parentChapterId; 70 | } 71 | 72 | public void setParentChapterId(int parentChapterId) { 73 | this.parentChapterId = parentChapterId; 74 | } 75 | 76 | public boolean isUserControlSetTop() { 77 | return userControlSetTop; 78 | } 79 | 80 | public void setUserControlSetTop(boolean userControlSetTop) { 81 | this.userControlSetTop = userControlSetTop; 82 | } 83 | 84 | public int getVisible() { 85 | return visible; 86 | } 87 | 88 | public void setVisible(int visible) { 89 | this.visible = visible; 90 | } 91 | 92 | public List getChildren() { 93 | return children; 94 | } 95 | 96 | public void setChildren(List children) { 97 | this.children = children; 98 | } 99 | 100 | 101 | @Override 102 | public String toString() { 103 | return "SystematicBean{" + 104 | "courseId=" + courseId + 105 | ", id=" + id + 106 | ", name='" + name + '\'' + 107 | ", order=" + order + 108 | ", parentChapterId=" + parentChapterId + 109 | ", userControlSetTop=" + userControlSetTop + 110 | ", visible=" + visible + 111 | ", children=" + children + 112 | ", childAppendString='" + childAppendString + '\'' + 113 | '}'; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /appx/src/main/java/com/zhengsr/tabhelper/fragment/BaseFragment.java: -------------------------------------------------------------------------------- 1 | package com.zhengsr.tabhelper.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.annotation.Nullable; 10 | 11 | import me.yokeyword.fragmentation.SupportFragment; 12 | 13 | /** 14 | * @author by zhengshaorui 2022/2/26 15 | * describe: 16 | */ 17 | public abstract class BaseFragment extends SupportFragment { 18 | 19 | @Nullable 20 | @Override 21 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 22 | View view; 23 | if (getLayoutId() != -1) { 24 | view = inflater.inflate(getLayoutId(), container, false); 25 | initView(view); 26 | }else{ 27 | view = getContentView(); 28 | } 29 | return view; 30 | } 31 | 32 | @Override 33 | public void onLazyInitView(@Nullable Bundle savedInstanceState) { 34 | super.onLazyInitView(savedInstanceState); 35 | initData(); 36 | } 37 | 38 | protected void initData() { 39 | } 40 | 41 | ; 42 | 43 | protected void initView(View view) { 44 | } 45 | 46 | 47 | 48 | public View getContentView(){ 49 | return null; 50 | } 51 | public int getLayoutId() { 52 | return -1; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /appx/src/main/java/com/zhengsr/tabhelper/fragment/CusFragment.java: -------------------------------------------------------------------------------- 1 | package com.zhengsr.tabhelper.fragment; 2 | 3 | import android.graphics.Color; 4 | import android.os.Bundle; 5 | import android.view.Gravity; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.TextView; 10 | 11 | import androidx.annotation.Nullable; 12 | import androidx.fragment.app.Fragment; 13 | 14 | /** 15 | * Created by Administrator on 2017/11/10. 16 | */ 17 | 18 | public class CusFragment extends BaseFragment { 19 | 20 | public static final String ARGUMENT = "argument"; 21 | private String mTitle; 22 | 23 | @Override 24 | public View getContentView() { 25 | Bundle bundle = getArguments(); 26 | 27 | TextView textView = new TextView(getActivity()); 28 | if (bundle != null){ 29 | textView.setText(bundle.getString(ARGUMENT)); 30 | }else{ 31 | textView.setText("nothing here"); 32 | } 33 | textView.setTextSize(30); 34 | textView.setGravity(Gravity.CENTER); 35 | textView.setTextColor(Color.BLACK); 36 | return textView; 37 | } 38 | 39 | 40 | 41 | /** 42 | * 弄一个静态工厂的方法调用 用于传参 43 | * @param key 44 | * @return 45 | */ 46 | public static CusFragment newInStance(String key){ 47 | CusFragment fragment = new CusFragment(); 48 | Bundle bundle = new Bundle(); 49 | bundle.putString(ARGUMENT,key); 50 | fragment.setArguments(bundle); 51 | return fragment; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /appx/src/main/java/com/zhengsr/tabhelper/fragment/RecyclerFragment.java: -------------------------------------------------------------------------------- 1 | package com.zhengsr.tabhelper.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.text.TextUtils; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import androidx.annotation.NonNull; 10 | import androidx.annotation.Nullable; 11 | import androidx.recyclerview.widget.LinearLayoutManager; 12 | import androidx.recyclerview.widget.RecyclerView; 13 | 14 | import com.chad.library.adapter.base.BaseQuickAdapter; 15 | import com.chad.library.adapter.base.viewholder.BaseViewHolder; 16 | import com.zhengsr.tabhelper.R; 17 | import com.zhengsr.tabhelper.bean.ArticleData; 18 | import com.zhengsr.tabhelper.bean.BaseResponse; 19 | import com.zhengsr.tabhelper.bean.NaviChildrenBean; 20 | import com.zhengsr.tabhelper.bean.PageDataInfo; 21 | import com.zhengsr.tabhelper.rx.HttpCreate; 22 | import com.zhengsr.tabhelper.utils.RxUtils; 23 | 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | 27 | import io.reactivex.Observer; 28 | import io.reactivex.disposables.Disposable; 29 | import me.yokeyword.fragmentation.SupportFragment; 30 | 31 | /** 32 | * @author by zhengshaorui on 2019/10/8 33 | * Describe: 34 | */ 35 | public class RecyclerFragment extends BaseFragment { 36 | private static final String TAG = "RecyclerFragment"; 37 | private NaviChildrenBean mBean; 38 | private ArticleAdapter mAdapter; 39 | private List mArticleBeans = new ArrayList<>(); 40 | public static RecyclerFragment newInstance(NaviChildrenBean bean) { 41 | 42 | Bundle args = new Bundle(); 43 | args.putSerializable("bean",bean); 44 | RecyclerFragment fragment = new RecyclerFragment(); 45 | fragment.setArguments(args); 46 | return fragment; 47 | } 48 | 49 | @Override 50 | public int getLayoutId() { 51 | return R.layout.recycler_layout; 52 | } 53 | @Override 54 | public void initView(View view) { 55 | Bundle arguments = getArguments(); 56 | mBean = (NaviChildrenBean) arguments.getSerializable("bean"); 57 | 58 | RecyclerView recyclerView = view.findViewById(R.id.recycler); 59 | LinearLayoutManager manager = new LinearLayoutManager(getContext()); 60 | recyclerView.setLayoutManager(manager); 61 | mAdapter = new ArticleAdapter(R.layout.item_article_recy_layout, mArticleBeans); 62 | recyclerView.setAdapter(mAdapter); 63 | 64 | 65 | 66 | 67 | } 68 | 69 | @Override 70 | protected void initData() { 71 | super.initData(); 72 | HttpCreate.getServer().getSystematicDetail(0,mBean.getId()) 73 | .compose(RxUtils.>>>rxScheduers()) 74 | .subscribe(new Observer>>>() { 75 | @Override 76 | public void onSubscribe(Disposable d) { 77 | 78 | } 79 | 80 | @Override 81 | public void onNext(BaseResponse>> pageDataInfoBaseResponse) { 82 | PageDataInfo> data = pageDataInfoBaseResponse.getData(); 83 | List datas = data.getDatas(); 84 | mAdapter.setNewData(datas); 85 | } 86 | 87 | @Override 88 | public void onError(Throwable e) { 89 | 90 | } 91 | 92 | @Override 93 | public void onComplete() { 94 | 95 | } 96 | }); 97 | } 98 | 99 | 100 | 101 | 102 | 103 | public class ArticleAdapter extends BaseQuickAdapter { 104 | 105 | private boolean isCollected = false; 106 | 107 | public ArticleAdapter(int layoutResId, @Nullable List data) { 108 | super(layoutResId, data); 109 | } 110 | 111 | public void setCollected(boolean collected) { 112 | isCollected = collected; 113 | } 114 | 115 | 116 | 117 | @Override 118 | protected void convert(BaseViewHolder helper, ArticleData item) { 119 | String msg; 120 | if (!TextUtils.isEmpty(item.getSuperChapterName())){ 121 | msg = item.getSuperChapterName()+"/"+item.getChapterName(); 122 | }else{ 123 | msg = item.getChapterName(); 124 | } 125 | String author = (item.getAuthor() != null && item.getAuthor().length() > 0) ? item.getAuthor():item.getShareUser(); 126 | helper.setText(R.id.item_article_author,author) 127 | .setText(R.id.item_article_chapat, msg) 128 | .setText(R.id.item_article_title,item.getTitle()) 129 | .setText(R.id.item_article_time,item.getNiceDate()); 130 | 131 | } 132 | 133 | 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /appx/src/main/java/com/zhengsr/tabhelper/fragment/TestFragment.java: -------------------------------------------------------------------------------- 1 | package com.zhengsr.tabhelper.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import androidx.annotation.Nullable; 9 | import androidx.fragment.app.Fragment; 10 | 11 | import com.zhengsr.tabhelper.R; 12 | import com.zhengsr.tablib.view.adapter.TabFlowAdapter; 13 | import com.zhengsr.tablib.view.flow.TabFlowLayout; 14 | 15 | import java.util.ArrayList; 16 | import java.util.Arrays; 17 | import java.util.List; 18 | 19 | /** 20 | * Created by Administrator on 2017/11/10. 21 | */ 22 | 23 | public class TestFragment extends BaseFragment { 24 | 25 | public static final String ARGUMENT = "argument"; 26 | private List mTitle = new ArrayList<>(Arrays.asList("Life is like an ocean Only strong willed people can reach the other side".split(" "))); 27 | 28 | 29 | @Override 30 | public int getLayoutId() { 31 | return R.layout.test_fragment; 32 | } 33 | 34 | @Override 35 | protected void initView(View view) { 36 | super.initView(view); 37 | TabFlowLayout tabFlowLayout = view.findViewById(R.id.tabflow); 38 | tabFlowLayout.setAdapter(new TabFlowAdapter(R.layout.item_msg,mTitle) { 39 | @Override 40 | public void bindView(View view, String data, int position) { 41 | setDefaultText(view,data); 42 | } 43 | 44 | 45 | }); 46 | } 47 | 48 | /** 49 | * 弄一个静态工厂的方法调用 用于传参 50 | * @return 51 | */ 52 | public static TestFragment newInStance(){ 53 | TestFragment fragment = new TestFragment(); 54 | Bundle bundle = new Bundle(); 55 | fragment.setArguments(bundle); 56 | return fragment; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /appx/src/main/java/com/zhengsr/tabhelper/rx/HttpCreate.java: -------------------------------------------------------------------------------- 1 | package com.zhengsr.tabhelper.rx; 2 | 3 | 4 | import java.util.concurrent.TimeUnit; 5 | 6 | import okhttp3.OkHttpClient; 7 | import retrofit2.Retrofit; 8 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; 9 | import retrofit2.converter.fastjson.FastJsonConverterFactory; 10 | import retrofit2.converter.scalars.ScalarsConverterFactory; 11 | 12 | /** 13 | * @author by zhengshaorui on 2019/10/9 14 | * Describe: 网络生成类 15 | */ 16 | public class HttpCreate { 17 | 18 | public static HttpServerApi getServer(){ 19 | Retrofit retrofit = new Retrofit.Builder() 20 | //这里采用这个,因为有多个baseurl 21 | .baseUrl("https://www.wanandroid.com/") 22 | //转字符串 23 | .addConverterFactory(ScalarsConverterFactory.create()) 24 | //fastjson 25 | .addConverterFactory(FastJsonConverterFactory.create()) 26 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) 27 | .client(OkHttpHolder.BUILDER) 28 | .build(); 29 | return retrofit.create(HttpServerApi.class); 30 | } 31 | 32 | /** 33 | * 配置okhttp3 client 34 | */ 35 | 36 | private static class OkHttpHolder{ 37 | static OkHttpClient BUILDER = new OkHttpClient.Builder() 38 | .connectTimeout(10, TimeUnit.SECONDS) 39 | .build(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /appx/src/main/java/com/zhengsr/tabhelper/rx/HttpServerApi.java: -------------------------------------------------------------------------------- 1 | package com.zhengsr.tabhelper.rx; 2 | 3 | 4 | import com.zhengsr.tabhelper.bean.ArticleData; 5 | import com.zhengsr.tabhelper.bean.BaseResponse; 6 | import com.zhengsr.tabhelper.bean.NaviBean; 7 | import com.zhengsr.tabhelper.bean.PageDataInfo; 8 | import com.zhengsr.tabhelper.bean.SystematicBean; 9 | 10 | import java.util.List; 11 | 12 | import io.reactivex.Observable; 13 | import retrofit2.http.GET; 14 | import retrofit2.http.Path; 15 | import retrofit2.http.Query; 16 | import retrofit2.http.Url; 17 | 18 | /** 19 | * @author by zhengshaorui on 2019/10/9 20 | * Describe: 统一网络服务接口类 21 | */ 22 | public interface HttpServerApi { 23 | @GET 24 | Observable getJson(@Url String url); 25 | 26 | 27 | 28 | /** 29 | * 获取体系 30 | * https://www.wanandroid.com/tree/json 31 | */ 32 | @GET("tree/json") 33 | Observable>> getTreeKnowledge(); 34 | 35 | /** 36 | * 获取系列的具体内容 37 | * https://www.wanandroid.com/article/list/0/json?cid=60 38 | * 39 | */ 40 | @GET("article/list/{page}/json") 41 | Observable>>> getSystematicDetail(@Path("page") int page, @Query("cid") int cid); 42 | 43 | 44 | 45 | 46 | /** 47 | * https://www.wanandroid.com/navi/json 48 | * 获取导航数据 49 | */ 50 | @GET("navi/json") 51 | Observable>> getNaviData(); 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /appx/src/main/java/com/zhengsr/tabhelper/utils/RxUtils.java: -------------------------------------------------------------------------------- 1 | package com.zhengsr.tabhelper.utils; 2 | 3 | 4 | import org.reactivestreams.Publisher; 5 | 6 | import io.reactivex.Flowable; 7 | import io.reactivex.FlowableTransformer; 8 | import io.reactivex.Observable; 9 | import io.reactivex.ObservableEmitter; 10 | import io.reactivex.ObservableOnSubscribe; 11 | import io.reactivex.ObservableSource; 12 | import io.reactivex.ObservableTransformer; 13 | import io.reactivex.android.schedulers.AndroidSchedulers; 14 | import io.reactivex.schedulers.Schedulers; 15 | 16 | /** 17 | * @author by zhengshaorui on 2019/10/9 18 | * Describe: 19 | */ 20 | public class RxUtils { 21 | /** 22 | * 封装线程调度 23 | * @param 24 | * @return 25 | */ 26 | public static ObservableTransformer rxScheduers(){ 27 | return new ObservableTransformer(){ 28 | 29 | @Override 30 | public ObservableSource apply(Observable upstream) { 31 | return upstream.subscribeOn(Schedulers.io()) 32 | .observeOn(AndroidSchedulers.mainThread()); 33 | } 34 | }; 35 | } 36 | 37 | 38 | public static FlowableTransformer flScheduers(){ 39 | return new FlowableTransformer() { 40 | @Override 41 | public Publisher apply(Flowable upstream) { 42 | return upstream.subscribeOn(Schedulers.io()) 43 | .observeOn(AndroidSchedulers.mainThread()); 44 | } 45 | }; 46 | } 47 | 48 | 49 | 50 | 51 | /** 52 | * 得到 Observable 53 | * @param 指定的泛型类型 54 | * @return Observable 55 | */ 56 | private static Observable createData(final T t) { 57 | return Observable.create(new ObservableOnSubscribe() { 58 | @Override 59 | public void subscribe(ObservableEmitter emitter) throws Exception { 60 | emitter.onNext(t); 61 | emitter.onComplete(); 62 | } 63 | }); 64 | } 65 | 66 | 67 | } 68 | -------------------------------------------------------------------------------- /appx/src/main/res/color/color_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /appx/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /appx/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /appx/src/main/res/drawable/select_tag.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /appx/src/main/res/drawable/shape_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /appx/src/main/res/drawable/shape_red_radius.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /appx/src/main/res/drawable/shape_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /appx/src/main/res/drawable/shape_round_ff.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /appx/src/main/res/drawable/shape_round_trans.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /appx/src/main/res/drawable/shape_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /appx/src/main/res/drawable/shape_search_select.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /appx/src/main/res/drawable/shape_showmore.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | -------------------------------------------------------------------------------- /appx/src/main/res/layout/activity_count.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 30 | 31 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /appx/src/main/res/layout/activity_label.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 17 | 25 | 26 | 32 | 33 |