├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── chilanka.otf │ ├── java │ └── github │ │ └── xuqk │ │ └── kdtablayout │ │ └── sample │ │ ├── BadgeTabActivity.kt │ │ ├── CustomTabActivity.kt │ │ ├── DynamicTabActivity.kt │ │ ├── Ext.kt │ │ ├── FixedTabActivity.kt │ │ ├── MainActivity.kt │ │ ├── OnlyIndicatorActivity.kt │ │ ├── ScrollableTabActivity.kt │ │ ├── adapter │ │ ├── ViewPager2Adapter.kt │ │ └── ViewPagerAdapter.kt │ │ └── widget │ │ ├── CustomFontTab.kt │ │ ├── ShadowGradientTab.kt │ │ └── TextViewTab.kt │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ ├── bg_round_stroke_r24.xml │ └── ic_launcher_background.xml │ ├── layout │ ├── activity_badge_tab.xml │ ├── activity_custom_tab.xml │ ├── activity_dynamic_tab.xml │ ├── activity_fixed_tab.xml │ ├── activity_main.xml │ ├── activity_only_indicator.xml │ └── activity_scrollable_tab.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── demo.gif ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── jitpack.yml ├── kdtablayout ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ └── main │ └── java │ └── github │ └── xuqk │ └── kdtablayout │ ├── Ext.kt │ ├── KDTabAdapter.kt │ ├── KDTabLayout.kt │ ├── KDViewPagerHelper.kt │ └── widget │ ├── KDBadge.kt │ ├── KDTab.kt │ ├── KDTabIndicator.kt │ ├── badge │ ├── KDContentEndRelativeBadge.kt │ ├── KDNumberBadge.kt │ └── KDTabEndRelativeBadge.kt │ ├── indicator │ ├── DotMorphingIndicator.kt │ ├── DotWithStrokeIndicator.kt │ └── KDRecIndicator.kt │ └── tab │ ├── KDColorClipTextTab.kt │ ├── KDColorMorphingTextTab.kt │ └── KDSizeMorphingTextTab.kt └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | 16 | 17 | 18 | # Created by https://www.gitignore.io/api/androidstudio 19 | 20 | ### AndroidStudio ### 21 | # Covers files to be ignored for android development using Android Studio. 22 | 23 | # Built application files 24 | *.apk 25 | *.ap_ 26 | 27 | # Files for the ART/Dalvik VM 28 | *.dex 29 | 30 | # Java class files 31 | *.class 32 | 33 | # Generated files 34 | bin/ 35 | gen/ 36 | out/ 37 | 38 | # Gradle files 39 | .gradle 40 | .gradle/ 41 | build/ 42 | 43 | # Signing files 44 | .signing/ 45 | 46 | # Local configuration file (sdk path, etc) 47 | local.properties 48 | 49 | # Proguard folder generated by Eclipse 50 | proguard/ 51 | 52 | # Log Files 53 | *.log 54 | 55 | # Android Studio 56 | /*/build/ 57 | /*/local.properties 58 | /*/out 59 | /*/*/build 60 | /*/*/production 61 | captures/ 62 | .navigation/ 63 | *.ipr 64 | *~ 65 | *.swp 66 | 67 | # Android Patch 68 | gen-external-apklibs 69 | 70 | # External native build folder generated in Android Studio 2.2 and later 71 | .externalNativeBuild 72 | 73 | # NDK 74 | obj/ 75 | 76 | # IntelliJ IDEA 77 | *.iml 78 | *.iws 79 | /out/ 80 | 81 | # User-specific configurations 82 | .idea/ 83 | 84 | # OS-specific files 85 | .DS_Store 86 | .DS_Store? 87 | ._* 88 | .Spotlight-V100 89 | .Trashes 90 | ehthumbs.db 91 | Thumbs.db 92 | 93 | # Legacy Eclipse project files 94 | .classpath 95 | .project 96 | .cproject 97 | .settings/ 98 | 99 | # Mobile Tools for Java (J2ME) 100 | .mtj.tmp/ 101 | 102 | # Package Files # 103 | *.war 104 | *.ear 105 | 106 | # virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml) 107 | hs_err_pid* 108 | 109 | ## Plugin-specific files: 110 | 111 | # mpeltonen/sbt-idea plugin 112 | .idea_modules/ 113 | 114 | # JIRA plugin 115 | atlassian-ide-plugin.xml 116 | 117 | # Mongo Explorer plugin 118 | .idea/mongoSettings.xml 119 | 120 | # Crashlytics plugin (for Android Studio and IntelliJ) 121 | com_crashlytics_export_strings.xml 122 | crashlytics.properties 123 | crashlytics-build.properties 124 | fabric.properties 125 | 126 | ### AndroidStudio Patch ### 127 | 128 | !/gradle/wrapper/gradle-wrapper.jar 129 | 130 | 131 | # End of https://www.gitignore.io/api/androidstudio 132 | 133 | # bugly 134 | /*/bugly 135 | 136 | # gradle profile reports 137 | /reports -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 KongKong 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![](https://jitpack.io/v/XuQK/KDTabLayout.svg)](https://jitpack.io/#XuQK/KDTabLayout) 2 | 3 | 一直感觉[MagicIndicator](https://github.com/hackware1993/MagicIndicator)这个库相当牛逼,在自己的工作过程中也帮我解决了很多问题,无奈作者志向高远,已经转行不写代码了,所以我参考了一下该库,自己撸了一个TabLayout。 4 | 5 | 本TabLayout直接继承自ViewGroup,默认实现了一些简单的效果,也留出了接口供用户自定义单个Tab,Indicator,Badge等控件,可以和ViewPager2和ViewPager搭配使用。 6 | 7 | 效果图: 8 | 9 | ![](demo.gif) 10 | 11 | # 使用方式: 12 | 13 | ## 将JitPack存储库添加到构建文件(项目根目录下build.gradle文件) 14 | 15 | ```groovy 16 | allprojects { 17 | repositories { 18 | ... 19 | maven { url 'https://jitpack.io' } 20 | } 21 | } 22 | ``` 23 | 24 | ## 添加依赖项 25 | 26 | ```groovy 27 | // 版本号参看Release 28 | implementation 'com.github.XuQK:KDTabLayout:versionCode' 29 | 30 | // 如果要使用ViewPager2,请添加ViewPager2库 31 | implementation 'androidx.viewpager2:viewpager2:versionCode' 32 | ``` 33 | 34 | ## 使用说明 35 | 36 | ### 简单使用 37 | 38 | 1. 将KDTabLayout添加到你的布局文件中 39 | 40 | 2. 为KDTabLayout配置Adapter 41 | 42 | ```kotlin 43 | // KDTabLayout本身主要有tabMode和scrollBiasX两个属性可设置,具体见类field注释,默认是TAB_MODE_FLEXIBLE 44 | tab2.tabMode = KDTabLayout.TAB_MODE_SCROLLABLE 45 | tabLayout.contentAdapter = object : KDTabAdapter() { 46 | override fun createTab(position: Int): KDTab? { 47 | // 如果该方法返回null,则TabLayout只会绘制Indicator 48 | // 这是一个Tab中文字颜色和大小会随滚动进度变化的Tab 49 | return KDColorMorphingTextTab(context, data[position]).apply { 50 | horizontalPadding = 16f 51 | selectedTextColor = Color.parseColor("#ff5722") 52 | normalTextColor = Color.parseColor("#9e9e9e") 53 | setOnClickListener { 54 | viewPager2.currentItem = position 55 | } 56 | } 57 | } 58 | 59 | override fun createIndicator(): KDTabIndicator? { 60 | // 如果该方法返回null,则TabLayout不会绘制Indicator 61 | // 这是一个普通的矩形Indicator 62 | return KDRecIndicator(tab2).apply { 63 | indicatorHeight = 6f 64 | color = 0xffff5722.toInt() 65 | cornerRadius = 3f 66 | mode = KDRecIndicator.MODE_EXACT 67 | indicatorWidth = 16f 68 | startInterpolator = AccelerateInterpolator() 69 | endInterpolator = DecelerateInterpolator(2f) 70 | } 71 | } 72 | 73 | override fun getTabCount(): Int { 74 | return ZH.size 75 | } 76 | } 77 | 78 | // 与ViewPager2联动 79 | tabLayout.setViewPager2(viewPager2) 80 | // 与ViewPager联动 81 | tabLayout.setViewPager(viewPager) 82 | ``` 83 | 84 | 以上配置后,即可顺利使用。 85 | 86 | ### 自定义Tab 87 | 88 | 只需继承`KDTab`,然后根据需要重写其中方法即可 89 | 90 | ```kotlin 91 | class XTab(context: Context) : KDTab(context) { 92 | /** 93 | * @param selectedFraction 该Tab被选中的比例,即滚动完成度 94 | * @param selectedInLeft 该Tab是否是从左边滚动到右边 95 | */ 96 | override fun onScrolling(selectedFraction: Float, selectedInLeft: Boolean) { 97 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 98 | } 99 | 100 | /** 101 | * 重置为初始状态 102 | */ 103 | override fun reset() { 104 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 105 | } 106 | 107 | /** 108 | * 设置为选中状态 109 | */ 110 | override fun selectTab() { 111 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 112 | } 113 | 114 | /** 115 | * 计算内容尺寸 116 | */ 117 | override fun computeContentBounds() { 118 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 119 | } 120 | } 121 | ``` 122 | 123 | ### 自定义Indicator 124 | 125 | 只需继承`KDTabIndicator`,根据需要重写其中方法即可 126 | 127 | ```kotlin 128 | class XIndicator(tabLayout: KDTabLayout) : KDTabIndicator(tabLayout) { 129 | /** 130 | * 初始化方法,在TabLayout布局尺寸改变,或adapter重新设置后会调用 131 | */ 132 | override fun init() { 133 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 134 | } 135 | 136 | /** 137 | * 此方法参数都是以滚动方向为参照 138 | */ 139 | override fun onTabScrolled(startItem: Int, endItem: Int, scrolledFraction: Float) { 140 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 141 | } 142 | 143 | override fun draw(canvas: Canvas) { 144 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 145 | } 146 | 147 | /** 148 | * 获取Indicator占用的宽度 149 | * 此方法在且仅在Indicator单独使用时需要实现 150 | */ 151 | override fun getWidth(): Int { 152 | return 0 153 | } 154 | 155 | /** 156 | * 获取Indicator占用的高度 157 | * 此方法在且仅在Indicator单独使用时需要实现 158 | */ 159 | override fun getHeight(): Int { 160 | return 0 161 | } 162 | } 163 | ``` -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | apply plugin: 'kotlin-android' 4 | 5 | android { 6 | namespace 'github.xuqk.kdtablayout.sample' 7 | compileSdkVersion 32 8 | defaultConfig { 9 | applicationId "github.xuqk.kdtablayout.demo" 10 | minSdkVersion 21 11 | targetSdkVersion 32 12 | versionCode 1 13 | versionName "1.0" 14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | 23 | viewBinding { 24 | enabled = true 25 | } 26 | } 27 | 28 | dependencies { 29 | implementation fileTree(dir: 'libs', include: ['*.jar']) 30 | implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" 31 | implementation 'androidx.appcompat:appcompat:1.4.1' 32 | implementation 'androidx.core:core-ktx:1.7.0' 33 | implementation 'androidx.constraintlayout:constraintlayout:2.1.3' 34 | 35 | implementation project(':kdtablayout') 36 | // releaseImplementation 'com.github.XuQK:KDTabLayout:1.1.2' 37 | 38 | implementation 'androidx.viewpager2:viewpager2:1.0.0' 39 | 40 | } 41 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 28 | 31 | 34 | 37 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/assets/chilanka.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XuQK/KDTabLayout/d78ab6eb89205cfa841d78dd2e37eabc93f492fd/app/src/main/assets/chilanka.otf -------------------------------------------------------------------------------- /app/src/main/java/github/xuqk/kdtablayout/sample/BadgeTabActivity.kt: -------------------------------------------------------------------------------- 1 | package github.xuqk.kdtablayout.sample 2 | 3 | import android.graphics.Color 4 | import android.os.Bundle 5 | import android.view.animation.DecelerateInterpolator 6 | import androidx.appcompat.app.AppCompatActivity 7 | import androidx.viewpager2.widget.ViewPager2 8 | import github.xuqk.kdtablayout.KDTabAdapter 9 | import github.xuqk.kdtablayout.KDTabLayout 10 | import github.xuqk.kdtablayout.sample.adapter.ViewPager2Adapter 11 | import github.xuqk.kdtablayout.sample.databinding.ActivityBadgeTabBinding 12 | import github.xuqk.kdtablayout.widget.KDTab 13 | import github.xuqk.kdtablayout.widget.KDTabIndicator 14 | import github.xuqk.kdtablayout.widget.badge.KDContentEndRelativeBadge 15 | import github.xuqk.kdtablayout.widget.badge.KDTabEndRelativeBadge 16 | import github.xuqk.kdtablayout.widget.indicator.KDRecIndicator 17 | import github.xuqk.kdtablayout.widget.tab.KDColorMorphingTextTab 18 | 19 | /** 20 | * Created By:XuQK 21 | * Created Date:2/23/20 6:08 PM 22 | * Creator Email:xuqiankun66@gmail.com 23 | * Description: 24 | */ 25 | class BadgeTabActivity : AppCompatActivity() { 26 | 27 | private lateinit var binding: ActivityBadgeTabBinding 28 | 29 | override fun onCreate(savedInstanceState: Bundle?) { 30 | super.onCreate(savedInstanceState) 31 | binding = ActivityBadgeTabBinding.inflate(layoutInflater) 32 | setContentView(binding.root) 33 | 34 | val data = ZH.copyOfRange(0, 3) 35 | 36 | binding.tab0.tabMode = KDTabLayout.TAB_MODE_SPREAD 37 | binding.tab0.contentAdapter = object : KDTabAdapter() { 38 | override fun createTab(position: Int): KDTab? { 39 | return KDColorMorphingTextTab(this@BadgeTabActivity, data[position]).apply { 40 | weight = position + 2 41 | selectedTextColor = Color.parseColor("#ff5722") 42 | normalTextColor = Color.parseColor("#9e9e9e") 43 | selectedTextSize = 18f 44 | normalTextSize = 14f 45 | selectedBold = true 46 | setOnClickListener { 47 | binding.vp2.currentItem = position 48 | } 49 | 50 | badge = KDTabEndRelativeBadge(this).apply { 51 | count = position 52 | showCount = true 53 | size = 12f 54 | marginEnd = 12f 55 | marginTop = 12f 56 | } 57 | } 58 | } 59 | 60 | override fun createIndicator(): KDTabIndicator? { 61 | return KDRecIndicator(binding.tab0).apply { 62 | indicatorHeight = 4f 63 | color = 0xffff5722.toInt() 64 | mode = KDRecIndicator.MODE_MATCH 65 | endInterpolator = DecelerateInterpolator(2f) 66 | } 67 | } 68 | 69 | override fun getTabCount(): Int { 70 | return data.size 71 | } 72 | } 73 | 74 | binding.tab1.tabMode = KDTabLayout.TAB_MODE_PACK 75 | binding.tab1.contentAdapter = object : KDTabAdapter() { 76 | override fun createTab(position: Int): KDTab? { 77 | return KDColorMorphingTextTab(this@BadgeTabActivity, data[position]).apply { 78 | horizontalPadding = 12f 79 | selectedTextColor = Color.parseColor("#039be5") 80 | normalTextColor = Color.parseColor("#9e9e9e") 81 | setOnClickListener { 82 | binding.vp2.currentItem = position 83 | badge?.dismiss() 84 | } 85 | 86 | badge = KDContentEndRelativeBadge(this).apply { 87 | count = position 88 | showCount = true 89 | size = 12f 90 | } 91 | } 92 | } 93 | 94 | override fun createIndicator(): KDTabIndicator? { 95 | return KDRecIndicator(binding.tab1).apply { 96 | indicatorHeight = 4f 97 | color = 0xff039be5.toInt() 98 | mode = KDRecIndicator.MODE_MATCH 99 | endInterpolator = DecelerateInterpolator(2f) 100 | } 101 | } 102 | 103 | override fun getTabCount(): Int { 104 | return data.size 105 | } 106 | } 107 | 108 | binding.tab0.setViewPager2(binding.vp2) 109 | binding.tab1.setViewPager2(binding.vp2) 110 | binding.vp2.adapter = ViewPager2Adapter(data.toMutableList()) 111 | binding.vp2.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { 112 | override fun onPageSelected(position: Int) { 113 | binding.tab0.getTab(position)?.badge?.dismiss() 114 | } 115 | }) 116 | } 117 | } -------------------------------------------------------------------------------- /app/src/main/java/github/xuqk/kdtablayout/sample/CustomTabActivity.kt: -------------------------------------------------------------------------------- 1 | package github.xuqk.kdtablayout.sample 2 | 3 | import android.graphics.Color 4 | import android.os.Bundle 5 | import androidx.appcompat.app.AppCompatActivity 6 | import github.xuqk.kdtablayout.KDTabAdapter 7 | import github.xuqk.kdtablayout.KDTabLayout 8 | import github.xuqk.kdtablayout.sample.adapter.ViewPager2Adapter 9 | import github.xuqk.kdtablayout.sample.databinding.ActivityCustomTabBinding 10 | import github.xuqk.kdtablayout.sample.widget.ShadowGradientTab 11 | import github.xuqk.kdtablayout.widget.KDTab 12 | import github.xuqk.kdtablayout.widget.KDTabIndicator 13 | 14 | /** 15 | * Created By:XuQK 16 | * Created Date:2/29/20 9:44 PM 17 | * Creator Email:xuqiankun66@gmail.com 18 | * Description: 19 | */ 20 | class CustomTabActivity : AppCompatActivity() { 21 | 22 | private lateinit var binding: ActivityCustomTabBinding 23 | 24 | override fun onCreate(savedInstanceState: Bundle?) { 25 | super.onCreate(savedInstanceState) 26 | binding = ActivityCustomTabBinding.inflate(layoutInflater) 27 | setContentView(binding.root) 28 | 29 | val data = ZH.copyOfRange(0, 4) 30 | 31 | binding.tab0.tabMode = KDTabLayout.TAB_MODE_SPREAD 32 | binding.tab0.contentAdapter = object : KDTabAdapter() { 33 | override fun createTab(position: Int): KDTab? { 34 | return ShadowGradientTab(this@CustomTabActivity, data[position]).apply { 35 | selectedTextColor = Color.WHITE 36 | normalTextColor = 0xFFBDC1C9.toInt() 37 | selectedTextSize = 16f 38 | normalTextSize = 12f 39 | setOnClickListener { 40 | binding.vp2.currentItem = position 41 | } 42 | } 43 | } 44 | 45 | override fun createIndicator(): KDTabIndicator? { 46 | return null 47 | } 48 | 49 | override fun getTabCount(): Int { 50 | return data.size 51 | } 52 | } 53 | 54 | binding.tab0.setViewPager2(binding.vp2) 55 | binding.vp2.adapter = ViewPager2Adapter(data.toMutableList()) 56 | } 57 | } -------------------------------------------------------------------------------- /app/src/main/java/github/xuqk/kdtablayout/sample/DynamicTabActivity.kt: -------------------------------------------------------------------------------- 1 | package github.xuqk.kdtablayout.sample 2 | 3 | import android.os.Bundle 4 | import androidx.appcompat.app.AppCompatActivity 5 | import github.xuqk.kdtablayout.KDTabAdapter 6 | import github.xuqk.kdtablayout.sample.adapter.ViewPager2Adapter 7 | import github.xuqk.kdtablayout.sample.databinding.ActivityDynamicTabBinding 8 | import github.xuqk.kdtablayout.widget.KDTab 9 | import github.xuqk.kdtablayout.widget.KDTabIndicator 10 | import github.xuqk.kdtablayout.widget.indicator.KDRecIndicator 11 | import github.xuqk.kdtablayout.widget.tab.KDColorClipTextTab 12 | import java.util.* 13 | 14 | /** 15 | * Created By:XuQK 16 | * Created Date:2/23/20 5:23 PM 17 | * Creator Email:xuqiankun66@gmail.com 18 | * Description: 19 | */ 20 | class DynamicTabActivity : AppCompatActivity() { 21 | 22 | private lateinit var binding: ActivityDynamicTabBinding 23 | 24 | override fun onCreate(savedInstanceState: Bundle?) { 25 | super.onCreate(savedInstanceState) 26 | binding = ActivityDynamicTabBinding.inflate(layoutInflater) 27 | setContentView(binding.root) 28 | 29 | val data = mutableListOf() 30 | data.addAll(ZH) 31 | 32 | binding.vp2.adapter = ViewPager2Adapter(data) 33 | 34 | binding.tab.setViewPager2(binding.vp2) 35 | binding.tab.contentAdapter = object : KDTabAdapter() { 36 | override fun createTab(position: Int): KDTab? { 37 | return KDColorClipTextTab(this@DynamicTabActivity, data[position]).apply { 38 | horizontalPadding = 16f 39 | selectedTextSize = 22f 40 | normalTextSize = 16f 41 | setOnClickListener { 42 | binding.vp2.currentItem = position 43 | } 44 | } 45 | } 46 | 47 | override fun createIndicator(): KDTabIndicator? { 48 | return KDRecIndicator(binding.tab).apply { 49 | indicatorHeight = 4f 50 | color = 0x4cff0000 51 | marginBottom = 4f 52 | cornerRadius = 2f 53 | mode = KDRecIndicator.MODE_MATCH 54 | } 55 | } 56 | 57 | override fun getTabCount(): Int { 58 | return data.size 59 | } 60 | } 61 | 62 | binding.btn.setOnClickListener { 63 | var n = Random().nextInt(ZH.size + 1) 64 | if (n == 0) n = ZH.size 65 | val newData = ZH.copyOfRange(0, n) 66 | data.clear() 67 | data.addAll(newData) 68 | 69 | binding.vp2.adapter!!.notifyDataSetChanged() 70 | binding.tab.init() 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /app/src/main/java/github/xuqk/kdtablayout/sample/Ext.kt: -------------------------------------------------------------------------------- 1 | package github.xuqk.kdtablayout.sample 2 | 3 | import android.content.Context 4 | import android.util.TypedValue 5 | 6 | /** 7 | * Created By:XuQK 8 | * Created Date:2/23/20 4:11 PM 9 | * Creator Email:xuqiankun66@gmail.com 10 | * Description: 11 | */ 12 | 13 | fun dpToPx(context: Context, dp: Float): Int { 14 | return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.resources.displayMetrics).toInt() 15 | } 16 | 17 | val ZH = arrayOf( 18 | "纸杯蛋糕", 19 | "甜甜圈", 20 | "闪电泡芙", 21 | "优格冰淇淋", 22 | "姜饼", 23 | "蜂巢", 24 | "冰淇淋三明治", 25 | "雷根糖", 26 | "奇巧巧克力", 27 | "棒棒糖", 28 | "棉花糖", 29 | "牛轧糖", 30 | "奥利奥", 31 | "派") 32 | 33 | val EN = arrayOf( 34 | "Cupcake", 35 | "Donut", 36 | "Eclair", 37 | "Froyo", 38 | "Gingerbread", 39 | "Honeycomb", 40 | "Ice Cream Sandwich", 41 | "Jelly Bean", 42 | "KitKat", 43 | "Lollipop", 44 | "Marshmallow", 45 | "Nougat", 46 | "Oreo", 47 | "Pie") -------------------------------------------------------------------------------- /app/src/main/java/github/xuqk/kdtablayout/sample/FixedTabActivity.kt: -------------------------------------------------------------------------------- 1 | package github.xuqk.kdtablayout.sample 2 | 3 | import android.graphics.Color 4 | import android.os.Bundle 5 | import android.view.animation.DecelerateInterpolator 6 | import androidx.appcompat.app.AppCompatActivity 7 | import github.xuqk.kdtablayout.KDTabAdapter 8 | import github.xuqk.kdtablayout.KDTabLayout 9 | import github.xuqk.kdtablayout.sample.adapter.ViewPagerAdapter 10 | import github.xuqk.kdtablayout.sample.databinding.ActivityFixedTabBinding 11 | import github.xuqk.kdtablayout.sample.widget.TextViewTab 12 | import github.xuqk.kdtablayout.widget.KDTab 13 | import github.xuqk.kdtablayout.widget.KDTabIndicator 14 | import github.xuqk.kdtablayout.widget.indicator.KDRecIndicator 15 | import github.xuqk.kdtablayout.widget.tab.KDColorClipTextTab 16 | import github.xuqk.kdtablayout.widget.tab.KDColorMorphingTextTab 17 | 18 | /** 19 | * Created By:XuQK 20 | * Created Date:2/23/20 4:57 PM 21 | * Creator Email:xuqiankun66@gmail.com 22 | * Description: 23 | */ 24 | class FixedTabActivity : AppCompatActivity() { 25 | 26 | private lateinit var binding: ActivityFixedTabBinding 27 | 28 | override fun onCreate(savedInstanceState: Bundle?) { 29 | super.onCreate(savedInstanceState) 30 | binding = ActivityFixedTabBinding.inflate(layoutInflater) 31 | setContentView(binding.root) 32 | 33 | val data = ZH.copyOfRange(0, 3) 34 | 35 | binding.tab0.tabMode = KDTabLayout.TAB_MODE_SPREAD 36 | binding.tab0.contentAdapter = object : KDTabAdapter() { 37 | override fun createTab(position: Int): KDTab? { 38 | return KDColorMorphingTextTab(this@FixedTabActivity, data[position]).apply { 39 | weight = position + 2 40 | selectedTextColor = Color.parseColor("#ff5722") 41 | normalTextColor = Color.parseColor("#9e9e9e") 42 | selectedTextSize = 18f 43 | normalTextSize = 14f 44 | selectedBold = true 45 | setOnClickListener { 46 | binding.vp.currentItem = position 47 | } 48 | } 49 | } 50 | 51 | override fun createIndicator(): KDTabIndicator? { 52 | return KDRecIndicator(binding.tab0).apply { 53 | indicatorHeight = 4f 54 | startColor = 0xffFF4343.toInt() 55 | endColor = 0x00FF7444.toInt() 56 | mode = KDRecIndicator.MODE_MATCH 57 | endInterpolator = DecelerateInterpolator(2f) 58 | } 59 | } 60 | 61 | override fun getTabCount(): Int { 62 | return data.size 63 | } 64 | } 65 | 66 | binding.tab1.tabMode = KDTabLayout.TAB_MODE_PACK 67 | binding.tab1.contentAdapter = object : KDTabAdapter() { 68 | override fun createTab(position: Int): KDTab? { 69 | return KDColorMorphingTextTab(this@FixedTabActivity, data[position]).apply { 70 | horizontalPadding = 12f 71 | selectedTextColor = Color.parseColor("#039be5") 72 | normalTextColor = Color.parseColor("#9e9e9e") 73 | setOnClickListener { 74 | binding.vp.currentItem = position 75 | } 76 | } 77 | } 78 | 79 | override fun createIndicator(): KDTabIndicator? { 80 | return KDRecIndicator(binding.tab1).apply { 81 | indicatorHeight = 4f 82 | color = 0xff039be5.toInt() 83 | mode = KDRecIndicator.MODE_MATCH 84 | endInterpolator = DecelerateInterpolator(2f) 85 | } 86 | } 87 | 88 | override fun getTabCount(): Int { 89 | return data.size 90 | } 91 | } 92 | 93 | binding.tab2.tabMode = KDTabLayout.TAB_MODE_PACK 94 | binding.tab2.contentAdapter = object : KDTabAdapter() { 95 | override fun createTab(position: Int): KDTab? { 96 | return KDColorClipTextTab(this@FixedTabActivity, data[position]).apply { 97 | horizontalPadding = 12f 98 | selectedTextColor = Color.parseColor("#ffffff") 99 | normalTextColor = Color.parseColor("#ff5722") 100 | setOnClickListener { 101 | binding.vp.currentItem = position 102 | } 103 | } 104 | } 105 | 106 | override fun createIndicator(): KDTabIndicator? { 107 | return KDRecIndicator(binding.tab2).apply { 108 | indicatorHeight = 48f 109 | color = 0xffff5722.toInt() 110 | cornerRadius = 24f 111 | mode = KDRecIndicator.MODE_MATCH 112 | } 113 | } 114 | 115 | override fun getTabCount(): Int { 116 | return data.size 117 | } 118 | } 119 | 120 | binding.tab3.tabMode = KDTabLayout.TAB_MODE_SPREAD 121 | binding.tab3.contentAdapter = object : KDTabAdapter() { 122 | override fun createTab(position: Int): KDTab? { 123 | return TextViewTab(this@FixedTabActivity, data[position]).apply { 124 | setOnClickListener { 125 | binding.vp.currentItem = position 126 | } 127 | } 128 | } 129 | 130 | override fun getTabCount(): Int { 131 | return data.size 132 | } 133 | } 134 | 135 | binding.tab0.setViewPager(binding.vp) 136 | binding.tab1.setViewPager(binding.vp) 137 | binding.tab2.setViewPager(binding.vp) 138 | binding.tab3.setViewPager(binding.vp) 139 | binding.vp.adapter = ViewPagerAdapter(data.toMutableList()) 140 | } 141 | } -------------------------------------------------------------------------------- /app/src/main/java/github/xuqk/kdtablayout/sample/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package github.xuqk.kdtablayout.sample 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import androidx.appcompat.app.AppCompatActivity 6 | import github.xuqk.kdtablayout.sample.databinding.ActivityMainBinding 7 | 8 | class MainActivity : AppCompatActivity() { 9 | 10 | private lateinit var binding: ActivityMainBinding 11 | 12 | override fun onCreate(savedInstanceState: Bundle?) { 13 | super.onCreate(savedInstanceState) 14 | binding = ActivityMainBinding.inflate(layoutInflater) 15 | setContentView(binding.root) 16 | 17 | binding.btnScrollableTab.setOnClickListener { 18 | startActivity( 19 | Intent(this, ScrollableTabActivity::class.java) 20 | ) 21 | } 22 | 23 | binding.btnFixedTab.setOnClickListener { 24 | startActivity( 25 | Intent(this, FixedTabActivity::class.java) 26 | ) 27 | } 28 | 29 | binding.btnDynamicTab.setOnClickListener { 30 | startActivity( 31 | Intent(this, DynamicTabActivity::class.java) 32 | ) 33 | } 34 | 35 | binding.btnOnlyIndicatorTab.setOnClickListener { 36 | startActivity( 37 | Intent(this, OnlyIndicatorActivity::class.java) 38 | ) 39 | } 40 | 41 | binding.btnBadgeTab.setOnClickListener { 42 | startActivity( 43 | Intent(this, BadgeTabActivity::class.java) 44 | ) 45 | } 46 | 47 | binding.btnCustomTab.setOnClickListener { 48 | startActivity( 49 | Intent(this, CustomTabActivity::class.java) 50 | ) 51 | } 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /app/src/main/java/github/xuqk/kdtablayout/sample/OnlyIndicatorActivity.kt: -------------------------------------------------------------------------------- 1 | package github.xuqk.kdtablayout.sample 2 | 3 | import android.os.Bundle 4 | import androidx.appcompat.app.AppCompatActivity 5 | import github.xuqk.kdtablayout.KDTabAdapter 6 | import github.xuqk.kdtablayout.sample.adapter.ViewPager2Adapter 7 | import github.xuqk.kdtablayout.sample.databinding.ActivityOnlyIndicatorBinding 8 | import github.xuqk.kdtablayout.widget.KDTab 9 | import github.xuqk.kdtablayout.widget.KDTabIndicator 10 | import github.xuqk.kdtablayout.widget.indicator.DotMorphingIndicator 11 | import github.xuqk.kdtablayout.widget.indicator.DotWithStrokeIndicator 12 | import github.xuqk.kdtablayout.widget.indicator.KDRecIndicator 13 | 14 | /** 15 | * Created By:XuQK 16 | * Created Date:2/23/20 6:51 PM 17 | * Creator Email:xuqiankun66@gmail.com 18 | * Description: 19 | */ 20 | class OnlyIndicatorActivity : AppCompatActivity() { 21 | 22 | private lateinit var binding: ActivityOnlyIndicatorBinding 23 | 24 | override fun onCreate(savedInstanceState: Bundle?) { 25 | super.onCreate(savedInstanceState) 26 | binding = ActivityOnlyIndicatorBinding.inflate(layoutInflater) 27 | setContentView(binding.root) 28 | 29 | val data = ZH 30 | 31 | binding.tab0.contentAdapter = object : KDTabAdapter() { 32 | override fun createTab(position: Int): KDTab? { 33 | return null 34 | } 35 | 36 | override fun createIndicator(): KDTabIndicator? { 37 | return KDRecIndicator(binding.tab0).apply { 38 | indicatorHeight = 4f 39 | color = 0xffff5722.toInt() 40 | mode = KDRecIndicator.MODE_MATCH 41 | } 42 | } 43 | 44 | override fun getTabCount(): Int { 45 | return data.size 46 | } 47 | } 48 | 49 | binding.tab1.contentAdapter = object : KDTabAdapter() { 50 | override fun createTab(position: Int): KDTab? { 51 | return null 52 | } 53 | 54 | override fun createIndicator(): KDTabIndicator? { 55 | return DotWithStrokeIndicator(binding.tab1) 56 | .apply { 57 | strokeWidth = 2f 58 | } 59 | } 60 | 61 | override fun getTabCount(): Int { 62 | return data.size 63 | } 64 | } 65 | 66 | binding.tab2.contentAdapter = object : KDTabAdapter() { 67 | override fun createTab(position: Int): KDTab? { 68 | return null 69 | } 70 | 71 | override fun createIndicator(): KDTabIndicator? { 72 | return DotMorphingIndicator(binding.tab2) 73 | } 74 | 75 | override fun getTabCount(): Int { 76 | return data.size 77 | } 78 | } 79 | 80 | binding.tab0.setViewPager2(binding.vp2) 81 | binding.tab1.setViewPager2(binding.vp2) 82 | binding.tab2.setViewPager2(binding.vp2) 83 | binding.vp2.adapter = ViewPager2Adapter(data.toMutableList()) 84 | } 85 | } -------------------------------------------------------------------------------- /app/src/main/java/github/xuqk/kdtablayout/sample/ScrollableTabActivity.kt: -------------------------------------------------------------------------------- 1 | package github.xuqk.kdtablayout.sample 2 | 3 | import android.graphics.Color 4 | import android.os.Bundle 5 | import android.view.animation.AccelerateInterpolator 6 | import android.view.animation.DecelerateInterpolator 7 | import androidx.appcompat.app.AppCompatActivity 8 | import github.xuqk.kdtablayout.KDTabAdapter 9 | import github.xuqk.kdtablayout.sample.adapter.ViewPager2Adapter 10 | import github.xuqk.kdtablayout.sample.databinding.ActivityScrollableTabBinding 11 | import github.xuqk.kdtablayout.sample.widget.CustomFontTab 12 | import github.xuqk.kdtablayout.widget.KDTab 13 | import github.xuqk.kdtablayout.widget.KDTabIndicator 14 | import github.xuqk.kdtablayout.widget.indicator.KDRecIndicator 15 | import github.xuqk.kdtablayout.widget.tab.KDColorClipTextTab 16 | import github.xuqk.kdtablayout.widget.tab.KDColorMorphingTextTab 17 | 18 | /** 19 | * Created By:XuQK 20 | * Created Date:2/23/20 4:48 PM 21 | * Creator Email:xuqiankun66@gmail.com 22 | * Description: 23 | */ 24 | class ScrollableTabActivity : AppCompatActivity() { 25 | 26 | private lateinit var binding: ActivityScrollableTabBinding 27 | 28 | override fun onCreate(savedInstanceState: Bundle?) { 29 | super.onCreate(savedInstanceState) 30 | binding = ActivityScrollableTabBinding.inflate(layoutInflater) 31 | setContentView(binding.root) 32 | 33 | binding.tab0.scrollBiasX = -100f 34 | binding.tab0.contentAdapter = object : KDTabAdapter() { 35 | override fun createTab(position: Int): KDTab? { 36 | return KDColorMorphingTextTab(this@ScrollableTabActivity, ZH[position]).apply { 37 | horizontalPadding = 16f 38 | selectedTextSize = 22f 39 | normalTextSize = 16f 40 | setOnClickListener { 41 | binding.vp2.currentItem = position 42 | } 43 | } 44 | } 45 | 46 | override fun createIndicator(): KDTabIndicator? { 47 | return null 48 | } 49 | 50 | override fun getTabCount(): Int { 51 | return ZH.size 52 | } 53 | } 54 | 55 | binding.tab1.scrollBiasX = -50f 56 | binding.tab1.contentAdapter = object : KDTabAdapter() { 57 | override fun createTab(position: Int): KDTab? { 58 | return KDColorClipTextTab(this@ScrollableTabActivity, ZH[position]).apply { 59 | horizontalPadding = 16f 60 | selectedTextSize = 22f 61 | normalTextSize = 16f 62 | setOnClickListener { 63 | binding.vp2.currentItem = position 64 | } 65 | } 66 | } 67 | 68 | override fun createIndicator(): KDTabIndicator? { 69 | return null 70 | } 71 | 72 | override fun getTabCount(): Int { 73 | return ZH.size 74 | } 75 | } 76 | 77 | binding.tab2.contentAdapter = object : KDTabAdapter() { 78 | override fun createTab(position: Int): KDTab? { 79 | return KDColorMorphingTextTab(this@ScrollableTabActivity, ZH[position]).apply { 80 | horizontalPadding = 16f 81 | selectedTextColor = Color.parseColor("#ff5722") 82 | normalTextColor = Color.parseColor("#9e9e9e") 83 | selectedTextSize = 32f 84 | normalTextSize = 16f 85 | resizeWithFontSize = true 86 | setOnClickListener { 87 | binding.vp2.currentItem = position 88 | } 89 | } 90 | } 91 | 92 | override fun createIndicator(): KDTabIndicator? { 93 | return KDRecIndicator(binding.tab2).apply { 94 | indicatorHeight = 6f 95 | color = 0xffff5722.toInt() 96 | cornerRadius = 3f 97 | mode = KDRecIndicator.MODE_EXACT 98 | indicatorWidth = 16f 99 | startInterpolator = AccelerateInterpolator() 100 | endInterpolator = DecelerateInterpolator(2f) 101 | } 102 | } 103 | 104 | override fun getTabCount(): Int { 105 | return ZH.size 106 | } 107 | } 108 | 109 | binding.tab3.scrollBiasX = 50f 110 | binding.tab3.needCompleteScroll = true 111 | binding.tab3.contentAdapter = object : KDTabAdapter() { 112 | override fun createTab(position: Int): KDTab? { 113 | return KDColorMorphingTextTab(this@ScrollableTabActivity, ZH[position]).apply { 114 | horizontalPadding = 16f 115 | selectedTextColor = Color.parseColor("#ff5722") 116 | normalTextColor = Color.BLACK 117 | setOnClickListener { 118 | binding.vp2.currentItem = position 119 | } 120 | } 121 | } 122 | 123 | override fun createIndicator(): KDTabIndicator? { 124 | return KDRecIndicator(binding.tab3).apply { 125 | indicatorHeight = 36f 126 | color = 0x4c03a9f4 127 | marginBottom = 6f 128 | cornerRadius = 18f 129 | mode = KDRecIndicator.MODE_MATCH 130 | } 131 | } 132 | 133 | override fun getTabCount(): Int { 134 | return ZH.size 135 | } 136 | } 137 | 138 | binding.tab4.scrollBiasX = 100f 139 | binding.tab4.post { 140 | binding.tab4.contentAdapter = object : KDTabAdapter() { 141 | override fun createTab(position: Int): KDTab? { 142 | return KDColorMorphingTextTab(this@ScrollableTabActivity, ZH[position]).apply { 143 | horizontalPadding = 16f 144 | selectedTextColor = Color.parseColor("#039be5") 145 | normalTextColor = Color.parseColor("#9e9e9e") 146 | setOnClickListener { 147 | binding.vp2.currentItem = position 148 | } 149 | } 150 | } 151 | 152 | override fun createIndicator(): KDTabIndicator? { 153 | return KDRecIndicator(binding.tab4).apply { 154 | indicatorHeight = 6f 155 | color = 0xff039be5.toInt() 156 | marginBottom = 42f 157 | mode = KDRecIndicator.MODE_EXACT 158 | indicatorWidth = 16f 159 | endInterpolator = DecelerateInterpolator(2f) 160 | } 161 | } 162 | 163 | override fun getTabCount(): Int { 164 | return ZH.size 165 | } 166 | } 167 | } 168 | 169 | 170 | binding.tab5.contentAdapter = object : KDTabAdapter() { 171 | override fun createTab(position: Int): KDTab? { 172 | return CustomFontTab(this@ScrollableTabActivity, EN[position]).apply { 173 | horizontalPadding = 16f 174 | selectedTextColor = Color.parseColor("#673ab7") 175 | normalTextColor = Color.parseColor("#9ccc65") 176 | setOnClickListener { 177 | binding.vp2.currentItem = position 178 | } 179 | } 180 | } 181 | 182 | override fun createIndicator(): KDTabIndicator? { 183 | return KDRecIndicator(binding.tab5).apply { 184 | indicatorHeight = 6f 185 | color = 0xff673ab7.toInt() 186 | mode = KDRecIndicator.MODE_WRAP_CONTENT 187 | } 188 | } 189 | 190 | override fun getTabCount(): Int { 191 | return EN.size 192 | } 193 | } 194 | 195 | binding.vp2.adapter = ViewPager2Adapter(ZH.toMutableList()) 196 | binding.tab0.setViewPager2(binding.vp2) 197 | binding.tab1.setViewPager2(binding.vp2) 198 | binding.tab2.setViewPager2(binding.vp2) 199 | binding.tab3.setViewPager2(binding.vp2) 200 | binding.tab4.setViewPager2(binding.vp2) 201 | binding.tab5.setViewPager2(binding.vp2) 202 | } 203 | } -------------------------------------------------------------------------------- /app/src/main/java/github/xuqk/kdtablayout/sample/adapter/ViewPager2Adapter.kt: -------------------------------------------------------------------------------- 1 | package github.xuqk.kdtablayout.sample.adapter 2 | 3 | import android.graphics.Color 4 | import android.util.TypedValue 5 | import android.view.Gravity 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import android.widget.TextView 9 | import androidx.recyclerview.widget.RecyclerView 10 | 11 | /** 12 | * Created By:XuQK 13 | * Created Date:2/23/20 5:25 PM 14 | * Creator Email:xuqiankun66@gmail.com 15 | * Description: 16 | */ 17 | class ViewPager2Adapter(private val data: MutableList = mutableListOf()) : RecyclerView.Adapter() { 18 | 19 | fun setNewData(newData: List) { 20 | data.clear() 21 | data.addAll(newData) 22 | notifyDataSetChanged() 23 | } 24 | 25 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewPager2Holder { 26 | val tv = TextView(parent.context).apply { 27 | setTextSize(TypedValue.COMPLEX_UNIT_SP, 24f) 28 | setTextColor(Color.RED) 29 | gravity = Gravity.CENTER 30 | } 31 | tv.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) 32 | return ViewPager2Holder( 33 | tv 34 | ) 35 | } 36 | 37 | override fun getItemCount(): Int { 38 | return data.size 39 | } 40 | 41 | override fun onBindViewHolder(holder: ViewPager2Holder, position: Int) { 42 | (holder.itemView as TextView).text = data[position] + "\n\nViewPager2" 43 | } 44 | 45 | class ViewPager2Holder(itemView: View) : RecyclerView.ViewHolder(itemView) { 46 | 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/java/github/xuqk/kdtablayout/sample/adapter/ViewPagerAdapter.kt: -------------------------------------------------------------------------------- 1 | package github.xuqk.kdtablayout.sample.adapter 2 | 3 | import android.graphics.Color 4 | import android.util.TypedValue 5 | import android.view.Gravity 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import android.widget.TextView 9 | import androidx.viewpager.widget.PagerAdapter 10 | 11 | /** 12 | * Created By:XuQK 13 | * Created Date:2/23/20 5:28 PM 14 | * Creator Email:xuqiankun66@gmail.com 15 | * Description: 16 | */ 17 | class ViewPagerAdapter(private val data: MutableList = mutableListOf()) : PagerAdapter() { 18 | 19 | fun setNewData(newData: Set) { 20 | data.clear() 21 | data.addAll(newData) 22 | notifyDataSetChanged() 23 | } 24 | 25 | override fun isViewFromObject(view: View, `object`: Any): Boolean { 26 | return view == `object` 27 | } 28 | 29 | override fun getCount(): Int { 30 | return data.size 31 | } 32 | 33 | override fun instantiateItem(container: ViewGroup, position: Int): Any { 34 | val tv = TextView(container.context).apply { 35 | setTextSize(TypedValue.COMPLEX_UNIT_SP, 24f) 36 | setTextColor(Color.RED) 37 | text = data[position] + "\n\nViewPager" 38 | gravity = Gravity.CENTER 39 | } 40 | tv.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) 41 | container.addView(tv) 42 | return tv 43 | } 44 | 45 | override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { 46 | container.removeView(`object` as View) 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/java/github/xuqk/kdtablayout/sample/widget/CustomFontTab.kt: -------------------------------------------------------------------------------- 1 | package github.xuqk.kdtablayout.sample.widget 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.graphics.Typeface 6 | import github.xuqk.kdtablayout.widget.tab.KDColorMorphingTextTab 7 | 8 | /** 9 | * Created By:XuQK 10 | * Created Date:21-3-5 下午2:57 11 | * Creator Email:xu.qiankun@xiji.com 12 | * Description: 13 | */ 14 | 15 | @SuppressLint("ViewConstructor") 16 | class CustomFontTab(context: Context, text: String) : KDColorMorphingTextTab(context, text) { 17 | 18 | private val customTypeface by lazy { 19 | Typeface.createFromAsset(context.assets, "chilanka.otf") 20 | } 21 | 22 | override fun setPaintParam() { 23 | super.setPaintParam() 24 | paint.typeface = customTypeface 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/java/github/xuqk/kdtablayout/sample/widget/ShadowGradientTab.kt: -------------------------------------------------------------------------------- 1 | package github.xuqk.kdtablayout.sample.widget 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.graphics.* 6 | import github.xuqk.kdtablayout.sample.dpToPx 7 | import github.xuqk.kdtablayout.widget.tab.KDColorMorphingTextTab 8 | 9 | /** 10 | * Created By:XuQK 11 | * Created Date:3/1/20 12:37 PM 12 | * Creator Email:xuqiankun66@gmail.com 13 | * Description: 14 | */ 15 | @SuppressLint("ViewConstructor") 16 | class ShadowGradientTab(context: Context, text: String) : KDColorMorphingTextTab(context, text) { 17 | private val paddingHorizontal = dpToPx(context, 5f) 18 | private val paddingVertical = dpToPx(context, 10f) 19 | private val shadowRadius = dpToPx(context, 4f).toFloat() 20 | private val shadowY = dpToPx(context, 5f).toFloat() 21 | private val rectRadius = dpToPx(context, 10f) 22 | private val rect = RectF() 23 | 24 | private val startColorRBG = intArrayOf(38, 160, 244) 25 | private val endColorRBG = intArrayOf(38, 105, 244) 26 | private val normalBgColor = Color.WHITE 27 | 28 | private var fraction: Float = 0f 29 | 30 | override fun onScrolling(selectedFraction: Float, selectedInLeft: Boolean) { 31 | super.onScrolling(selectedFraction, selectedInLeft) 32 | fraction = selectedFraction 33 | } 34 | 35 | override fun reset() { 36 | super.reset() 37 | fraction = 0f 38 | } 39 | 40 | override fun selectTab() { 41 | super.selectTab() 42 | fraction = 1f 43 | } 44 | 45 | override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { 46 | super.onLayout(changed, left, top, right, bottom) 47 | if (changed) { 48 | rect.set( 49 | paddingHorizontal.toFloat(), 50 | paddingVertical.toFloat(), 51 | (width - paddingHorizontal).toFloat(), 52 | (height - paddingVertical).toFloat() 53 | ) 54 | } 55 | } 56 | 57 | override fun drawContent(canvas: Canvas) { 58 | // 绘制白色底色 59 | paint.reset() 60 | paint.color = normalBgColor 61 | paint.alpha = 255 62 | paint.setShadowLayer(shadowRadius * fraction, 0f, shadowY * fraction, 0x4c26A0F4.toInt()) 63 | canvas.drawRoundRect(rect, rectRadius.toFloat(), rectRadius.toFloat(), paint) 64 | 65 | // 如果fraction大于0,绘制覆盖的渐变色 66 | if (fraction > 0f) { 67 | paint.reset() 68 | val start = Color.argb((255 * fraction).toInt(), startColorRBG[0], startColorRBG[1], startColorRBG[2]) 69 | val end = Color.argb((255 * fraction).toInt(), endColorRBG[0], endColorRBG[1], endColorRBG[2]) 70 | 71 | paint.shader = LinearGradient( 72 | rect.left, 73 | rect.bottom, 74 | rect.right, 75 | rect.top, 76 | start, 77 | end, 78 | Shader.TileMode.CLAMP 79 | ) 80 | canvas.drawRoundRect(rect, rectRadius.toFloat(), rectRadius.toFloat(), paint) 81 | } 82 | 83 | super.drawContent(canvas) 84 | } 85 | } -------------------------------------------------------------------------------- /app/src/main/java/github/xuqk/kdtablayout/sample/widget/TextViewTab.kt: -------------------------------------------------------------------------------- 1 | package github.xuqk.kdtablayout.sample.widget 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.graphics.Typeface 6 | import android.view.Gravity 7 | import android.widget.TextView 8 | import github.xuqk.kdtablayout.widget.KDTab 9 | 10 | /** 11 | * Created By:XuQK 12 | * Created Date:21-3-5 下午2:57 13 | * Creator Email:xu.qiankun@xiji.com 14 | * Description: 15 | */ 16 | 17 | @SuppressLint("ViewConstructor") 18 | class TextViewTab(context: Context, text: String) : KDTab(context) { 19 | 20 | private val tv: TextView = TextView(context).apply { 21 | this.text = text 22 | textSize = 16f 23 | } 24 | 25 | init { 26 | addView( 27 | tv, 28 | LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT).apply { 29 | gravity = Gravity.CENTER 30 | } 31 | ) 32 | } 33 | 34 | override fun onScrolling(selectedFraction: Float, selectedInLeft: Boolean) { 35 | if (selectedFraction > 0.5f) { 36 | tv.typeface = Typeface.DEFAULT_BOLD 37 | } else { 38 | tv.typeface = Typeface.DEFAULT 39 | } 40 | } 41 | 42 | override fun reset() { 43 | tv.typeface = Typeface.DEFAULT 44 | } 45 | 46 | override fun selectTab() { 47 | tv.typeface = Typeface.DEFAULT_BOLD 48 | } 49 | 50 | override fun computeContentBounds() { 51 | 52 | } 53 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_round_stroke_r24.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_badge_tab.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 23 | 24 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_custom_tab.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_dynamic_tab.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 18 | 19 |