├── demo
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── drawable
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_round.png
│ │ │ │ ├── tab_contact_normal.png
│ │ │ │ ├── bg_navigation.xml
│ │ │ │ ├── bar_my.xml
│ │ │ │ ├── bar_news.xml
│ │ │ │ ├── bar_invite.xml
│ │ │ │ ├── bar_manage.xml
│ │ │ │ ├── bar_constact.xml
│ │ │ │ ├── item_check.xml
│ │ │ │ └── ic_launcher_background.xml
│ │ │ ├── drawable-hdpi
│ │ │ │ ├── icon_add.png
│ │ │ │ ├── tab_my_normal.png
│ │ │ │ ├── tab_my_selected.png
│ │ │ │ ├── tab_news_normal.png
│ │ │ │ ├── tab_contact_normal.png
│ │ │ │ ├── tab_invite_normal.png
│ │ │ │ ├── tab_manage_normal.png
│ │ │ │ ├── tab_news_selected.png
│ │ │ │ ├── tab_contact_selected.png
│ │ │ │ ├── tab_invite_selected.png
│ │ │ │ └── tab_manage_selected.png
│ │ │ ├── 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
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── layout
│ │ │ │ ├── fragment_home.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ └── activity_main_viewpager.xml
│ │ │ ├── menu
│ │ │ │ └── navigation_menu.xml
│ │ │ └── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ ├── java
│ │ │ └── cn
│ │ │ │ └── onestravel
│ │ │ │ └── one
│ │ │ │ └── navigation
│ │ │ │ └── demo
│ │ │ │ ├── BaseFragment.java
│ │ │ │ ├── ThirdFragment.kt
│ │ │ │ ├── SecondFragment.kt
│ │ │ │ ├── FiveFragment.kt
│ │ │ │ ├── FourFragment.kt
│ │ │ │ ├── FirstFragment.kt
│ │ │ │ ├── MainActivity.kt
│ │ │ │ └── MainViewPagerActivity.kt
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── cn
│ │ │ └── onestravel
│ │ │ └── bottomview
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── cn
│ │ └── onestravel
│ │ └── bottomview
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── .gitattributes
├── OneBottomNavigationBar
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── styles.xml
│ │ │ │ └── attrs.xml
│ │ │ └── drawable
│ │ │ │ └── default_blue_tab_tint.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── cn
│ │ │ └── onestravel
│ │ │ └── one
│ │ │ └── navigation
│ │ │ ├── utils
│ │ │ ├── EventUtils.kt
│ │ │ └── DensityUtils.kt
│ │ │ └── androidx
│ │ │ └── OneBottomNavigationBarX.kt
│ ├── test
│ │ └── java
│ │ │ └── cn
│ │ │ └── onestravel
│ │ │ └── bottomview
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── cn
│ │ └── onestravel
│ │ └── bottomview
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── resources
├── SVID_20190130_155132_1.gif
└── SVID_20190130_155440_1.gif
├── .idea
├── encodings.xml
├── vcs.xml
├── compiler.xml
├── misc.xml
├── runConfigurations.xml
├── gradle.xml
├── jarRepositories.xml
├── codeStyles
│ └── Project.xml
└── dbnavigator.xml
├── .gitignore
├── gradle.properties
├── project.properties
├── gradlew.bat
├── jcenter_publish.gradle
├── gradlew
└── README.md
/demo/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.java linguist-language=Java
--------------------------------------------------------------------------------
/OneBottomNavigationBar/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':demo', ':OneBottomNavigationBar'
2 |
--------------------------------------------------------------------------------
/OneBottomNavigationBar/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/OneBottomNavigationBar/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/resources/SVID_20190130_155132_1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/resources/SVID_20190130_155132_1.gif
--------------------------------------------------------------------------------
/resources/SVID_20190130_155440_1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/resources/SVID_20190130_155440_1.gif
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/drawable/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-hdpi/icon_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/drawable-hdpi/icon_add.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-hdpi/tab_my_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/drawable-hdpi/tab_my_normal.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/drawable/ic_launcher_round.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/tab_contact_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/drawable/tab_contact_normal.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-hdpi/tab_my_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/drawable-hdpi/tab_my_selected.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-hdpi/tab_news_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/drawable-hdpi/tab_news_normal.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/OneBottomNavigationBar/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-hdpi/tab_contact_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/drawable-hdpi/tab_contact_normal.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-hdpi/tab_invite_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/drawable-hdpi/tab_invite_normal.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-hdpi/tab_manage_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/drawable-hdpi/tab_manage_normal.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-hdpi/tab_news_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/drawable-hdpi/tab_news_selected.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-hdpi/tab_contact_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/drawable-hdpi/tab_contact_selected.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-hdpi/tab_invite_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/drawable-hdpi/tab_invite_selected.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-hdpi/tab_manage_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onestravel/OneBottomNavigationBar/HEAD/demo/src/main/res/drawable-hdpi/tab_manage_selected.png
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches/build_file_checksums.ser
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | .DS_Store
9 | /build
10 | /captures
11 | .externalNativeBuild
12 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 |
7 |
--------------------------------------------------------------------------------
/demo/src/main/java/cn/onestravel/one/navigation/demo/BaseFragment.java:
--------------------------------------------------------------------------------
1 | package cn.onestravel.one.navigation.demo;
2 |
3 | import androidx.fragment.app.Fragment;
4 |
5 | /**
6 | * Created by wanghu on 2020-03-03
7 | */
8 | public class BaseFragment extends Fragment {
9 | }
10 |
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/bg_navigation.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | BottomView
3 |
4 |
5 | Hello blank fragment
6 | 设置
7 | 拍照
8 | 首页
9 |
10 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/bar_my.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/bar_news.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/bar_invite.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/bar_manage.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/bar_constact.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/demo/src/test/java/cn/onestravel/bottomview/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package cn.onestravel.bottomview
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see [Testing documentation](http://d.android.com/tools/testing)
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, (2 + 2).toLong())
16 | }
17 | }
--------------------------------------------------------------------------------
/OneBottomNavigationBar/src/test/java/cn/onestravel/bottomview/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package cn.onestravel.bottomview
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see [Testing documentation](http://d.android.com/tools/testing)
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, (2 + 2).toLong())
16 | }
17 | }
--------------------------------------------------------------------------------
/OneBottomNavigationBar/src/main/res/drawable/default_blue_tab_tint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/item_check.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/fragment_home.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/demo/src/androidTest/java/cn/onestravel/bottomview/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package cn.onestravel.bottomview
2 |
3 | import android.content.Context
4 | import androidx.test.InstrumentationRegistry
5 | import androidx.test.runner.AndroidJUnit4
6 |
7 | import org.junit.Test
8 | import org.junit.runner.RunWith
9 |
10 | import org.junit.Assert.*
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see [Testing documentation](http://d.android.com/tools/testing)
16 | */
17 | @RunWith(AndroidJUnit4::class)
18 | class ExampleInstrumentedTest {
19 | @Test
20 | fun useAppContext() {
21 | // Context of the app under test.
22 | val appContext = InstrumentationRegistry.getTargetContext()
23 |
24 | assertEquals("cn.onestravel.bottomview", appContext.packageName)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/demo/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 |
--------------------------------------------------------------------------------
/demo/src/main/java/cn/onestravel/one/navigation/demo/ThirdFragment.kt:
--------------------------------------------------------------------------------
1 | package cn.onestravel.one.navigation.demo
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 |
8 | import cn.onestravel.bottomview.demo.R
9 | import kotlinx.android.synthetic.main.fragment_home.*
10 |
11 | /**
12 | * @author onestravel
13 | * @createTime 2019-08-04 11:52
14 | * @description TODO
15 | */
16 | class ThirdFragment : BaseFragment() {
17 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
18 | savedInstanceState: Bundle?): View? {
19 | return inflater.inflate(R.layout.fragment_home, container, false).apply { init() }
20 | }
21 | fun init() {
22 | tvName?.let {it.text = "ThirdFragment"}
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | android.enableJetifier=true
10 | android.useAndroidX=true
11 | org.gradle.jvmargs=-Xmx1536m
12 | # When configured, Gradle will run in incubating parallel mode.
13 | # This option should only be used with decoupled projects. More details, visit
14 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
15 | # org.gradle.parallel=true
16 |
17 |
18 |
--------------------------------------------------------------------------------
/OneBottomNavigationBar/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 |
--------------------------------------------------------------------------------
/OneBottomNavigationBar/src/androidTest/java/cn/onestravel/bottomview/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package cn.onestravel.bottomview
2 |
3 | import android.content.Context
4 | import androidx.test.InstrumentationRegistry
5 | import androidx.test.runner.AndroidJUnit4
6 |
7 | import org.junit.Test
8 | import org.junit.runner.RunWith
9 |
10 | import org.junit.Assert.*
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see [Testing documentation](http://d.android.com/tools/testing)
16 | */
17 | @RunWith(AndroidJUnit4::class)
18 | class ExampleInstrumentedTest {
19 | @Test
20 | fun useAppContext() {
21 | // Context of the app under test.
22 | val appContext = InstrumentationRegistry.getTargetContext()
23 |
24 | assertEquals("cn.onestravel.bottomview2.test", appContext.packageName)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/demo/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/demo/src/main/java/cn/onestravel/one/navigation/demo/SecondFragment.kt:
--------------------------------------------------------------------------------
1 | package cn.onestravel.one.navigation.demo
2 |
3 | import android.app.Fragment
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.TextView
9 |
10 | import cn.onestravel.bottomview.demo.R
11 | import kotlinx.android.synthetic.main.fragment_home.*
12 |
13 | /**
14 | * @author onestravel
15 | * @createTime 2019-08-04 11:52
16 | * @description TODO
17 | */
18 | class SecondFragment : BaseFragment() {
19 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
20 | savedInstanceState: Bundle?): View? {
21 | return inflater.inflate(R.layout.fragment_home, container, false).apply { init() }
22 | }
23 | fun init() {
24 | tvName?.let {it.text = "SecondFragment"}
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/demo/src/main/res/menu/navigation_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/demo/src/main/java/cn/onestravel/one/navigation/demo/FiveFragment.kt:
--------------------------------------------------------------------------------
1 | package cn.onestravel.one.navigation.demo
2 |
3 | import android.app.Fragment
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.TextView
9 |
10 | import cn.onestravel.bottomview.demo.R
11 | import kotlinx.android.synthetic.main.fragment_home.*
12 |
13 | /**
14 | * @author onestravel
15 | * @createTime 2019-08-04 11:52
16 | * @description TODO
17 | */
18 | class FiveFragment : BaseFragment() {
19 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
20 | savedInstanceState: Bundle?): View? {
21 | val view = inflater.inflate(R.layout.fragment_home, container, false)
22 | return view
23 | }
24 |
25 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
26 | super.onViewCreated(view, savedInstanceState)
27 | init()
28 | }
29 | fun init() {
30 | tvName?.let {it.text = "FiveFragment"}
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/demo/src/main/java/cn/onestravel/one/navigation/demo/FourFragment.kt:
--------------------------------------------------------------------------------
1 | package cn.onestravel.one.navigation.demo
2 |
3 | import android.app.Fragment
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.TextView
9 |
10 | import cn.onestravel.bottomview.demo.R
11 | import kotlinx.android.synthetic.main.fragment_home.*
12 |
13 | /**
14 | * @author onestravel
15 | * @createTime 2019-08-04 11:52
16 | * @description TODO
17 | */
18 | class FourFragment : BaseFragment() {
19 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
20 | savedInstanceState: Bundle?): View? {
21 | val view = inflater.inflate(R.layout.fragment_home, container, false)
22 | return view
23 | }
24 |
25 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
26 | super.onViewCreated(view, savedInstanceState)
27 | init()
28 | }
29 | fun init() {
30 | tvName?.let {it.text = "FourFragment"}
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/demo/src/main/java/cn/onestravel/one/navigation/demo/FirstFragment.kt:
--------------------------------------------------------------------------------
1 | package cn.onestravel.one.navigation.demo
2 |
3 | import android.app.Fragment
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.TextView
9 |
10 | import cn.onestravel.bottomview.demo.R
11 | import kotlinx.android.synthetic.main.fragment_home.*
12 |
13 | /**
14 | * @author onestravel
15 | * @createTime 2019-08-04 11:52
16 | * @description TODO
17 | */
18 | class FirstFragment : BaseFragment() {
19 |
20 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
21 | savedInstanceState: Bundle?): View? {
22 | val view = inflater.inflate(R.layout.fragment_home, container, false)
23 | return view
24 | }
25 |
26 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
27 | super.onViewCreated(view, savedInstanceState)
28 | init()
29 | }
30 |
31 | fun init() {
32 | tvName?.let { it.text = "FirstFragment" }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/OneBottomNavigationBar/src/main/java/cn/onestravel/one/navigation/utils/EventUtils.kt:
--------------------------------------------------------------------------------
1 | package cn.onestravel.one.navigation.utils
2 |
3 | import android.graphics.Rect
4 | import android.view.View
5 |
6 | /**
7 | * @author onestravel
8 | * @version 1.0.0
9 | * @name EventUtils
10 | * @description //TODO
11 | * @createTime 2019/1/23 10:50
12 | */
13 | object EventUtils {
14 | /**
15 | * 判断点击事件是否在view内
16 | * @param view
17 | * @param x
18 | * @param y
19 | * @return
20 | */
21 | fun isInViewZone(view: View, x: Double, y: Double): Boolean {
22 | val mChangeImageBackgroundRect = Rect()
23 | view.getDrawingRect(mChangeImageBackgroundRect)
24 | val location = IntArray(2)
25 | view.getLocationOnScreen(location)
26 | mChangeImageBackgroundRect.left = location[0]
27 | mChangeImageBackgroundRect.top = location[1]
28 | mChangeImageBackgroundRect.right = mChangeImageBackgroundRect.right + location[0]
29 | mChangeImageBackgroundRect.bottom = mChangeImageBackgroundRect.bottom + location[1]
30 | return mChangeImageBackgroundRect.contains(x.toInt(), y.toInt())
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/OneBottomNavigationBar/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/project.properties:
--------------------------------------------------------------------------------
1 | project.repo=one
2 | project.name=OneBottomNavigationBar
3 | project.groupId=cn.onestravel.one
4 | project.description=OneBottomNavigationBar is a custom View that implements the function of the navigation bar at the bottom of the App. It can achieve 2-5 navigation menus at the bottom (generally there are no more), and can achieve the effect of a certain menu. You can choose to make the third menu floating. This is a function that many apps have; you can change the color of icons and text when selected and unselected according to the resource file of the color change. You can freely control whether You need to check (checkable). When you select On, you can change to the selected color. When you select Off, you cannot change to the selected color. You can control which item is selected by default. You can set the number of unread messages (number or small red) in a navigation menu. point)
5 | project.artifact=one_bottom_navigationbar
6 | project.packaging=aar
7 | project.version=1.2.4-beta2
8 | project.siteUrl=https://github.com/onestravel/OneBottomNavigationBar
9 | project.gitUrl=https://github.com/onestravel/OneBottomNavigationBar.git
10 | project.licenseName=The Apache Software License, Version 2.0
11 | project.licenseUrl=http://www.apache.org/licenses/LICENSE-2.0.txt
12 | project.allLicenses=["Apache-2.0"]
13 | javadoc.name=OneBottomNavigationBar
14 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/OneBottomNavigationBar/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android-extensions'
3 | apply plugin: 'kotlin-android'
4 | apply from: '../jcenter_publish.gradle'
5 |
6 | android {
7 | compileSdkVersion 29
8 | buildToolsVersion "29.0.0"
9 |
10 | defaultConfig {
11 | minSdkVersion 15
12 | targetSdkVersion 29
13 | versionCode 110
14 | versionName "1.1.0"
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 |
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | lintOptions {
27 | abortOnError false
28 | }
29 |
30 | }
31 |
32 | dependencies {
33 | implementation fileTree(dir: 'libs', include: ['*.jar'])
34 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
35 | implementation 'androidx.appcompat:appcompat:1.0.2'
36 | testImplementation 'junit:junit:4.12'
37 | androidTestImplementation 'androidx.test:runner:1.1.0'
38 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
39 | implementation "androidx.core:core-ktx:+"
40 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
41 | }
42 | repositories {
43 | mavenCentral()
44 | }
45 |
--------------------------------------------------------------------------------
/demo/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android-extensions'
3 | apply plugin: 'kotlin-android'
4 |
5 | android {
6 | compileSdkVersion 29
7 | buildToolsVersion "29.0.0"
8 | defaultConfig {
9 | applicationId "cn.onestravel.bottomview.demo"
10 | minSdkVersion 15
11 | targetSdkVersion 29
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.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | }
23 |
24 | dependencies {
25 | implementation fileTree(include: ['*.jar'], dir: 'libs')
26 | implementation Deps.appcompat
27 | implementation Deps.constraintlayout
28 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
29 | testImplementation 'junit:junit:4.12'
30 | androidTestImplementation 'androidx.test:runner:1.1.0'
31 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
32 | implementation project(':OneBottomNavigationBar')
33 | implementation "androidx.core:core-ktx:+"
34 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
35 | // implementation 'cn.onestravel.one:one_bottom_navigationbar:1.2.2'
36 |
37 | }
38 | repositories {
39 | mavenCentral()
40 | }
41 |
--------------------------------------------------------------------------------
/demo/src/main/java/cn/onestravel/one/navigation/demo/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package cn.onestravel.one.navigation.demo
2 |
3 | import android.graphics.Color
4 | import androidx.appcompat.app.AppCompatActivity
5 | import android.os.Bundle
6 |
7 | import cn.onestravel.bottomview.demo.R
8 | import kotlinx.android.synthetic.main.activity_main.*
9 |
10 |
11 | class MainActivity : AppCompatActivity() {
12 |
13 |
14 | override fun onCreate(savedInstanceState: Bundle?) {
15 | super.onCreate(savedInstanceState)
16 |
17 | setContentView(R.layout.activity_main)
18 | oneBottomLayout.setMenu(R.menu.navigation_menu)
19 | oneBottomLayout.setFragmentManager(supportFragmentManager, mainFragment )
20 | oneBottomLayout.isReplace = false
21 | oneBottomLayout.addFragment(R.id.tab1, FirstFragment())
22 | oneBottomLayout.addFragment(R.id.tab4, FourFragment())
23 | oneBottomLayout.addFragment(R.id.tab5, FiveFragment())
24 | oneBottomLayout.setFloatingEnable(true)
25 | oneBottomLayout.setTopLineColor(Color.RED)
26 | oneBottomLayout.setItemColorStateList(R.drawable.item_check)
27 | oneBottomLayout.setMsgCount(0, 32)
28 | oneBottomLayout.setMsgCount(2, 1)
29 | oneBottomLayout.setMsgCount(1, -1)
30 | oneBottomLayout.setOnItemSelectedListener { item, position ->
31 | // if (position == 1) {
32 | // oneBottomLayout.setFloatingEnable(true)
33 | // } else {
34 | // oneBottomLayout.setFloatingEnable(false)
35 | // }
36 | false
37 | }
38 |
39 | }
40 |
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/demo/src/main/java/cn/onestravel/one/navigation/demo/MainViewPagerActivity.kt:
--------------------------------------------------------------------------------
1 | package cn.onestravel.one.navigation.demo
2 |
3 | import android.graphics.Color
4 | import androidx.appcompat.app.AppCompatActivity
5 | import android.os.Bundle
6 |
7 | import cn.onestravel.bottomview.demo.R
8 | import kotlinx.android.synthetic.main.activity_main.*
9 | import kotlinx.android.synthetic.main.activity_main.oneBottomLayout
10 | import kotlinx.android.synthetic.main.activity_main_viewpager.*
11 |
12 |
13 | class MainViewPagerActivity : AppCompatActivity() {
14 |
15 |
16 | override fun onCreate(savedInstanceState: Bundle?) {
17 | super.onCreate(savedInstanceState)
18 |
19 | setContentView(R.layout.activity_main_viewpager)
20 |
21 | oneBottomLayout.setMenu(R.menu.navigation_menu)
22 |
23 | oneBottomLayout.attachViewPager(supportFragmentManager,viewPager, listOf(FirstFragment(),FiveFragment(),FirstFragment(),FiveFragment()))
24 | oneBottomLayout.setFloatingEnable(true)
25 | oneBottomLayout.setTopLineColor(Color.RED)
26 | oneBottomLayout.setItemColorStateList(R.drawable.item_check)
27 | oneBottomLayout.setMsgCount(0, 32)
28 | oneBottomLayout.setMsgCount(2, 1)
29 | oneBottomLayout.setMsgCount(1, -1)
30 | oneBottomLayout.setOnItemSelectedListener { item, position ->
31 | // if (position == 1) {
32 | // oneBottomLayout.setFloatingEnable(true)
33 | // } else {
34 | // oneBottomLayout.setFloatingEnable(false)
35 | // }
36 | false
37 | }
38 |
39 |
40 |
41 | }
42 |
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/OneBottomNavigationBar/src/main/java/cn/onestravel/one/navigation/utils/DensityUtils.kt:
--------------------------------------------------------------------------------
1 | package cn.onestravel.one.navigation.utils
2 |
3 | import android.content.Context
4 | import android.content.res.Resources
5 |
6 | /**
7 | * @author onestravel
8 | * @version 1.0.0
9 | * @name DensityUtils
10 | * @description //TODO
11 | * @createTime 2019/1/22 11:11
12 | */
13 | object DensityUtils {
14 |
15 | /**
16 | * dp转换为px
17 | *
18 | * @param context
19 | * @param dpValue
20 | * @return
21 | */
22 | fun dpToPx(context: Context, dpValue: Float): Int {//dp转换为px
23 | val scale = context.resources.displayMetrics.density//获得当前屏幕密度
24 | return (dpValue * scale + 0.5f).toInt()
25 | }
26 |
27 | /**
28 | * px转换为dp
29 | *
30 | * @param context
31 | * @param pxValue
32 | * @return
33 | */
34 | fun pxToDp(context: Context, pxValue: Float): Int {//
35 | val scale = context.resources.displayMetrics.density//获得当前屏幕密度
36 | return (pxValue / scale + 0.5f).toInt()
37 | }
38 |
39 | /**
40 | * dp转换为px
41 | *
42 | * @param resources
43 | * @param dpValue
44 | * @return
45 | */
46 | fun dpToPx(resources: Resources, dpValue: Float): Int {
47 | val scale = resources.displayMetrics.density//获得当前屏幕密度
48 | return (dpValue * scale + 0.5f).toInt()
49 | }
50 |
51 |
52 | /**
53 | * px转换为dp
54 | *
55 | * @param resources
56 | * @param pxValue
57 | * @return
58 | */
59 | fun pxToDp(resources: Resources, pxValue: Float): Int {//
60 | val scale = resources.displayMetrics.density//获得当前屏幕密度
61 | return (pxValue / scale + 0.5f).toInt()
62 | }
63 |
64 |
65 | /**
66 | * sp转换为px
67 | *
68 | * @param resources
69 | * @param spValue
70 | * @return
71 | */
72 | fun spToPx(resources: Resources, spValue: Float): Int {
73 | val scale = resources.displayMetrics.scaledDensity//获得当前屏幕密度
74 | return (spValue * scale + 0.5f).toInt()
75 | }
76 |
77 |
78 | /**
79 | * px转换为sp
80 | *
81 | * @param resources
82 | * @param pxValue
83 | * @return
84 | */
85 | fun pxToSp(resources: Resources, pxValue: Float): Int {//
86 | val scale = resources.displayMetrics.scaledDensity//获得当前屏幕密度
87 | return (pxValue / scale + 0.5f).toInt()
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/activity_main_viewpager.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | xmlns:android
14 |
15 | ^$
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | xmlns:.*
25 |
26 | ^$
27 |
28 |
29 | BY_NAME
30 |
31 |
32 |
33 |
34 |
35 |
36 | .*:id
37 |
38 | http://schemas.android.com/apk/res/android
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | .*:name
48 |
49 | http://schemas.android.com/apk/res/android
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | name
59 |
60 | ^$
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | style
70 |
71 | ^$
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | .*
81 |
82 | ^$
83 |
84 |
85 | BY_NAME
86 |
87 |
88 |
89 |
90 |
91 |
92 | .*
93 |
94 | http://schemas.android.com/apk/res/android
95 |
96 |
97 | ANDROID_ATTRIBUTE_ORDER
98 |
99 |
100 |
101 |
102 |
103 |
104 | .*
105 |
106 | .*
107 |
108 |
109 | BY_NAME
110 |
111 |
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/jcenter_publish.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.jfrog.bintray'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 | //apply plugin: 'org.jetbrains.dokka-android'
4 |
5 |
6 | if (project.hasProperty("kotlin")) { //Kotlin libraries
7 | task sourcesJar(type: Jar) {
8 | classifier = 'sources'
9 | from android.sourceSets.main.java.srcDirs
10 | }
11 |
12 | task javadoc(type: Javadoc) {
13 |
14 | }
15 | } else if (project.hasProperty("android")) { // Android libraries
16 | task sourcesJar(type: Jar) {
17 | classifier = 'sources'
18 | from android.sourceSets.main.java.srcDirs
19 | }
20 |
21 | task javadoc(type: Javadoc) {
22 | source = android.sourceSets.main.java.srcDirs
23 | // classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
24 | }
25 | } else { // Java libraries
26 | task sourcesJar(type: Jar, dependsOn: classes) {
27 | classifier = 'sources'
28 | from sourceSets.main.allSource
29 | }
30 | }
31 |
32 | task javadocJar(type: Jar, dependsOn: javadoc) {
33 | classifier = 'javadoc'
34 | from javadoc.destinationDir
35 | }
36 |
37 | //解决kotlin javadoc.options抱错
38 | //dokka {
39 | //// outputFormat = 'html'
40 | //// outputDirectory = "$buildDir/javadoc"
41 | //}
42 |
43 | tasks.withType(Javadoc) {
44 | options.addStringOption('Xdoclint:none', '-quiet')
45 | options.addStringOption('encoding', 'UTF-8')
46 | options.addStringOption('charSet', 'UTF-8')
47 | }
48 | artifacts {
49 | archives javadocJar
50 | archives sourcesJar
51 | }
52 | sourceSets {
53 | main.java.srcDirs += 'src/main/kotlin'
54 | }
55 |
56 | // project
57 | Properties propertiesProject = new Properties()
58 | propertiesProject.load(project.rootProject.file('project.properties').newDataInputStream())
59 |
60 | version = propertiesProject.getProperty("project.version")
61 | group = propertiesProject.getProperty("project.groupId")
62 | def versionName = propertiesProject.getProperty("project.version")
63 | def groupName = propertiesProject.getProperty("project.groupId")
64 | def projectRepo = propertiesProject.getProperty("project.repo")
65 | def artifact = propertiesProject.getProperty("project.artifact")
66 | def projectName = propertiesProject.getProperty("project.name")
67 | def projectDescription = propertiesProject.getProperty("project.description")
68 | def siteUrl = propertiesProject.getProperty("project.siteUrl")
69 | def gitUrl = propertiesProject.getProperty("project.gitUrl")
70 | def packageType = propertiesProject.getProperty("project.packaging")
71 | def licenseName = propertiesProject.getProperty("project.licenseName")
72 | def licenseUrl = propertiesProject.getProperty("project.licenseUrl")
73 | def allLicenses = propertiesProject.getProperty("project.allLicenses")
74 |
75 | // Bintray
76 | Properties propertiesLocal = new Properties()
77 | propertiesLocal.load(project.rootProject.file('local.properties').newDataInputStream())
78 |
79 | def developerId = propertiesLocal.getProperty("developer.id")
80 | def developerName = propertiesLocal.getProperty("developer.name")
81 | def developerEmail = propertiesLocal.getProperty("developer.email")
82 |
83 | install {
84 |
85 | repositories.mavenInstaller {
86 | // This generates POM.xml with proper parameters
87 | pom {
88 | project {
89 | packaging packageType
90 | groupId groupName
91 | artifactId artifact
92 |
93 | // Add your description here
94 | name projectName
95 | description projectDescription
96 | url siteUrl
97 |
98 | // Set your license
99 | licenses {
100 | license {
101 | name licenseName
102 | url licenseUrl
103 | }
104 | }
105 | developers {
106 | developer {
107 | id developerId
108 | name developerName
109 | email developerEmail
110 | }
111 | }
112 | scm {
113 | connection gitUrl
114 | developerConnection gitUrl
115 | url siteUrl
116 |
117 | }
118 | }
119 | }
120 | }
121 | }
122 |
123 |
124 | bintray {
125 | user = propertiesLocal.getProperty("bintray.user")
126 | key = propertiesLocal.getProperty("bintray.apikey")
127 |
128 | configurations = ['archives']
129 | pkg {
130 | repo = projectRepo
131 | name = projectName
132 | desc = projectDescription
133 | websiteUrl = siteUrl
134 | vcsUrl = gitUrl
135 | licenses = ["Apache-2.0"]
136 | publish = true
137 | publicDownloadNumbers = true
138 | version {
139 | name = versionName
140 | desc = projectDescription
141 | // gpg {
142 | // sign = true //Determines whether to GPG sign the files. The default is false
143 | // passphrase = properties.getProperty("bintray.gpg.password")
144 | // //Optional. The passphrase for GPG signing'
145 | // }
146 | }
147 | }
148 | }
149 | //./gradlew install
150 | //./gradlew bintrayUpload
151 |
152 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/demo/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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # [OneBottomNavigationBar](https://github.com/onestravel/OneBottomNavigationBar) 使用说明
4 |
5 | ## 简介:
6 |
7 | ##### OneBottomNavigationBar 是自定义的一个实现App应用底部导航栏功能的View,可以实现底部 2-5 个导航菜单(一般不会有更多),可以实现某一个菜单凸起的效果,如,有5个菜单,可以选择让第三个菜单凸起(floating),这是很多App都有的功能; 可以根据编写的颜色变化的资源文件来更改图标和文字选中时和未选中时的颜色,可以自由控制是否需要选中(checkable),选择开启时,可变换为选中颜色,选择关闭时,不能更改为选择颜色;可以控制默认选中哪一项;可以设置某一个导航菜单的未读消息数(数字或者小红点)。
8 |
9 | ### 先看一组效果图
10 |
11 | #### 五个菜单,没有凸起的,都是可选中的
12 |
13 | 
14 |
15 | 图1
16 |
17 | #### 中间有凸起,并且中间的不能选中,但点击事件可以响应
18 |
19 | 
20 |
21 | 图2
22 |
23 | ## 引入方法
24 |
25 | ### jcenter
26 |
27 | VERSION: [  ](https://bintray.com/onestravel/one/OneBottomNavigationBar)
28 |
29 | - 在model 中的build.gradle 中增加依赖
30 |
31 | ```
32 | dependencies {
33 | implementation 'cn.onestravel.one:one_bottom_navigationbar:VERSION'
34 | }
35 |
36 | ```
37 | 例如:
38 | ```
39 | dependencies {
40 | implementation 'cn.onestravel.one:one_bottom_navigationbar:1.1.1'
41 | }
42 | ```
43 |
44 | ### jitPack
45 |
46 | VERSION: [](https://jitpack.io/#onestravel/BottomNavigationBar)
47 |
48 |
49 | - 在项目中的根目录下的 build.gradle (与model同级的) 中增加如下配置
50 |
51 | ```
52 |
53 | allprojects {
54 | repositories {
55 | ...
56 | maven { url 'https://jitpack.io' }
57 | }
58 | }
59 |
60 | ```
61 |
62 | - 在model 中的build.gradle 中增加依赖
63 |
64 | ```
65 | dependencies {
66 | implementation 'com.github.onestravel:OneBottomNavigationBar:VERSION'
67 | }
68 |
69 | ```
70 | 例如:
71 | ```
72 | dependencies {
73 | implementation 'com.github.onestravel:OneBottomNavigationBar:1.1.1'
74 | }
75 | ```
76 |
77 | ## 属性说明
78 |
79 | ### OneBottomNavigationBar 属性说明
80 |
81 | | 属性 | 参考值 | 说明 |
82 | | ------------------ | ---------------------- | ------------------------------------------------------------ |
83 | | app:oneItemIconTint | @drawable/tab_selecter | 整体的tab菜单的图片选中和未选中的颜色变化,传入一个资源drawable文件 |
84 | | app:oneItemTextColor | @drawable/tab_selecter | @drawable/tab_selecter@drawable/tab_selecter整体的tab菜单的图片选中和未选中的颜色变化,传入一个资源drawable文件 |
85 | | app:oneFloatingEnable | true/false | 是否开启浮动,默认为false,设置为true是,可以实现中间凸起 |
86 | | app:oneFloatingUp | 20dp | 设置Tab的上浮尺寸,比如:上浮20dp,上浮尺寸不可超过整个菜单高度的1/2 |
87 | | app:oneMenu | @menu/botom_menu | BottomNavigationBar导航栏的关键,设置导航栏的tab菜单 |
88 | | app:oneItemTextSize | 15sp | 设置导航栏文字的大小 |
89 | | app:oneItemIconWidth | 30dp | 设置导航栏Icon的宽度 |
90 | | app:oneItemIconHeight | 30dp | 设置导航栏Icon的高度 |
91 | | app:oneItemTextTopMargin | 5dp | 设置导航栏文字和Icon的间隔高度 |
92 | | app:oneItemTopLineColor |#CCCCCC | 设置导航栏顶部分割线颜色,想去掉该分割线可设置透明色 |
93 | | app:oneItemPadding |5dp | 设置正常导航栏上下边距 |
94 | | app:oneFloatingPadding |2dp | 设置浮动导航栏上下边距 |
95 |
96 |
97 | #### 示例1:不需要浮动(凸起)的菜单,图1效果
98 |
99 | ```
100 |
101 |
110 |
111 |
112 |
113 | ```
114 |
115 | #### 示例2:需要浮动(凸起)的菜单,图2效果
116 |
117 | ```
118 |
129 |
130 |
131 | ```
132 |
133 | ### menu 菜单属性值说明
134 |
135 | | 属性 | 参考值 | 说明 |
136 | | ----------------- | ------------------ | ------------------------------------------------------------ |
137 | | android:id | @+id/tab1 | 导航菜单 Item 的ID; |
138 | | android:icon | @drawable/bar_news | 导航菜单 Item 的图标,可以是图标选择器(selector),也可以是默认图标,根据与OneBottomNavigationBar 的属性 app:oneItemIconTint 更改选中与不选中的颜色变化,默认为蓝色和灰色; |
139 | | android:title | 首页 | 导航菜单 Item 的文字,可以默认为空字符串,表示不设置; |
140 | | android:checkable | true/false | 设置导航菜单 Item 是否可以选择,值影响选择与不选中效果,不影响点击事件; |
141 | | android:checked | true/false | 设置导航菜单 Item 是否默认选中,默认为第一个选中,请不要在多个Item上设置改; |
142 | | app:floating | true/false | 设置该导航菜单 Item 是否浮动,与OneBottomNavigationBar 的app:floatingEnable和 app:oneFloatingUp属性配合使用,默认为false,即不浮动(不凸起); |
143 |
144 | #### 示例1:不需要浮动(凸起)的菜单,图1效果
145 |
146 | ```
147 |
148 |
172 | ```
173 |
174 | #### 示例2:需要浮动(凸起)的菜单,图2效果
175 |
176 | ```
177 |
178 |
204 | ```
205 |
206 | ### 设置点击切换监听
207 | **在NavigationBar的Tab进行切换时,会回调改方法,可进行相应处理,如:未读消息数设置**
208 | ```
209 | bottomView.setOnItemSelectedListener(new OneBottomNavigationBar.OnItemSelectedListener() {
210 | @Override
211 | public void onItemSelected(OneBottomNavigationBar.Item item, int position) {
212 | if(position==2){
213 | bottomView.setFloatingEnable(true);
214 | }else {
215 | bottomView.setFloatingEnable(false);
216 | }
217 | }
218 | });
219 | ```
220 |
221 | ### 添加Fragment进行管理,点击自动切换
222 | **1. 需要先设置FragmentManager管理器和加载Fragment的ViewGroup,一般为FrameLayout ,需要设置id;之后调用addFragment,为对应的Tab添加Fragment,**
223 | ```java
224 | bottomView.setFragmentManager(getFragmentManager(),mainFragment);
225 | bottomView.addFragment(R.id.tab1,new FirstFragment());
226 | bottomView.addFragment(R.id.tab2,new SecondFragment());
227 | bottomView.addFragment(R.id.tab3,new ThirdFragment());
228 | bottomView.addFragment(R.id.tab4,new FourFragment());
229 | bottomView.addFragment(R.id.tab5,new FiveFragment());
230 | ```
231 | **2. 使用 ViewPager 来管理切换 Fragment** begin 1.2.4-beta
232 | java
233 |
234 | ```java
235 | ArrayList fragments = new ArrayList<>();
236 | fragments.add(new FirstFragment());
237 | fragments.add(new SecondFragment());
238 | fragments.add(new ThirdFragment());
239 | fragments.add(new FourFragment());
240 | fragments.add(new FiveFragment());
241 | bottomView.attachViewPager(getSupportFragmentManager(),viewPager, fragments);
242 | ```
243 |
244 | kotlin
245 |
246 | ```kotlin
247 | bottomView.attachViewPager(supportFragmentManager,viewPager, listOf(FirstFragment(),ThirdFragment(),FourFragment(),FiveFragment()))
248 | ```
249 |
250 | 注意:如果 tab 中有不需要展示 Fragment 的时候,在使用 ViewPager 管理切换 Fragment 时,也不应该包含对应的 Fragment 对象
251 |
252 |
253 | ### 版本更新说明
254 |
255 |
256 | #### 1.2.4-beta
257 | - 修复菜单突出时,上边界划线失效问题
258 | - 支持 Viewpager 切换 Fragment
259 |
260 |
261 | #### 1.2.2
262 | - 修复菜单突出时,上边界划线失效问题
263 |
264 |
265 | #### 1.2.0
266 | - 优化图标尺寸计算方式
267 | - 优化纬度角标绘制位置
268 | - 新增参数 ``app:oneItemPadding`` 和 ``app:oneFloatingPadding`` 设置上下边距
269 |
270 |
271 | #### 1.1.1
272 | - 开发语言更换为 kotlin
273 | - 新增使用androidx.fragment.app.Fragment和androidx.fragment.app.FragmentManager管理fragment的支持,
274 | 包路径为:cn.onestravel.one.navigation.androidx.OneBottomNavigationBar
275 | - 在jcenter上发布新包
276 |
277 |
278 | #### 1.1.0
279 | - 更换属性,部分属性前增加one前缀,解决属性冲突问题
280 | - BottomNavigationBar 更换为 OneBottomNavigationBar
281 | - 增加顶部分割线颜色属性,可设置分割线颜色(或透明色)
282 |
283 |
284 | #### 1.0.6
285 | - 可以Java Api 设置导航栏文字大小
286 | - 可以Java Api 设置图标的宽度和高度
287 | - Java Api 设置图标和文字间隔高度
288 | - 支持管理Fragment ,实现Fragment点击自动切换
289 |
290 |
291 | #### 1.0.5
292 | - 可以自定义导航栏文字大小
293 | - 可以自定义图标的宽度和高度
294 | - 自定义图标和文字间隔高度
295 |
296 | #### 1.0.4
297 | - 优化选中突出效果,支持选中放大,支持导航栏背景圆角
298 |
299 | #### 1.0.3
300 | - 在原基础上对封装进行优化,支持代码实现导航栏
301 |
302 |
303 | #### 1.0.2
304 | - 初版实现自定义底部导航栏
305 |
306 |
307 |
308 |
309 |
310 | # 温馨提示:
311 | **在使用过程中,如遇到任何问题,可发送邮件至server@onestravel.cn说明相关问题,我在看到邮件第一时间,会针对相应问题进行沟通解决,谢谢支持!**#
312 |
--------------------------------------------------------------------------------
/.idea/dbnavigator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
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 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
--------------------------------------------------------------------------------
/OneBottomNavigationBar/src/main/java/cn/onestravel/one/navigation/androidx/OneBottomNavigationBarX.kt:
--------------------------------------------------------------------------------
1 | package cn.onestravel.one.navigation.androidx
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import android.content.res.ColorStateList
6 | import android.graphics.Bitmap
7 | import android.graphics.Canvas
8 | import android.graphics.Color
9 | import android.graphics.Paint
10 | import android.graphics.PixelFormat
11 | import android.graphics.PorterDuff
12 | import android.graphics.Rect
13 | import android.graphics.drawable.BitmapDrawable
14 | import android.graphics.drawable.ColorDrawable
15 | import android.graphics.drawable.Drawable
16 | import android.graphics.drawable.GradientDrawable
17 | import android.graphics.drawable.NinePatchDrawable
18 | import android.graphics.drawable.StateListDrawable
19 | import android.os.Build
20 |
21 | import androidx.annotation.ColorInt
22 | import androidx.annotation.ColorRes
23 | import androidx.annotation.DrawableRes
24 | import androidx.annotation.IdRes
25 | import androidx.annotation.MenuRes
26 | import androidx.core.content.res.ResourcesCompat
27 | import androidx.core.graphics.drawable.DrawableCompat
28 |
29 | import android.text.TextUtils
30 | import android.util.AttributeSet
31 | import android.util.Log
32 | import android.view.MotionEvent
33 | import android.view.View
34 | import android.view.ViewGroup
35 | import android.widget.FrameLayout
36 | import android.widget.ImageView
37 | import android.widget.LinearLayout
38 | import android.widget.RelativeLayout
39 | import androidx.fragment.app.Fragment
40 | import androidx.fragment.app.FragmentManager
41 | import androidx.fragment.app.FragmentPagerAdapter
42 | import androidx.viewpager.widget.PagerAdapter
43 | import androidx.viewpager.widget.ViewPager
44 | import cn.onestravel.one.navigation.BuildConfig
45 |
46 | import org.xmlpull.v1.XmlPullParser
47 | import org.xmlpull.v1.XmlPullParserException
48 |
49 | import java.io.IOException
50 |
51 | import cn.onestravel.one.navigation.R
52 | import cn.onestravel.one.navigation.utils.DensityUtils
53 | import java.util.*
54 | import kotlin.math.sqrt
55 |
56 | /**
57 | * @author onestravel
58 | * @createTime 2019/1/20 9:48 AM
59 | * @description 可以凸起的底部导航菜单VIEW
60 | */
61 |
62 | typealias OnItemSelectedListener = (item: OneBottomNavigationBar.Item, position: Int) -> Boolean
63 |
64 | class OneBottomNavigationBar : View {
65 | private var mViewPager: ViewPager? = null
66 | private var mLayoutParams: ViewGroup.LayoutParams? = null
67 | private val TAG = "BottomNavigationBar"
68 |
69 | // 导航菜单键列表
70 | private var itemList: MutableList- = ArrayList()
71 |
72 | //总宽度 width
73 | private var mWidth = 0
74 |
75 | //总高度 height
76 | private var mHeight = 0
77 |
78 | //每个菜单的宽度 item width
79 | private var mItemWidth = 0
80 |
81 | //每个菜单的告诉 item height
82 | private var mItemHeight = 0
83 |
84 | //整体的上边距
85 | private var topPadding = DensityUtils.dpToPx(resources, 3f)
86 |
87 | //整体下边距
88 | private var bottomPadding = DensityUtils.dpToPx(resources, 3f)
89 |
90 | //文字相对于图标的边距
91 | private var textTop = DensityUtils.dpToPx(resources, 3f)
92 |
93 | //画笔
94 | private val mTextPaint: Paint by lazy { Paint() }
95 |
96 | //图标的状态颜色列表
97 | private var itemIconTintRes: ColorStateList? = null
98 |
99 | //文字的状态颜色列表
100 | private var itemColorStateList: ColorStateList? = null
101 |
102 | //Item菜单的选中事件
103 | private var onItemSelectedListener: OnItemSelectedListener? = null
104 |
105 | // 当前选中的坐标位置
106 | private var checkedPosition = 0
107 | private var showPosition = 0
108 |
109 | //是否开启上浮
110 | private var floatingEnable: Boolean = false
111 |
112 | //上浮距离
113 | private var floatingUp: Int = 0
114 |
115 | //背景资源
116 | private var bgDrawable: Drawable? = null
117 |
118 | //菜单的布局文件
119 | @MenuRes
120 | private var menuRes: Int = 0
121 | private var titleSize: Int = 0
122 | private var itemIconWidth: Int = 0
123 | private var itemIconHeight: Int = 0
124 | private var itemPadding: Int = 0
125 | private var itemFloatingPadding: Int = 0
126 | private val fragmentMap: MutableMap = HashMap()
127 | private var manager: FragmentManager? = null
128 | private var containerView: View? = null
129 | private var currentFragment: Fragment? = null
130 | /**
131 | * 是否替换Fragment,替换后Fragment 数据会清空
132 | *
133 | * @return
134 | */
135 | /**
136 | * 设置是否替换Fragment,替换后Fragment 数据会清空
137 | *
138 | * @param replace
139 | */
140 | var isReplace: Boolean = false
141 | private var linePaint: Paint? = null
142 | private val lineWidth by lazy { DensityUtils.dpToPx(context, 1f).toFloat() }
143 | private var topLineColor: Int = 0
144 | private final val DEFAULT_MSG_COUNT_TEXT_PADDING: Int = DensityUtils.dpToPx(resources, 2f)
145 |
146 | constructor(context: Context) : super(context) {
147 | init(context, null, 0)
148 | }
149 |
150 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
151 | init(context, attrs, 0)
152 | }
153 |
154 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
155 | init(context, attrs, defStyleAttr)
156 | }
157 |
158 |
159 | /**
160 | * 设置选中的监听事件
161 | *
162 | * @param onItemSelectedListener return true 选中事件由调用者自己处理
163 | * return false 选中事件将有本管理器自动实现
164 | */
165 | fun setOnItemSelectedListener(onItemSelectedListener: OnItemSelectedListener) {
166 | this.onItemSelectedListener = onItemSelectedListener
167 | }
168 |
169 | /**
170 | * 设置选中
171 | *
172 | * @param position 选中位置
173 | */
174 | fun setSelected(position: Int, vpPosition: Int = -1) {
175 | if (position < 0 || position >= itemList.size) {
176 | return
177 | }
178 | val item = itemList[position]
179 | if (item.isCheckable) {
180 | if (checkedPosition >= 0) {
181 | itemList[checkedPosition].isChecked = false
182 | }
183 | item.isChecked = true
184 | checkedPosition = position
185 | }
186 | postInvalidate()
187 | if (onItemSelectedListener != null && onItemSelectedListener!!.invoke(item, position)) {
188 | return
189 | }
190 | try {
191 | if (!item.showFragment) {
192 | return
193 | }
194 | if (mViewPager != null) {
195 | showPosition = if (vpPosition == -1) {
196 | if (needChangePos(position)) {
197 | 0.coerceAtLeast(position - 1)
198 | } else {
199 | position
200 | }
201 | } else {
202 | vpPosition
203 | }
204 | mViewPager?.currentItem = showPosition
205 | } else if (manager != null || containerView != null || containerView is ViewGroup || containerView!!.id != View.NO_ID) {
206 | showPosition = position;
207 | val fragment = fragmentMap[item.id]
208 | ?: throw RuntimeException("[" + item.id + "] fragment is null ")
209 | selectFragmentByManager(fragment)
210 | }
211 |
212 | } catch (e: Exception) {
213 | e.printStackTrace()
214 | }
215 |
216 | }
217 |
218 | /**
219 | * 绑定 ViewPager 使用,ViewPager 使用的 Fragment 数量需要与 Tab 数量一致,否则会出现 Fragment 显示与 tab 选中状态不对应的情况
220 | * @param viewPager
221 | */
222 | fun attachViewPager(fragmentManager: FragmentManager, viewPager: ViewPager, fragments: List) {
223 | this.mViewPager = viewPager
224 | if (this.mViewPager != null) {
225 | mViewPager?.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
226 | override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
227 | }
228 |
229 | override fun onPageSelected(position: Int) {
230 | val item = itemList[position]
231 | var newPos = position
232 | if (needChangePos(position)) {
233 | newPos = position + 1
234 | }
235 | setSelected(newPos, position)
236 | }
237 |
238 | override fun onPageScrollStateChanged(state: Int) {
239 | }
240 | })
241 | mViewPager?.adapter = ViewpagerAdapter(fragmentManager, fragments)
242 | mViewPager?.currentItem = 0
243 | }
244 | }
245 |
246 | private fun needChangePos(position: Int): Boolean {
247 | val notShowPos = findNotShowFragmentPos()
248 | if (notShowPos in 0..position) {
249 | return true
250 | }
251 | return false
252 | }
253 |
254 | private fun findNotShowFragmentPos(): Int {
255 | var pos = -1
256 | if (itemList == null || itemList.isEmpty()) {
257 | return pos
258 | }
259 | val item = itemList.find { item -> !item.showFragment }
260 | if (item != null) {
261 | pos = itemList.indexOf(item);
262 | }
263 | return pos;
264 | }
265 |
266 | /**
267 | * 设置未读消息数
268 | *
269 | * @param position 未读消息数的位置
270 | * @param count 未读消息数量 <0 是显示为小红点,没有数字
271 | * == 0 时不显示未读消息红点
272 | * >0 && <100 时显示对应的消息数量
273 | * >=100 时显示 99+
274 | */
275 | fun setMsgCount(position: Int, count: Int) {
276 | if (position < itemList.size) {
277 | itemList[position].msgCount = count
278 | postInvalidate()
279 | }
280 | }
281 |
282 |
283 | /**
284 | * 设置Menu 菜单资源文件
285 | *
286 | * @param menuRes
287 | */
288 | fun setMenu(@MenuRes menuRes: Int) {
289 | this.menuRes = menuRes
290 | parseXml(menuRes)
291 | format()
292 | postInvalidate()
293 | }
294 |
295 | /**
296 | * 设置Item 菜单的图标颜色状态列表
297 | *
298 | * @param resId 图标颜色状态的资源文件
299 | */
300 | fun setItemIconTint(@DrawableRes @ColorRes resId: Int) {
301 | this.itemIconTintRes = ResourcesCompat.getColorStateList(resources, resId, null)
302 | parseXml(menuRes)
303 | format()
304 | postInvalidate()
305 | }
306 |
307 | /**
308 | * 设置Item 菜单的文字颜色状态列表
309 | *
310 | * @param resId 文字颜色状态的资源文件
311 | */
312 | fun setItemColorStateList(@DrawableRes @ColorRes resId: Int) {
313 | this.itemColorStateList = ResourcesCompat.getColorStateList(resources, resId, null)
314 | postInvalidate()
315 | }
316 |
317 |
318 | /**
319 | * 设置分割线颜色
320 | * @param color
321 | */
322 | fun setTopLineColor(@ColorInt color: Int) {
323 | this.topLineColor = color
324 | invalidate()
325 | }
326 |
327 |
328 | /**
329 | * 设置分割线颜色
330 | * @param colorRes
331 | */
332 | fun setTopLineColorRes(@ColorRes colorRes: Int) {
333 | this.topLineColor = resources.getColor(colorRes)
334 | invalidate()
335 | }
336 |
337 |
338 | /**
339 | * 设置是否开启浮动
340 | *
341 | * @param floatingEnable
342 | */
343 | fun setFloatingEnable(floatingEnable: Boolean) {
344 | this.floatingEnable = floatingEnable
345 | postInvalidate()
346 | }
347 |
348 | /**
349 | * 设置上浮距离,不能超过导航栏高度的1/2
350 | *
351 | * @param floatingUp
352 | */
353 | fun setFloatingUp(floatingUp: Int) {
354 | this.floatingUp = floatingUp
355 | postInvalidate()
356 | }
357 |
358 | /**
359 | * 设置FragmentManager,管理fragment
360 | *
361 | * @param fragmentManager fragment管理
362 | * @param fragmentContainerView fragment 将要添加的view
363 | */
364 | fun setFragmentManager(fragmentManager: FragmentManager, fragmentContainerView: View) {
365 | this.manager = fragmentManager
366 | this.containerView = fragmentContainerView
367 | }
368 |
369 | /**
370 | * 添加Fragment
371 | *
372 | * @param tabId
373 | * @param fragment
374 | */
375 | fun addFragment(@IdRes tabId: Int, fragment: Fragment) {
376 | fragmentMap[tabId] = fragment
377 | }
378 |
379 | /**
380 | * 获取布局参数
381 | *
382 | * @return
383 | */
384 | override fun getLayoutParams(): ViewGroup.LayoutParams {
385 | return super.getLayoutParams()
386 | }
387 |
388 | /**
389 | * 设置图标大小
390 | *
391 | * @param itemIconWidth
392 | * @param itemIconHeight
393 | */
394 | fun setItemIconSize(itemIconWidth: Int, itemIconHeight: Int) {
395 | this.itemIconWidth = itemIconWidth
396 | this.itemIconHeight = itemIconHeight
397 | format()
398 | postInvalidate()
399 | }
400 |
401 | /**
402 | * 设置Title文字大小
403 | *
404 | * @param titleSize
405 | */
406 | fun setTitleSize(titleSize: Int) {
407 | this.titleSize = titleSize
408 | format()
409 | postInvalidate()
410 | }
411 |
412 | /**
413 | * 设置图标和title文字间距
414 | *
415 | * @param textTopMargin
416 | */
417 | fun setTextTopMargin(textTopMargin: Int) {
418 | this.textTop = textTopMargin
419 | postInvalidate()
420 | }
421 |
422 | override fun onAttachedToWindow() {
423 | super.onAttachedToWindow()
424 | if (parent != null && parent is ViewGroup) {
425 | (parent as ViewGroup).clipChildren = false
426 | }
427 | }
428 |
429 | override fun setLayoutParams(params: ViewGroup.LayoutParams?) {
430 | super.setLayoutParams(params)
431 | updateLayoutParams()
432 | }
433 |
434 | private fun updateLayoutParams() {
435 | val params = layoutParams;
436 | if (floatingEnable) {
437 | val floatingUp = getFloatingUpHeight()
438 | when (params) {
439 | is LinearLayout.LayoutParams -> {
440 | params.topMargin = 0 - floatingUp
441 | }
442 | is RelativeLayout.LayoutParams -> {
443 | params.topMargin = 0 - floatingUp
444 | }
445 | is FrameLayout.LayoutParams -> {
446 | params.topMargin = 0 - floatingUp
447 | }
448 | is ViewGroup.MarginLayoutParams -> {
449 | params.topMargin = 0 - floatingUp
450 | }
451 | }
452 | }
453 | }
454 |
455 |
456 | /**
457 | * 初始化,获取该View的自定义属性,以及item 列表
458 | *
459 | * @param context 上下文
460 | * @param attrs 属性
461 | * @param defStyleAttr 默认样式
462 | */
463 | @SuppressLint("ResourceType")
464 | private fun init(context: Context, attrs: AttributeSet?, defStyleAttr: Int) {
465 | if (attrs != null) {
466 | val ta = context.obtainStyledAttributes(attrs, R.styleable.One_StyleBottomLayout)
467 | itemIconTintRes = ta.getColorStateList(R.styleable.One_StyleBottomLayout_oneItemIconTint)
468 | itemColorStateList = ta.getColorStateList(R.styleable.One_StyleBottomLayout_oneItemTextColor)
469 | if (itemColorStateList == null) {
470 | itemColorStateList = ResourcesCompat.getColorStateList(resources, R.drawable.default_blue_tab_tint, null)
471 | }
472 | topLineColor = ta.getColor(R.styleable.One_StyleBottomLayout_oneItemTopLineColor, Color.TRANSPARENT)
473 | floatingEnable = ta.getBoolean(R.styleable.One_StyleBottomLayout_oneFloatingEnable, false)
474 | floatingUp = ta.getDimension(R.styleable.One_StyleBottomLayout_oneFloatingUp, 20f).toInt()
475 | titleSize = ta.getDimension(R.styleable.One_StyleBottomLayout_oneItemTextSize, DensityUtils.spToPx(resources, 12f).toFloat()).toInt()
476 | textTop = ta.getDimension(R.styleable.One_StyleBottomLayout_oneItemTextTopMargin, DensityUtils.dpToPx(resources, 3f).toFloat()).toInt()
477 | itemIconWidth = ta.getDimension(R.styleable.One_StyleBottomLayout_oneItemIconWidth, 0f).toInt()
478 | itemIconHeight = ta.getDimension(R.styleable.One_StyleBottomLayout_oneItemIconHeight, 0f).toInt()
479 | itemPadding = ta.getDimension(R.styleable.One_StyleBottomLayout_oneItemPadding, 0f).toInt()
480 | itemFloatingPadding = ta.getDimension(R.styleable.One_StyleBottomLayout_oneFloatingPadding, 0f).toInt()
481 | val xmlRes = ta.getResourceId(R.styleable.One_StyleBottomLayout_oneMenu, 0)
482 | parseXml(xmlRes)
483 | }
484 | format()
485 | }
486 |
487 | /**
488 | * 处理数据
489 | */
490 | private fun format() {
491 | if (itemList.size > 5) {
492 | itemList = itemList.subList(0, 5)
493 | }
494 | bgDrawable = if (background != null && background is ColorDrawable) {
495 | background
496 | } else if (background is StateListDrawable) {
497 | background
498 | } else if (background is GradientDrawable) {
499 | background
500 | } else {
501 | ColorDrawable(Color.WHITE)
502 | }
503 | for (item in itemList) {
504 | item.titleSize = titleSize
505 | item.iconWidth = itemIconWidth
506 | item.iconHeight = itemIconHeight
507 | if (item.isFloating) {
508 | item.padding = itemFloatingPadding
509 | } else {
510 | item.padding = itemPadding;
511 | }
512 | }
513 | linePaint = createPaint(topLineColor, Paint.Style.FILL, lineWidth)
514 | }
515 |
516 | /**
517 | * 解析 menu 的 xml 的文件,得到相关的 导航栏菜单
518 | *
519 | * @param xmlRes
520 | */
521 | private fun parseXml(xmlRes: Int) {
522 | try {
523 | if (xmlRes == 0) {
524 | return
525 | }
526 | itemList.clear()
527 | val xmlParser = resources.getXml(xmlRes)
528 | var event = xmlParser.eventType //先获取当前解析器光标在哪
529 | while (event != XmlPullParser.END_DOCUMENT) { //如果还没到文档的结束标志,那么就继续往下处理
530 | when (event) {
531 | XmlPullParser.START_DOCUMENT -> {
532 | if (BuildConfig.DEBUG) {
533 | Log.e(TAG, "xml解析开始")
534 | }
535 | }
536 | XmlPullParser.START_TAG ->
537 | //一般都是获取标签的属性值,所以在这里数据你需要的数据
538 | // Log.e(TAG, "当前标签是:" + xmlParser.getName());
539 | if (xmlParser.name == "item") {
540 | val item = Item()
541 | for (i in 0 until xmlParser.attributeCount) {
542 | //两种方法获取属性值
543 | // Log.e(TAG, "第" + (i + 1) + "个属性:" + xmlParser.getAttributeName(i)
544 | // + ": " + xmlParser.getAttributeValue(i));
545 | if ("id".equals(xmlParser.getAttributeName(i), ignoreCase = true)) {
546 | item.id = xmlParser.getAttributeResourceValue(i, 0)
547 | } else if ("icon".equals(xmlParser.getAttributeName(i), ignoreCase = true)) {
548 | val drawableId = xmlParser.getAttributeResourceValue(i, 0)
549 | val drawable = ResourcesCompat.getDrawable(resources, drawableId, null)
550 | item.drawable = drawable!!.constantState!!.newDrawable()
551 | var stateListDrawable = StateListDrawable()
552 | if (drawable is StateListDrawable) {
553 | stateListDrawable = drawable
554 | stateListDrawable.state = intArrayOf(android.R.attr.state_checked)
555 | stateListDrawable.mutate()
556 | } else {
557 | val selectedDrawable = tintListDrawable(drawable, itemIconTintRes)
558 | selectedDrawable.state = intArrayOf(android.R.attr.state_checked)
559 | stateListDrawable.addState(intArrayOf(android.R.attr.state_checked), selectedDrawable.current)
560 | stateListDrawable.addState(intArrayOf(android.R.attr.state_selected), selectedDrawable.current)
561 | stateListDrawable.addState(intArrayOf(android.R.attr.state_pressed), selectedDrawable.current)
562 | stateListDrawable.addState(intArrayOf(android.R.attr.state_focused), selectedDrawable.current)
563 | selectedDrawable.state = intArrayOf()
564 | stateListDrawable.addState(intArrayOf(), selectedDrawable.current)
565 | }
566 | item.icon = stateListDrawable
567 | } else if ("title" == xmlParser.getAttributeName(i)) {
568 | val titleId = xmlParser.getAttributeResourceValue(i, 0)
569 | if (titleId > 0) {
570 | item.title = resources.getString(titleId)
571 | } else {
572 | item.title = xmlParser.getAttributeValue(i)
573 | }
574 | } else if ("floating" == xmlParser.getAttributeName(i)) {
575 | item.isFloating = xmlParser.getAttributeBooleanValue(i, false)
576 | } else if ("checked" == xmlParser.getAttributeName(i)) {
577 | item.isChecked = xmlParser.getAttributeBooleanValue(i, false)
578 | } else if ("checkable" == xmlParser.getAttributeName(i)) {
579 | item.isCheckable = xmlParser.getAttributeBooleanValue(i, false)
580 | } else if ("showFragment" == xmlParser.getAttributeName(i)) {
581 | item.showFragment = xmlParser.getAttributeBooleanValue(i, true)
582 | }
583 | }
584 | if (item.isCheckable && item.isChecked) {
585 | checkedPosition = itemList.size
586 | }
587 | itemList.add(item)
588 | }
589 | XmlPullParser.TEXT -> {
590 | }
591 | XmlPullParser.END_TAG -> {
592 | if (BuildConfig.DEBUG) {
593 | Log.e(TAG, "xml解析结束")
594 | }
595 | }
596 | else -> {
597 | }
598 | }// Log.e(TAG, "Text:" + xmlParser.getText());
599 | event = xmlParser.next() //将当前解析器光标往下一步移
600 | }
601 | } catch (e: XmlPullParserException) {
602 | e.printStackTrace()
603 | } catch (e: IOException) {
604 | e.printStackTrace()
605 | }
606 |
607 | }
608 |
609 |
610 | /**
611 | * 当初始化布局以后,进行默认选中
612 | *
613 | * @param changed
614 | * @param left
615 | * @param top
616 | * @param right
617 | * @param bottom
618 | */
619 | override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
620 | super.onLayout(changed, left, top, right, bottom)
621 | setSelected(checkedPosition, showPosition)
622 | }
623 |
624 | /**
625 | * 尺寸测量
626 | *
627 | * @param widthMeasureSpec
628 | * @param heightMeasureSpec
629 | */
630 | override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
631 | val specMode = MeasureSpec.getMode(heightMeasureSpec)
632 | mWidth = MeasureSpec.getSize(widthMeasureSpec)
633 | mItemWidth = (mWidth - paddingLeft - paddingRight) / itemList.size
634 | topPadding = paddingTop
635 | bottomPadding = paddingBottom
636 | setTextPaint(titleSize, Color.BLACK)
637 | val textHeight = getTextHeight("首页", mTextPaint)
638 | mHeight = if (specMode == View.MeasureSpec.AT_MOST) {
639 | itemIconHeight = if (itemIconHeight < 50) itemIconHeight else 50
640 | topPadding + bottomPadding + itemIconHeight + textHeight + textTop + itemPadding * 2
641 | } else {
642 | val height = MeasureSpec.getSize(heightMeasureSpec)
643 | this.itemIconHeight = height - topPadding - bottomPadding - textHeight - textTop - itemPadding * 2
644 | height
645 | }
646 | this.itemIconWidth = this.itemIconHeight
647 | mHeight += getFloatingUpHeight()
648 | mItemHeight = mHeight
649 | super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(mHeight, specMode))
650 | layoutParams = layoutParams
651 | }
652 |
653 |
654 | /**
655 | * 进行绘制
656 | *
657 | * @param canvas
658 | */
659 | override fun onDraw(canvas: Canvas) {
660 | super.onDraw(canvas)
661 | var floatingUpInt = getFloatingUpHeight()
662 | canvas.drawLine(0f, floatingUpInt.toFloat(), mWidth.toFloat(), floatingUpInt.toFloat(), linePaint!!)
663 | //画背景
664 | drawFloating(canvas)
665 |
666 | val rectInit = Rect()
667 | rectInit.set(0, (floatingUpInt + lineWidth / 2).toInt(), mWidth, mHeight)
668 | bgDrawable!!.bounds = rectInit
669 | bgDrawable!!.draw(canvas)
670 |
671 | //画Floating
672 | //画出所有导航菜单
673 | if (itemList.size > 0) {
674 | for (i in itemList.indices) {
675 | val item = itemList[i]
676 | drawItem(canvas, item, i)
677 | }
678 | }
679 |
680 | }
681 |
682 | /**
683 | * 画出上浮图标的背景
684 | *
685 | * @param canvas
686 | */
687 | private fun drawFloating(canvas: Canvas) {
688 | if (!floatingEnable) {
689 | return
690 | }
691 | if (itemList.size > 0) {
692 | for (i in itemList.indices) {
693 | val item = itemList[i]
694 | if (item.isFloating) {
695 | var rect = getIconRect(item, i)
696 | val x = (rect.left + rect.right) / 2
697 | val y = (rect.top + rect.bottom) / 2
698 | val paint = createPaint(Color.WHITE, Paint.Style.FILL, 0f)
699 | val r = y - linePaint!!.strokeWidth / 2
700 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
701 | paint.colorFilter = bgDrawable!!.colorFilter
702 | }
703 | linePaint!!.style = Paint.Style.STROKE
704 | canvas.drawCircle(x.toFloat(), y.toFloat(), r, linePaint!!)
705 | paint.style = Paint.Style.FILL
706 | canvas.drawCircle(x.toFloat(), y.toFloat(), r - linePaint!!.strokeWidth / 2, paint)
707 | }
708 | }
709 | }
710 | }
711 |
712 | /**
713 | * 获取内容区域位置
714 | *
715 | */
716 | private fun getItemRect(item: Item, position: Int): Rect {
717 | val rect = Rect()
718 | rect.left = paddingLeft + position * mItemWidth
719 | if (floatingEnable && item.isFloating) {
720 | rect.top = paddingTop + item.padding + getFloatingUpHeight() / 4
721 | } else {
722 | rect.top = paddingTop + getFloatingUpHeight() + item.padding
723 | }
724 | rect.right = rect.left + mItemWidth
725 | rect.bottom = mItemHeight - paddingBottom - item.padding
726 | return rect
727 | }
728 |
729 | /**
730 | * 画出每一个Item导航菜单
731 | *
732 | * @param canvas
733 | * @param item
734 | */
735 | private fun drawItem(canvas: Canvas, item: Item?, position: Int) {
736 | if (item == null) {
737 | return
738 | }
739 | var rect = getItemRect(item, position)
740 | if (!TextUtils.isEmpty(item.title)) {
741 | var color = if (item.isChecked) itemColorStateList!!.getColorForState(intArrayOf(android.R.attr.state_checked), itemColorStateList!!.defaultColor) else itemColorStateList!!.defaultColor
742 | if (!item.isCheckable) {
743 | color = itemColorStateList!!.getColorForState(intArrayOf(android.R.attr.state_checked), itemColorStateList!!.defaultColor)
744 | }
745 | setTextPaint(if (item.titleSize == 0) DensityUtils.dpToPx(resources, 14f) else item.titleSize, color)
746 | val textHeight = getTextHeight(item.title, mTextPaint)
747 | val textX = (rect.left + rect.right) / 2
748 | val textY = rect.bottom - textHeight / 4
749 | canvas.drawText(item.title!!, textX.toFloat(), textY.toFloat(), mTextPaint)
750 | }
751 | if (item.icon != null) {
752 | val drawable: Drawable? = getIconDrawable(item, position)
753 | drawable?.let {
754 | it.draw(canvas)
755 | }
756 | }
757 | if (item.msgCount != 0) {
758 | drawItemMsgCount(item, position, canvas)
759 | }
760 | }
761 |
762 | /**
763 | * 画出消息数
764 | */
765 | private fun drawItemMsgCount(item: Item, position: Int, canvas: Canvas) {
766 | val msgCountRect = getMsgCountRect(item, position)
767 | var x = (msgCountRect.left + msgCountRect.right) / 2
768 | var y = (msgCountRect.top + msgCountRect.bottom) / 2
769 | var r = (msgCountRect.bottom - msgCountRect.top) / 2
770 |
771 | if (item.msgCount > 0) {
772 | var countStr = when {
773 | item.msgCount > 99 -> {
774 | setTextPaint(DensityUtils.dpToPx(resources, 7f), Color.WHITE)
775 | "99+"
776 | }
777 | item.msgCount < 10 -> {
778 | setTextPaint(DensityUtils.dpToPx(resources, 9f), Color.WHITE)
779 | item.msgCount.toString()
780 | }
781 | else -> {
782 | setTextPaint(DensityUtils.dpToPx(resources, 8f), Color.WHITE)
783 | item.msgCount.toString()
784 | }
785 | }
786 | val paint = createPaint(Color.RED, Paint.Style.FILL, 0f)
787 | canvas.drawCircle(x.toFloat(), y.toFloat(), r.toFloat(), paint)
788 | canvas.drawText(countStr, x.toFloat(), (y + (r - DEFAULT_MSG_COUNT_TEXT_PADDING) / 2).toFloat(), mTextPaint)
789 | paint.style = Paint.Style.STROKE
790 | paint.color = Color.WHITE
791 | paint.strokeWidth = DensityUtils.dpToPx(resources, 1f).toFloat()
792 | canvas.drawCircle(x.toFloat(), y.toFloat(), r.toFloat(), paint)
793 | } else {
794 | val paint = createPaint(Color.RED, Paint.Style.FILL, 0f)
795 | canvas.drawCircle(x.toFloat(), y.toFloat(), r.toFloat(), paint)
796 | paint.style = Paint.Style.STROKE
797 | paint.color = Color.WHITE
798 | paint.strokeWidth = DensityUtils.dpToPx(resources, 1f).toFloat()
799 | canvas.drawCircle(x.toFloat(), y.toFloat(), r.toFloat(), paint)
800 | }
801 | }
802 |
803 | private fun getMsgCountRect(item: Item, position: Int): Rect {
804 | val r = if (item.msgCount > 0) {
805 | setTextPaint(DensityUtils.dpToPx(resources, 7f), Color.WHITE)
806 | getTextWidth("99+", mTextPaint!!) / 2 + DEFAULT_MSG_COUNT_TEXT_PADDING
807 | } else {
808 | 7
809 | }
810 | val rect = getIconRect(item, position)
811 | var x = (rect.left + rect.right) / 2
812 | var y = (rect.top + rect.bottom) / 2
813 | var r2 = y - rect.top
814 | val offset = sqrt(r2 * r2 * 1.0 / 2)
815 | val msgRect = Rect()
816 | msgRect.left = (x + offset - r).toInt()
817 | msgRect.top = (y - offset - r).toInt()
818 | if (item.msgCount > 0) {
819 | msgRect.left += r / 3
820 | msgRect.top += r / 3
821 | }
822 | msgRect.right = msgRect.left + 2 * r
823 | msgRect.bottom = msgRect.top + 2 * r
824 | return msgRect
825 | }
826 |
827 |
828 | private fun getFloatingUpHeight(): Int {
829 | if (floatingEnable) {
830 | for (item in itemList) {
831 | if (item.isFloating) {
832 | return floatingUp
833 | }
834 | }
835 | }
836 | return 0
837 | }
838 |
839 | private fun getIconDrawable(item: Item, position: Int): Drawable? {
840 | val drawable: Drawable? = if (item.isCheckable) {
841 | if (item.isChecked) {
842 | item.icon!!.state = intArrayOf(android.R.attr.state_checked)
843 | item.icon!!.current
844 | } else {
845 | item.icon!!.state = intArrayOf()
846 | item.icon!!.current
847 | }
848 | } else {
849 | item.drawable
850 | }
851 | drawable?.let {
852 | it.bounds = getIconRect(item, position)
853 | }
854 | return drawable
855 | }
856 |
857 | /**
858 | * 获取图标的位置
859 | */
860 | private fun getIconRect(item: Item, position: Int): Rect {
861 | val rect = getItemRect(item, position)
862 | val to = Rect()
863 | val floating = getFloatingUpHeight()
864 | var iconSize = itemIconWidth.coerceAtMost(itemIconHeight)
865 | setTextPaint(titleSize, Color.BLACK)
866 | val textHeight = getTextHeight("首页", mTextPaint!!)
867 | if (TextUtils.isEmpty(item.title)) {
868 | iconSize += (textTop + textHeight)
869 | }
870 | to.top = rect.top
871 | if (floatingEnable && item.isFloating) {
872 | iconSize += floating * 3 / 4
873 | }
874 | iconSize += (itemPadding - item.padding) * 2//高度修复
875 | to.left = (rect.left + rect.right - iconSize) / 2
876 | to.right = to.left + iconSize
877 | to.bottom = to.top + iconSize
878 | return to
879 | }
880 |
881 |
882 | /**
883 | * 创建文字类型的画笔
884 | *
885 | * @param textSize 文字大小
886 | * @param textColor 文字颜色
887 | * @return
888 | */
889 | private fun setTextPaint(textSize: Int, textColor: Int): Paint {
890 | return mTextPaint?.apply {
891 | this.color = textColor//设置画笔的颜色
892 | this.textSize = textSize.toFloat()//设置文字大小
893 | this.isAntiAlias = true//设置抗锯齿功能 true表示抗锯齿 false则表示不需要这功能
894 | this.textAlign = Paint.Align.CENTER
895 | this.style = Paint.Style.FILL_AND_STROKE
896 | }
897 | }
898 |
899 | /**
900 | * 创建图形的画笔
901 | *
902 | * @param color 画笔颜色
903 | * @return
904 | */
905 | private fun createPaint(color: Int, style: Paint.Style, strokeWidth: Float): Paint {
906 | return Paint().apply {
907 | this.color = color
908 | this.isAntiAlias = true//设置抗锯齿功能 true表示抗锯齿 false则表示不需要这功能
909 | this.textAlign = Paint.Align.CENTER
910 | this.style = style
911 | this.strokeWidth = strokeWidth
912 | }
913 | }
914 |
915 |
916 | /**
917 | * 获取文字宽度
918 | *
919 | * @param text 文字
920 | * @param paint 画笔
921 | * @return
922 | */
923 | private fun getTextWidth(text: String, paint: Paint): Int {
924 | val rect = Rect() // 文字所在区域的矩形
925 | paint.getTextBounds(text, 0, text.length, rect)
926 | return rect.width()
927 | }
928 |
929 | /**
930 | * 获取文字高度
931 | *
932 | * @param text 文字
933 | * @param paint 画笔
934 | * @return
935 | */
936 | private fun getTextHeight(text: String?, paint: Paint): Int {
937 | val rect = Rect()
938 | paint.getTextBounds(text, 0, text!!.length, rect)
939 | return rect.height()
940 | }
941 |
942 |
943 | /**
944 | * 更改图片颜色
945 | *
946 | * @param drawable
947 | * @param colors
948 | * @return
949 | */
950 | private fun tintListDrawable(drawable: Drawable, colors: ColorStateList?): Drawable {
951 | return if (colors != null) {
952 | val wrappedDrawable = DrawableCompat.wrap(drawable)
953 | DrawableCompat.setTintMode(wrappedDrawable, PorterDuff.Mode.MULTIPLY)
954 | DrawableCompat.setTintList(wrappedDrawable, colors)
955 | wrappedDrawable
956 | } else {
957 | drawable
958 | }
959 | }
960 |
961 | /**
962 | * 触摸事件监听
963 | *
964 | * @param event
965 | * @return
966 | */
967 | override fun onTouchEvent(event: MotionEvent): Boolean {
968 | val x = event.rawX.toDouble()
969 | var y = event.rawY.toDouble()
970 | //获取控件在屏幕的位置
971 | val location = IntArray(2)
972 | getLocationOnScreen(location)
973 | val locationY = location[1]
974 | y -= locationY
975 | val action = event.action
976 | if (BuildConfig.DEBUG) {
977 | Log.e(TAG, "action = $action")
978 | }
979 | when (action) {
980 | MotionEvent.ACTION_DOWN -> return true
981 | // break;
982 | MotionEvent.ACTION_MOVE -> {
983 | }
984 | MotionEvent.ACTION_UP -> {
985 | for (i in itemList.indices) {
986 | val item = itemList[i]
987 | var startTop = 0
988 | if (!item.isFloating) {
989 | startTop = paddingTop + getFloatingUpHeight()
990 | }
991 | if (x > paddingLeft + mItemWidth * i && x < paddingLeft + mItemWidth * (i + 1)) {
992 | //图片文字内容宽度
993 | val width = mItemHeight - topPadding - bottomPadding
994 | //图片文字内容高度
995 | val height = mItemHeight - topPadding - bottomPadding
996 | if (!TextUtils.isEmpty(item.title)) {
997 | val color = if (item.isChecked) itemColorStateList!!.getColorForState(intArrayOf(android.R.attr.state_checked), itemColorStateList!!.defaultColor) else itemColorStateList!!.defaultColor
998 | setTextPaint(if (item.titleSize == 0) DensityUtils.dpToPx(resources, 14f) else item.titleSize, color)
999 | val textHeight = getTextHeight(item.title, mTextPaint!!)
1000 | val textY = startTop + height - textHeight / 4//上边距+图片文字内容高度
1001 | val w = textY - textHeight / 2 - topPadding
1002 | // width = height = height - textHeight - textTop;
1003 | }
1004 | val centerX = paddingLeft + i * mItemWidth + (mItemWidth - width) / 2 + width / 2
1005 | val centerY = mItemHeight / 2
1006 | val r = mItemHeight / 2
1007 | if (y >= getFloatingUpHeight() || item.isFloating && isInCircle(centerX, centerY, r, x.toInt(), y.toInt())) {
1008 | setSelected(i)
1009 | }
1010 | }
1011 | }
1012 | postInvalidate()
1013 | }
1014 | }
1015 | return super.onTouchEvent(event)
1016 | }
1017 |
1018 |
1019 | /**
1020 | * 判断触摸位置是否在圆形内部
1021 | *
1022 | * @param vCenterX 圆形的 X 坐标
1023 | * @param vCenterY 圆形的 Y 坐标
1024 | * @param r 圆形的半径
1025 | * @param touchX 触摸位置的 X 坐标
1026 | * @param touchY 触摸位置的 Y 坐标
1027 | * @return
1028 | */
1029 | private fun isInCircle(vCenterX: Int, vCenterY: Int, r: Int, touchX: Int, touchY: Int): Boolean {
1030 | //点击位置x坐标与圆心的x坐标的距离
1031 | val distanceX = Math.abs(vCenterX - touchX)
1032 | //点击位置y坐标与圆心的y坐标的距离
1033 | val distanceY = Math.abs(vCenterY - touchY)
1034 | //点击位置与圆心的直线距离
1035 | val distanceZ = Math.sqrt(Math.pow(distanceX.toDouble(), 2.0) + Math.pow(distanceY.toDouble(), 2.0)).toInt()
1036 |
1037 | //如果点击位置与圆心的距离大于圆的半径,证明点击位置没有在圆内
1038 | return distanceZ <= r
1039 | }
1040 |
1041 | /**
1042 | * 导航菜单Item 的实体
1043 | */
1044 | inner class Item {
1045 | var showFragment: Boolean = true
1046 | var id: Int = 0
1047 | var icon: StateListDrawable? = null
1048 | var drawable: Drawable? = null
1049 | var title: String? = null
1050 | var titleSize: Int = 0
1051 | var iconWidth: Int = 0
1052 | var iconHeight: Int = 0
1053 | var padding: Int = 0
1054 | var isFloating = false
1055 | var isChecked = false
1056 | var isCheckable = true
1057 | var msgCount = 0
1058 | }
1059 |
1060 |
1061 | internal fun drawable2Bitmap(drawable: Drawable?): Bitmap {
1062 | if (drawable is BitmapDrawable) {
1063 | return drawable.bitmap
1064 | } else if (drawable is NinePatchDrawable) {
1065 | val bitmap = Bitmap
1066 | .createBitmap(
1067 | drawable.intrinsicWidth,
1068 | drawable.intrinsicHeight,
1069 | if (drawable.opacity != PixelFormat.OPAQUE)
1070 | Bitmap.Config.ARGB_8888
1071 | else
1072 | Bitmap.Config.RGB_565)
1073 | val canvas = Canvas(bitmap)
1074 | drawable.setBounds(0, 0, drawable.intrinsicWidth,
1075 | drawable.intrinsicHeight)
1076 | drawable.draw(canvas)
1077 | return bitmap
1078 | } else {
1079 | val bitmap: Bitmap
1080 | if (drawable!!.intrinsicWidth <= 0 || drawable.intrinsicHeight <= 0) {
1081 | bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888) // Single color bitmap will be created of 1x1 pixel
1082 | } else {
1083 | bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
1084 | }
1085 | val canvas = Canvas(bitmap)
1086 | drawable.setBounds(0, 0, canvas.width, canvas.height)
1087 | drawable.draw(canvas)
1088 | return bitmap
1089 | }
1090 | }
1091 |
1092 | /**
1093 | * 改变Fragment
1094 | *
1095 | * @param to
1096 | */
1097 | private fun selectFragmentByManager(to: Fragment) {
1098 | if (!isReplace) {
1099 | hiddenFragment(currentFragment, to)
1100 | } else {
1101 | replaceFragment(currentFragment, to)
1102 | }
1103 |
1104 | }
1105 |
1106 | /**
1107 | * 隐藏Fragment
1108 | *
1109 | * @param from
1110 | * @param to
1111 | */
1112 | private fun hiddenFragment(from: Fragment?, to: Fragment) {
1113 | val transaction = manager!!.beginTransaction()
1114 | if (from != null && from !== to) {
1115 | if (to.isAdded) {
1116 | transaction.hide(from).show(to)
1117 | } else {
1118 | transaction.add(containerView!!.id, to).hide(from).show(to)
1119 | }
1120 | } else if (to != null) {
1121 | transaction.replace(containerView!!.id, to).show(to)
1122 | }
1123 | transaction.commit()
1124 | currentFragment = to
1125 | }
1126 |
1127 | /**
1128 | * 替换Fragment
1129 | *
1130 | * @param from
1131 | * @param to
1132 | */
1133 | private fun replaceFragment(from: Fragment?, to: Fragment) {
1134 | val transaction = manager!!.beginTransaction()
1135 | if (from != null && from !== to) {
1136 | transaction.remove(from)
1137 | transaction.replace(containerView!!.id, to).show(to)
1138 | } else if (to != null) {
1139 | transaction.replace(containerView!!.id, to).show(to)
1140 | }
1141 | transaction.commit()
1142 | currentFragment = to
1143 | }
1144 |
1145 |
1146 | private class ViewpagerAdapter(fragmentManager: FragmentManager, val fragments: List) : FragmentPagerAdapter(fragmentManager) {
1147 | override fun getCount(): Int {
1148 | return fragments.size
1149 | }
1150 |
1151 |
1152 | override fun getItem(position: Int): Fragment {
1153 | return fragments[position]
1154 | }
1155 |
1156 |
1157 | }
1158 |
1159 | }
--------------------------------------------------------------------------------