├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── styles.xml
│ │ │ │ └── colors.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ └── layout
│ │ │ │ ├── activity_main2.xml
│ │ │ │ └── activity_main.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── duan
│ │ │ └── indicatorviewdemo
│ │ │ ├── Utils.java
│ │ │ └── MainActivity.java
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── duan
│ │ │ └── indicatorviewdemo
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── duan
│ │ └── indicatorviewdemo
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── library
├── .gitignore
├── src
│ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── res
│ │ │ └── values
│ │ │ │ ├── strings.xml
│ │ │ │ └── attrs.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── duan
│ │ │ └── indicatorview
│ │ │ └── IndicatorView.java
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── duan
│ │ │ └── indicatorview
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── duan
│ │ └── indicatorview
│ │ └── ExampleInstrumentedTest.java
├── gradle.properties
├── proguard-rules.pro
├── build.gradle
└── bintray.gradle
├── settings.gradle
├── screenshot001.gif
├── screenshot002.gif
├── screenshot003.gif
├── screenshot004.gif
├── .idea
├── dictionaries
│ └── ai.xml
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── vcs.xml
├── modules.xml
├── runConfigurations.xml
├── gradle.xml
├── compiler.xml
└── misc.xml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── gradle.properties
├── gradlew.bat
├── gradlew
└── README.md
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':library'
2 |
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/screenshot001.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DuanJiaNing/IndicatorView/HEAD/screenshot001.gif
--------------------------------------------------------------------------------
/screenshot002.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DuanJiaNing/IndicatorView/HEAD/screenshot002.gif
--------------------------------------------------------------------------------
/screenshot003.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DuanJiaNing/IndicatorView/HEAD/screenshot003.gif
--------------------------------------------------------------------------------
/screenshot004.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DuanJiaNing/IndicatorView/HEAD/screenshot004.gif
--------------------------------------------------------------------------------
/.idea/dictionaries/ai.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/library/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | library
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | IndicatorViewDemo
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DuanJiaNing/IndicatorView/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DuanJiaNing/IndicatorView/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DuanJiaNing/IndicatorView/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DuanJiaNing/IndicatorView/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DuanJiaNing/IndicatorView/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DuanJiaNing/IndicatorView/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DuanJiaNing/IndicatorView/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DuanJiaNing/IndicatorView/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DuanJiaNing/IndicatorView/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DuanJiaNing/IndicatorView/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DuanJiaNing/IndicatorView/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Apr 04 10:12:27 CST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
11 |
12 |
13 | #built application files
14 | *.apk
15 | *.ap_
16 |
17 | # files for the dex VM
18 | *.dex
19 |
20 | # Java class files
21 | *.class
22 |
23 | # generated files
24 | bin/
25 | gen/
26 |
27 | # Local configuration file (sdk path, etc)
28 | local.properties
29 |
30 | # Windows thumbnail db
31 | Thumbs.db
32 |
33 | #NDK
34 | obj/
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/library/gradle.properties:
--------------------------------------------------------------------------------
1 | PROJ_GROUP=com.duan
2 | PROJ_VERSION=0.0.1
3 | PROJ_NAME=IndicatorView
4 | PROJ_WEBSITEURL=https://github.com/DuanJiaNing/IndicatorView
5 | PROJ_ISSUETRACKERURL=https://github.com/DuanJiaNing/IndicatorView/issues
6 | PROJ_VCSURL=git@github.com:DuanJiaNing/IndicatorView.git
7 | PROJ_DESCRIPTION=indicator for android widget like view pager , list or other selectable.
8 | PROJ_ARTIFACTID=IndicatorView
9 |
10 | DEVELOPER_ID=Allan Duan
11 | DEVELOPER_NAME=duanjianing
12 | DEVELOPER_EMAIL=aimeimeits@gmail.com
--------------------------------------------------------------------------------
/library/src/test/java/com/duan/indicatorview/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.duan.indicatorview;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/test/java/com/duan/indicatorviewdemo/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.duan.indicatorviewdemo;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
8 |
9 | #e98718
10 | #a1a1a1
11 |
12 | #f15c5c
13 | #f5f346
14 | #35dcdc
15 | #ed4ae3
16 | #38c658
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/duan/indicatorview/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.duan.indicatorview;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.duan.library.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/duan/indicatorviewdemo/Utils.java:
--------------------------------------------------------------------------------
1 | package com.duan.indicatorviewdemo;
2 |
3 | import android.graphics.Color;
4 |
5 | /**
6 | * Created by DuanJiaNing on 2017/4/2.
7 | */
8 |
9 | public class Utils {
10 |
11 | /**
12 | * 获得一个随机的颜色
13 | * @return 颜色
14 | */
15 | public static int getRandomColor()
16 | {
17 | int r = (int)(Math.random()*255); //产生一个255以内的整数
18 | int g = (int)(Math.random()*255); //产生一个255以内的整数
19 | int b = (int)(Math.random()*255); //产生一个255以内的整数
20 | return Color.rgb(r,g,b);
21 | }
22 |
23 | /**
24 | * 获得一个比较暗的随机颜色
25 | * @return 颜色
26 | */
27 | public static int getRandomColor_d()
28 | {
29 | int r = (int)(Math.random()*100); //产生一个100以内的整数
30 | int g = (int)(Math.random()*100);
31 | int b = (int)(Math.random()*100);
32 | return Color.rgb(r,g,b);
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/duan/indicatorviewdemo/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.duan.indicatorviewdemo;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.duan.indicatorviewdemao", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\JetBrains\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/library/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\JetBrains\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 26
5 | buildToolsVersion "25.0.2"
6 | defaultConfig {
7 | applicationId "com.duan.indicatorviewdemao"
8 | minSdkVersion 14
9 | targetSdkVersion 26
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 |
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | compileOptions {
22 | targetCompatibility 1.7
23 | sourceCompatibility 1.7
24 | }
25 | android {
26 | lintOptions {
27 | abortOnError false
28 | }
29 | }
30 | }
31 |
32 | dependencies {
33 | compile fileTree(include: ['*.jar'], dir: 'libs')
34 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
35 | exclude group: 'com.android.support', module: 'support-annotations'
36 | })
37 | compile 'com.android.support:appcompat-v7:25.3.1'
38 | compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha9'
39 | testCompile 'junit:junit:4.12'
40 | compile project(':library')
41 | }
42 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.novoda.bintray-release' // must be applied after your artifact generating plugin (eg. java / com.android.library)
3 |
4 | allprojects {
5 | repositories {
6 | jcenter()
7 | mavenCentral()
8 | }
9 | //加上这些
10 | tasks.withType(Javadoc) {
11 | options{ encoding "UTF-8"
12 | charSet 'UTF-8'
13 | links "http://docs.oracle.com/javase/7/docs/api"
14 | }
15 | }
16 | }
17 |
18 | publish {
19 | userOrg = 'duan' //bintray注册的用户名
20 | groupId = 'com.duan' //compile引用时的第1部分groupId
21 | artifactId = 'IndicatorView' //compile引用时的第2部分项目名
22 | publishVersion = '1.0.1' //compile引用时的第3部分版本号
23 | desc = 'indicator for android widget like view pager , list or other selectable.'
24 | website = 'https://github.com/DuanJiaNing/IndicatorView'
25 | }
26 |
27 | android {
28 | compileSdkVersion 26
29 | buildToolsVersion "25.0.2"
30 | defaultConfig {
31 | minSdkVersion 14
32 | targetSdkVersion 26
33 | versionCode 1
34 | versionName PROJ_VERSION
35 |
36 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
37 |
38 | }
39 | buildTypes {
40 | release {
41 | minifyEnabled false
42 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
43 | }
44 | }
45 | android {
46 | lintOptions {
47 | abortOnError false
48 | }
49 | }
50 |
51 | }
52 |
53 | dependencies {
54 | compile fileTree(dir: 'libs', include: ['*.jar'])
55 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
56 | exclude group: 'com.android.support', module: 'support-annotations'
57 | })
58 | compile 'com.android.support:appcompat-v7:26.+'
59 | testCompile 'junit:junit:4.12'
60 | }
61 |
62 | //gradlew clean build bintrayUpload -PbintrayUser=duanjianing -PbintrayKey=bd5b56e0c4e1f9aaacbd2881751607c50501648b -PdryRun=false
63 |
64 | //通过配置我们最后的依赖地址=第一部分+第二部分+第三部分;
65 | //compile 'com.wzgiceman:RxBus:1.0.1'
--------------------------------------------------------------------------------
/.idea/misc.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 | 1.8
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/library/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 |
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 |
--------------------------------------------------------------------------------
/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 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
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 Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main2.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
26 |
27 |
32 |
33 |
38 |
39 |
58 |
59 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/library/bintray.gradle:
--------------------------------------------------------------------------------
1 | group = PROJ_GROUP
2 | version = PROJ_VERSION
3 | project.archivesBaseName = PROJ_ARTIFACTID
4 |
5 | apply plugin: 'com.jfrog.bintray'
6 | apply plugin: 'com.github.dcendents.android-maven'
7 |
8 | task sourcesJar(type: Jar) {
9 | from android.sourceSets.main.java.srcDirs
10 | classifier = 'sources'
11 | }
12 |
13 | task javadoc(type: Javadoc) {
14 | source = android.sourceSets.main.java.srcDirs
15 | classpath += configurations.compile
16 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
17 | }
18 |
19 | task javadocJar(type: Jar, dependsOn: javadoc) {
20 | classifier = 'javadoc'
21 | from javadoc.destinationDir
22 | }
23 |
24 | javadoc {
25 | options{
26 | encoding "UTF-8"
27 | charSet 'UTF-8'
28 | author true
29 | version true
30 | links "https://androiddoc.qiniudn.com/reference/"
31 | title "$PROJ_NAME $PROJ_VERSION"
32 | }
33 | }
34 |
35 | artifacts {
36 | archives sourcesJar
37 | archives javadocJar
38 | }
39 |
40 | install {
41 | repositories.mavenInstaller {
42 | pom.project {
43 | name PROJ_NAME
44 | description PROJ_DESCRIPTION
45 | url PROJ_WEBSITEURL
46 | inceptionYear '2016'
47 |
48 | packaging 'aar'
49 | groupId PROJ_GROUP
50 | artifactId PROJ_ARTIFACTID
51 | version PROJ_VERSION
52 |
53 | licenses {
54 | license {
55 | name 'The Apache Software License, Version 2.0'
56 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
57 | distribution 'repo'
58 | }
59 | }
60 | scm {
61 | connection PROJ_VCSURL
62 | url PROJ_WEBSITEURL
63 |
64 | }
65 | developers {
66 | developer {
67 | id DEVELOPER_ID
68 | name DEVELOPER_NAME
69 | email DEVELOPER_EMAIL
70 | }
71 | }
72 | }
73 | }
74 | }
75 |
76 | bintray {
77 | user = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : project.property('BINTRAY_USER')
78 | key = project.hasProperty('bintrayKey') ? project.property('bintrayKey') : project.property('BINTRAY_KEY')
79 |
80 | configurations = ['archives']
81 |
82 | dryRun = false
83 | publish = true
84 |
85 | pkg {
86 | repo = 'maven'
87 | name = PROJ_NAME
88 | licenses = ['Apache-2.0']
89 | vcsUrl = PROJ_VCSURL
90 | websiteUrl = PROJ_WEBSITEURL
91 | issueTrackerUrl = PROJ_ISSUETRACKERURL
92 | publicDownloadNumbers = true
93 | version {
94 | name = PROJ_VERSION
95 | desc = PROJ_DESCRIPTION
96 | vcsTag = PROJ_VERSION
97 |
98 | gpg {
99 | sign = true
100 | }
101 | }
102 | }
103 | }
104 |
105 | //以下内容用于发布SNAPSHOT版本,如果不需要可以移除。
106 | //参考自:https://www.jfrog.com/confluence/display/RTF/Gradle+Artifactory+Plugin
107 |
108 | apply plugin: "com.jfrog.artifactory"
109 | artifactory {
110 | contextUrl = 'http://oss.jfrog.org/artifactory' //The base Artifactory URL if not overridden by the publisher/resolver
111 | resolve {
112 | repository {
113 | repoKey = 'libs-release'
114 | }
115 | }
116 | publish {
117 | repository {
118 | repoKey = 'oss-snapshot-local' //The Artifactory repository key to publish to
119 | username = bintray.user
120 | password = bintray.key
121 | maven = true
122 | }
123 | defaults {
124 | //这里的名字和前面bintray.configurations的值一致即可,会将其包含的输出上传到jfrog上去
125 | publishConfigs('archives')
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
16 |
17 |
20 |
21 |
26 |
27 |
39 |
40 |
45 |
46 |
62 |
63 |
68 |
69 |
80 |
81 |
86 |
87 |
100 |
101 |
106 |
107 |
123 |
124 |
125 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 自定义View和属性动画ValueAnimator实现圆点指示器:blush:
2 |
3 | >**自定义View和属性动画相结合实现支持动态修改指示点位置,拖拽或点击改变指示点位置,点击位置监听及切换动画自定义的圆点指示器。**
4 |
5 | #### 一.开发背景
6 | 最近学习了自定义View和属性动画的知识,开发这个简单的圆点指示器以巩固所学知识。
7 |
8 | #### 二.效果图
9 |
10 | 
11 |
12 | #### 三.IndicatorView主要属性
13 | ##### 3.1 构成元素
14 | - 小圆点:固定不动的圆形
15 | - 指示点:在小圆点上来回移动,通过改变指示点当前所在位置来实现 `指示器` 的功能,为了实现“挤扁”的动画效果,绘制时用的是椭圆。
16 | - 线段:用于连接两个小圆点,绘制时以两个相邻小圆点间的距离为一个 `线段` 单位。循环绘制 `线段` ,绘制`小圆点个数减一` 次后连通所有小圆点,*在布局文件或代码中可修改其可见性(`lineVisible`)*
17 |
18 |
19 | 
20 | ##### 3.2 xml属性
21 | - 指示点大小、颜色
22 | - 固定显示的小圆点的大小、颜色以及数量
23 | - 连接小圆点的线条的可见性,线条宽度、长度、颜色
24 | - 默认提供了两个用于指示点间切换的动画(平移和挤扁),也可选择不使用动画或自定义
25 | - 默认提供的切换动画的时间可指定
26 | - 启用/禁用拖拽切换(点击切换或两者)功能
27 | - 指定控件的显示方向,水平或是纵向(默认为水平)
28 | ##### 3.3 功能
29 | - 通过代码动态修改部分属性
30 | - 通过代码获得属性值,如当前指示点位置,颜色等
31 | - 通过代码自定义指示点间切换动画,指示点被触摸的反馈动画及点击事件监听的回调
32 |
33 | #### 四.适用场景:
34 |
35 | #### 五.如何使用
36 | 可以在布局文件中直接使用:
37 | ``` xml
38 |
54 | ```
55 | 具体使用可参看博文:[自定义View和属性动画ValueAnimator实现圆点指示器](http://blog.csdn.net/aimeimeiTS/article/details/69370853)
56 | #### 六.版本变化
57 | - v 1.0 2017-04-03:
58 | - v 1.1 2017-05-04:添加**纵向视图**支持,现在可以在`xml`文件中通过指定`indicatorOrientation`属性为`vertical`使控件以纵向视图显示
59 | ``` xml
60 | app:indicatorOrientation="vertical"
61 | ```
62 | 
63 |
64 | 具体使用可参看博文:[自定义View和属性动画ValueAnimator实现圆点指示器——支持“纵向视图”](http://blog.csdn.net/aimeimeits/article/details/71158500)
65 |
66 | - v 1.2 2017-05-05:添加指示点拖拽监听和指示点位置改变监听,在代码中设置监听器即可监听指示点拖拽时的位置改变(映射到的小圆点对应的位置),及其间距变化(与最左或最下的小圆点间的距离)。
67 |
68 | 使用示例
69 | ```java
70 | @Override
71 | protected void onCreate(Bundle savedInstanceState) {
72 | //...
73 | IndicatorView indicator = (IndicatorView) findViewById(R.id.main2_indicator);
74 | indicator.setOnIndicatorSeekListener(new IndicatorView.OnIndicatorSeekListener() {
75 | @Override
76 | public void onSeekChange(IndicatorView view, int distance, int dotPos) {
77 | Log.i(TAG, "onSeekChange: distance=" + distance + " dot=" + dotPos);
78 | }
79 |
80 | @Override
81 | public void onStartTrackingTouch(IndicatorView view) {
82 | Toast.makeText(MainActivity.this, "touched", Toast.LENGTH_SHORT).show();
83 | }
84 |
85 | @Override
86 | public void onSopTrackingTouch(IndicatorView view) {
87 | Toast.makeText(MainActivity.this, "touch leave", Toast.LENGTH_SHORT).show();
88 | }
89 | });
90 |
91 | indicator.setOnIndicatorChangeListener(new IndicatorView.OnIndicatorChangeListener() {
92 | @Override
93 | public void onIndicatorChange(int currentPos, int oldPos) {
94 | Log.i(TAG, "onIndicatorChange: cuPos=" + currentPos + " oldPos=" + oldPos);
95 | }
96 | });
97 | //...
98 | }
99 | ```
100 | - v 1.3 2017-05-10:自定义指示点在各个位置的颜色,现在可以在代码中设置指示点在指定位置的颜色,提供了三种方式为指示点设置颜色。
101 |
102 | 1. `setIndicatorColor(int color)`:将指示点在各个位置的颜色全部设置为指定颜色
103 | 2. `setIndicatorColor(int index, int color)`:修改指示点在指定位置处的颜色
104 | 3. `setIndicatorColor(int... colors)`:为指示点指定在每一个位置的颜色
105 |
106 | 此外还添加了一个方法控制在进行指示点切换时是否改变线段的颜色。
107 | `changeLineColorWhileSwitch(boolean chage)`,同时修正了小圆点和指示点实际大小与给定大小不一致的问题。
108 |
109 | 使用示例
110 | ```java
111 | @Override
112 | protected void onCreate(Bundle savedInstanceState) {
113 | //...
114 | IndicatorView indicator = (IndicatorView) findViewById(R.id.main2_indicator);
115 | IndicatorView indicator1 = (IndicatorView) findViewById(R.id.main2_indicator1);
116 |
117 | indicator.setIndicatorColor(new int[]{
118 | getResources().getColor(R.color.color_1),
119 | getResources().getColor(R.color.color_2),
120 | getResources().getColor(R.color.color_3),
121 | getResources().getColor(R.color.color_4),
122 | getResources().getColor(R.color.color_5)
123 | });
124 | //在进行指示点切换过程中不改变线段颜色
125 | indicator.changeLineColorWhileSwitch(false);
126 |
127 | indicator1.setIndicatorColor(0, getResources().getColor(R.color.color_1));
128 | indicator1.setIndicatorColor(indicator2.getDotCount() - 1, getResources().getColor(R.color.yellow));
129 | indicator1.setIndicatorColor(indicator2.getDotCount() / 2, getResources().getColor(R.color.color_5));
130 |
131 | //...
132 | }
133 | ```
134 |
135 | 
136 |
137 |
138 | - v 1.4 2017-05-24:适配 API 11 ,修复 match_parent 时绘制线段和小圆点顺序不一致(纵向时的从上往下和从下往上)导致的错位问题,同时修复 match_parent 模式下,不在可点击范围内点击时指示点依然有触摸回馈的错误。
139 |
140 | - v 1.5 2017-12-31:动态修改圆点个数
141 | 添加了两个方法用以动态修改圆点个数
142 | ```java
143 |
144 | /**
145 | * 动态修改圆点个数,如果圆点个数增加,那么指示点位置被保留;减小且原先指示位置大于新圆点个数时最后一个位置成为指示点
146 | *
147 | * @param count 新的圆点个数
148 | */
149 | public void setDotCount(int count) {
150 | setDotCount(count, count <= mIndicatorPos ? count : mIndicatorPos);
151 | }
152 |
153 | /**
154 | * 动态修改指示点个数,指定新的指示点位置
155 | *
156 | * @param count 新的圆点个数
157 | * @param indicatorPos 指示点位置 1 ~ count
158 | */
159 | public void setDotCount(int count, int indicatorPos) {
160 |
161 | if (count >= minDotNum && count <= maxDotCount && count != mDotCount) {
162 | //注意:如果将mDotCount变小,那么指定指示点的自定义颜色会丢失
163 | mIndicatorColors = Arrays.copyOf(mIndicatorColors, count);
164 | if (count > mDotCount) {
165 | Arrays.fill(mIndicatorColors, mDotCount - 1, count, mIndicatorColor);
166 | }
167 |
168 | mDotCount = count;
169 | if (indicatorPos >= 1 && indicatorPos <= count) {
170 | mIndicatorPos = indicatorPos - 1;
171 | }
172 |
173 | clickableAreas = new int[mDotCount][2];
174 | this.requestLayout();
175 | }
176 |
177 | }
178 |
179 | ```
180 | 
181 |
182 |
183 | #### 七.未来的开发计划
184 | - [X] 添加**纵向视图**支持
185 | - [X] 添加指示点拖拽监听和指示点位置改变监听
186 | - [X] 自定义指示点在各个位置的颜色
187 | - [X] 动态修改圆点个数
188 |
189 | #### 八.Q&A
190 |
--------------------------------------------------------------------------------
/app/src/main/java/com/duan/indicatorviewdemo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.duan.indicatorviewdemo;
2 |
3 | import android.animation.AnimatorSet;
4 | import android.animation.ArgbEvaluator;
5 | import android.animation.ObjectAnimator;
6 | import android.animation.ValueAnimator;
7 | import android.graphics.Color;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.os.Bundle;
10 | import android.util.Log;
11 | import android.view.View;
12 | import android.widget.Toast;
13 |
14 | import com.duan.indicatorview.IndicatorView;
15 |
16 | import java.util.Random;
17 | import java.util.Timer;
18 | import java.util.TimerTask;
19 |
20 | public class MainActivity extends AppCompatActivity {
21 |
22 | private static final String TAG = "MainActivity";
23 | private IndicatorView indicator1;
24 | private IndicatorView indicator2;
25 | private IndicatorView indicator3;
26 | private IndicatorView indicator4;
27 |
28 | @Override
29 | protected void onCreate(Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 | setContentView(R.layout.activity_main2);
32 |
33 | final IndicatorView indicator = (IndicatorView) findViewById(R.id.main2_indicator);
34 | final IndicatorView indicator1 = (IndicatorView) findViewById(R.id.main2_indicator1);
35 | final IndicatorView indicator2 = (IndicatorView) findViewById(R.id.main2_indicator2);
36 |
37 | indicator.setIndicatorColor(new int[]{
38 | getResources().getColor(R.color.color_1),
39 | getResources().getColor(R.color.color_2),
40 | getResources().getColor(R.color.color_3),
41 | getResources().getColor(R.color.color_4),
42 | getResources().getColor(R.color.color_5)
43 | });
44 | indicator.changeLineColorWhileSwitch(false);
45 |
46 | indicator1.setIndicatorColor(0, getResources().getColor(R.color.color_1));
47 | indicator1.setIndicatorColor(indicator1.getDotCount() - 1, getResources().getColor(R.color.yellow));
48 | indicator1.setIndicatorColor(indicator1.getDotCount() / 2, getResources().getColor(R.color.color_5));
49 |
50 | findViewById(R.id.changeCount).setOnClickListener(new View.OnClickListener() {
51 | Random r = new Random();
52 |
53 | @Override
54 | public void onClick(View view) {
55 | int count = r.nextInt(6) + 2;
56 | int pos = r.nextInt(count) + 1;
57 | indicator.setDotCount(count, pos);
58 | indicator2.setDotCount(count);
59 | Toast.makeText(MainActivity.this, "count=" + count + " pos=" + pos, Toast.LENGTH_SHORT).show();
60 | }
61 | });
62 |
63 | // setContentView(R.layout.activity_main);
64 | // indicator1 = (IndicatorView) findViewById(R.id.indicator1);
65 | // indicator2 = (IndicatorView) findViewById(R.id.indicator2);
66 | // indicator3 = (IndicatorView) findViewById(R.id.indicator3);
67 | // indicator4 = (IndicatorView) findViewById(R.id.indicator4);
68 | // execuInV1();
69 | // execuInV2();
70 | // execuInV3();
71 | // execuInV4();
72 |
73 | }
74 |
75 | //代码动态指定属性
76 | private void execuInV1() {
77 |
78 | new Timer().schedule(new TimerTask() {
79 | Random random = new Random();
80 |
81 | @Override
82 | public void run() {
83 | indicator1.post(new Runnable() {
84 | @Override
85 | public void run() {
86 | indicator1.setIndicatorPos(random.nextInt(indicator1.getDotCount()));
87 | indicator1.setIndicatorColor(Utils.getRandomColor());
88 | indicator1.setDotColor(Utils.getRandomColor_d());
89 | indicator1.setIndicatorSwitchAnim(random.nextInt(IndicatorView.INDICATOR_SWITCH_ANIM_SQUEEZE + 1));
90 |
91 | }
92 | });
93 | }
94 | }, 2000, 2000);
95 |
96 | }
97 |
98 | //不可点击+自定义指示点触摸动画
99 | private void execuInV2() {
100 | indicator2.setOnIndicatorPressAnimator(new IndicatorView.OnIndicatorPressAnimator() {
101 | @Override
102 | public AnimatorSet onIndicatorPress(IndicatorView view, IndicatorView.IndicatorHolder target) {
103 | int terminalColor = indicator2.getIndicatorColor();
104 | int centerColor = Color.RED;
105 | int centerColor2 = Color.BLUE;
106 | ValueAnimator animator = null;
107 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
108 | animator = ObjectAnimator.ofArgb(target, "color", terminalColor, centerColor, centerColor2, terminalColor);
109 | } else {
110 | animator = ObjectAnimator.ofInt(target, "color", terminalColor, centerColor, centerColor2, terminalColor);
111 | animator.setEvaluator(new ArgbEvaluator());
112 | }
113 |
114 | int terminalSize = indicator2.getIndicatorPixeSize();
115 | int centerSize = indicator2.getIndicatorPixeSize() * 2;
116 | ValueAnimator animatorH = ObjectAnimator.ofInt(target, "height", terminalSize, centerSize, terminalSize);
117 | ValueAnimator animatorW = ObjectAnimator.ofInt(target, "width", terminalSize, centerSize, terminalSize);
118 |
119 | AnimatorSet set = new AnimatorSet();
120 | set.play(animator).with(animatorH).with(animatorW);
121 | set.setDuration(1000); //播放时为700
122 |
123 | return set;
124 | }
125 | });
126 |
127 |
128 | }
129 |
130 | //线条不可见(线条长度仍需指定)+自定义指示点切换动画
131 | private void execuInV3() {
132 | indicator3.setOnIndicatorSwitchAnimator(new IndicatorView.OnIndicatorSwitchAnimator() {
133 | @Override
134 | public AnimatorSet onIndicatorSwitch(IndicatorView view, IndicatorView.IndicatorHolder target) {
135 | int terminalAlpha = 255;
136 | int centerAlpha = 0;
137 | ValueAnimator alphaAnim = ObjectAnimator.ofInt(target, "alpha", terminalAlpha, centerAlpha, terminalAlpha);
138 |
139 | int terminalSize = indicator3.getIndicatorPixeSize();
140 | int centerSize = 0;
141 | ValueAnimator animatorH = ObjectAnimator.ofInt(target, "height", terminalSize, centerSize, terminalSize);
142 | ValueAnimator animatorW = ObjectAnimator.ofInt(target, "width", terminalSize, centerSize, terminalSize);
143 |
144 | AnimatorSet set = new AnimatorSet();
145 | set.play(alphaAnim).with(animatorH).with(animatorW);
146 | set.setDuration(500);
147 |
148 | return set;
149 | }
150 | });
151 |
152 | }
153 |
154 | //自定义指示点切换动画+监听点击事件+不可拖拽
155 | private void execuInV4() {
156 | indicator4.setOnDotClickListener(new IndicatorView.OnDotClickListener() {
157 | @Override
158 | public void onDotClickChange(View v, int position) {
159 | Toast.makeText(MainActivity.this, "点击了 " + position, Toast.LENGTH_SHORT).show();
160 | }
161 | });
162 | indicator4.setOnIndicatorSwitchAnimator(new IndicatorView.OnIndicatorSwitchAnimator() {
163 | @Override
164 | public AnimatorSet onIndicatorSwitch(IndicatorView view, IndicatorView.IndicatorHolder target) {
165 |
166 | int terminalColor = indicator4.getIndicatorColor();
167 | int centerColor = indicator4.getDotColor();
168 | ValueAnimator colorAnim = null;
169 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
170 | colorAnim = ObjectAnimator.ofArgb(target, "color", terminalColor, centerColor, terminalColor);
171 | } else {
172 | colorAnim = ObjectAnimator.ofInt(target, "color", terminalColor, centerColor, terminalColor);
173 | colorAnim.setEvaluator(new ArgbEvaluator());
174 | }
175 |
176 | int terminalSize = indicator4.getIndicatorPixeSize();
177 | int centerSize = indicator4.getIndicatorPixeSize() * 3 / 2;
178 | ValueAnimator animatorH = ObjectAnimator.ofInt(target, "height", terminalSize, centerSize, terminalSize);
179 | ValueAnimator animatorW = ObjectAnimator.ofInt(target, "width", terminalSize, centerSize, terminalSize);
180 |
181 | AnimatorSet set = new AnimatorSet();
182 | set.play(colorAnim).with(animatorH).with(animatorW);
183 | set.setDuration(500);
184 |
185 | return set;
186 |
187 | }
188 | });
189 | }
190 |
191 | }
192 |
--------------------------------------------------------------------------------
/library/src/main/java/com/duan/indicatorview/IndicatorView.java:
--------------------------------------------------------------------------------
1 | package com.duan.indicatorview;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorSet;
5 | import android.animation.ArgbEvaluator;
6 | import android.animation.ObjectAnimator;
7 | import android.animation.ValueAnimator;
8 | import android.content.Context;
9 | import android.content.res.TypedArray;
10 | import android.graphics.Canvas;
11 | import android.graphics.Color;
12 | import android.graphics.Paint;
13 | import android.graphics.RectF;
14 | import android.os.Build;
15 | import android.support.annotation.Nullable;
16 | import android.util.AttributeSet;
17 | import android.util.Log;
18 | import android.view.MotionEvent;
19 | import android.view.View;
20 |
21 | import java.util.Arrays;
22 |
23 | import static android.content.ContentValues.TAG;
24 |
25 | /**
26 | * Created by DuanJiaNing on 2017/4/3.
27 | */
28 |
29 | public class IndicatorView extends View {
30 |
31 | private Context mContext;
32 |
33 | private int mDotColor;
34 |
35 | private int mDotSize;
36 | private int mDotCount;
37 |
38 | private boolean mLineVisible;
39 | private int mLineColor;
40 | private int mLineWidth;
41 | private int mLineLength;
42 |
43 | private int mIndicatorSize;
44 | private int mIndicatorColor;
45 | private int mIndicatorPos;
46 | private boolean mDotClickEnable;
47 |
48 | private boolean mIndicatorDragEnable;
49 | private boolean mTouchEnable;
50 |
51 | private int mIndicatorSwitchAnim;
52 | public static final int INDICATOR_SWITCH_ANIM_NONE = 0;
53 | public static final int INDICATOR_SWITCH_ANIM_TRANSLATION = 1;
54 | public static final int INDICATOR_SWITCH_ANIM_SQUEEZE = 2;
55 |
56 | private int mIndicatorOrientation;
57 | public static final int INDICATOR_ORIENTATION_VERTICAL = 0;
58 | public static final int INDICATOR_ORIENTATION_HORIZONTAL = 1;
59 |
60 | private int mDuration;
61 |
62 | private boolean mChangeLineColorWhileSwitch = true;
63 |
64 | private int[] mIndicatorColors;
65 |
66 | private int defaultDotSize = 8;
67 | private int defaultIndicatorSize = 15;
68 | private int defaultLineLength = 40;
69 | private int minLineWidth = 1;
70 | private int maxDotCount = 30;
71 | private int minDotNum = 2;
72 |
73 | private Paint mPaint;
74 |
75 | /**
76 | * 上下左右边界
77 | * 由 clickableAreas 定义的边界
78 | * 拖拽指示点离开上下边界(左右边界)时,使 switchTo 值为边界点的下标,防止数组越界。
79 | * 手机屏幕左上角向下为上,向右为右
80 | */
81 | private int mBorderTop;
82 | private int mBorderBottom;
83 | private int mBorderRight;
84 | private int mBorderLeft;
85 |
86 | /**
87 | * 保存所有小圆点的圆点坐标,用于在touch事件中判断触摸了哪个点
88 | */
89 | private int[][] clickableAreas;
90 |
91 | /**
92 | * 指示点,不断修改它的属性从而实现动画(属性动画)
93 | */
94 | private IndicatorHolder indicatorHolder;
95 |
96 | /**
97 | * 指示点要移动到的目标位置
98 | */
99 | private int switchTo = -1;
100 |
101 | /**
102 | * 辅助 switchTo 变量,
103 | */
104 | private int switchToTemp;
105 |
106 | /**
107 | * 手松开后根据该变量判断是否需要启动切换动画
108 | */
109 | private boolean haveIndicatorPressAniming = false;
110 |
111 | /**
112 | * 指示点是否被拖拽过,当指示点被拖拽了但没有超过当前指示点位置范围时使之回到原位
113 | */
114 | private boolean haveIndicatorDraged = false;
115 |
116 | /**
117 | * 保存转移动画开始时线的颜色
118 | */
119 | private int tempLineColor;
120 |
121 | public interface OnDotClickListener {
122 | /**
123 | * 小圆点点击事件监听(点击的小圆点不是当前指示点所在位置时才会回调)
124 | *
125 | * @param v view
126 | * @param position 点击的指示点 0 ~ mDotCount
127 | */
128 | void onDotClickChange(View v, int position);
129 | }
130 |
131 | public interface OnIndicatorPressAnimator {
132 | /**
133 | * 自定义指示点挤压时的属性动画
134 | *
135 | * @param view IndicatorView
136 | * @param target 属性动画操作的目标对象
137 | * @return 返回定义好的属性动画,动画的启动由IndicatorView自己控制,用户不应该调用Animator.start()
138 | */
139 | AnimatorSet onIndicatorPress(IndicatorView view, IndicatorHolder target);
140 | }
141 |
142 | public interface OnIndicatorSwitchAnimator {
143 | /**
144 | * 自定义指示点切换时的属性动画
145 | *
146 | * @param view IndicatorView
147 | * @param target 属性动画操作的目标对象
148 | * @return 返回定义好的属性动画,动画的启动由IndicatorView自己控制,用户不应该调用Animator.start()
149 | */
150 | AnimatorSet onIndicatorSwitch(IndicatorView view, IndicatorHolder target);
151 | }
152 |
153 | /**
154 | * 指示点拖拽状态监听(前提为指示点可拖拽)
155 | */
156 | public interface OnIndicatorSeekListener {
157 |
158 | /**
159 | * 指示点被拖拽时回调
160 | *
161 | * @param view view
162 | * @param distance 当前指示点位置与最左边(或最下边“纵向视图”)的小圆点的间距
163 | * @param dotPos 当前指示点靠近的小圆点(松手后指示点会固定到这一位置)
164 | */
165 | void onSeekChange(IndicatorView view, int distance, int dotPos);
166 |
167 | /**
168 | * 指示点开始被拖拽,在指示点触摸回馈动画开始时回调
169 | *
170 | * @param view view
171 | */
172 | void onStartTrackingTouch(IndicatorView view);
173 |
174 | /**
175 | * 指示点停止被拖拽,手指离开指示点后立即回调
176 | *
177 | * @param view view
178 | */
179 | void onSopTrackingTouch(IndicatorView view);
180 |
181 | }
182 |
183 | public interface OnIndicatorChangeListener {
184 | /**
185 | * 指示点所在位置改变时回调
186 | * 注意:若拖动指示点位置从1到3再回到2后松手,则 oldPos 的值始终为1,currentPos 的值依次为 2,3,2
187 | *
188 | * @param currentPos 当前所在位置
189 | * @param oldPos 开始拖动时所在的位置
190 | */
191 | void onIndicatorChange(int currentPos, int oldPos);
192 | }
193 |
194 | private OnIndicatorPressAnimator mPressAnimator;
195 | private OnIndicatorSwitchAnimator mSwitchAnimator;
196 |
197 | private OnDotClickListener mListener;
198 | private OnIndicatorSeekListener mSeekListener;
199 | private OnIndicatorChangeListener mChangeListener;
200 |
201 | public void setOnIndicatorChangeListener(OnIndicatorChangeListener mChangeListener) {
202 | this.mChangeListener = mChangeListener;
203 | }
204 |
205 | public void setOnIndicatorSeekListener(OnIndicatorSeekListener mSeekListener) {
206 | this.mSeekListener = mSeekListener;
207 | }
208 |
209 | public void setOnIndicatorPressAnimator(OnIndicatorPressAnimator pressAnimator) {
210 | this.mPressAnimator = pressAnimator;
211 | }
212 |
213 | public void setOnIndicatorSwitchAnimator(OnIndicatorSwitchAnimator switchAnimator) {
214 | this.mSwitchAnimator = switchAnimator;
215 | }
216 |
217 | public void setOnDotClickListener(OnDotClickListener listener) {
218 | this.mListener = listener;
219 | }
220 |
221 | public IndicatorView(Context context) {
222 | this(context, null);
223 | }
224 |
225 | public IndicatorView(Context context, @Nullable AttributeSet attrs) {
226 | this(context, attrs, 0);
227 | }
228 |
229 | public IndicatorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
230 | super(context, attrs, defStyleAttr);
231 |
232 | mContext = context;
233 |
234 | final TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.IndicatorView, defStyleAttr, 0);
235 |
236 | //默认动画为“挤扁”
237 | mIndicatorSwitchAnim = array.getInteger(R.styleable.IndicatorView_IndicatorSwitchAnimation, INDICATOR_SWITCH_ANIM_SQUEEZE);
238 |
239 | //默认为 水平
240 | mIndicatorOrientation = array.getInteger(R.styleable.IndicatorView_indicatorOrientation, INDICATOR_ORIENTATION_HORIZONTAL);
241 |
242 | mTouchEnable = array.getBoolean(R.styleable.IndicatorView_touchEnable, true);
243 | if (!mTouchEnable) {
244 | mIndicatorDragEnable = false;
245 | mDotClickEnable = false;
246 | } else {
247 | mIndicatorDragEnable = array.getBoolean(R.styleable.IndicatorView_indicatorDragEnable, true);
248 | mDotClickEnable = array.getBoolean(R.styleable.IndicatorView_dotClickEnable, true);
249 | }
250 |
251 | mDotColor = array.getColor(R.styleable.IndicatorView_dotColor, Color.GRAY);
252 | mLineColor = array.getColor(R.styleable.IndicatorView_lineColor, Color.GRAY);
253 | mIndicatorColor = array.getColor(R.styleable.IndicatorView_indicatorColor, Color.LTGRAY);
254 |
255 | mDotSize = array.getDimensionPixelSize(R.styleable.IndicatorView_dotSize, defaultDotSize);
256 | mLineLength = array.getDimensionPixelSize(R.styleable.IndicatorView_lineLength, defaultLineLength);
257 | mLineWidth = array.getDimensionPixelSize(R.styleable.IndicatorView_lineWidth, minLineWidth);
258 | mIndicatorSize = array.getDimensionPixelSize(R.styleable.IndicatorView_indicatorSize, defaultIndicatorSize);
259 | //因为在onDraw中绘制指示点时会通过 indicatorHolder.getWidth() / 2 使两点间切换动画播放过程中椭圆边界不超过 mLineLength * Math.abs(switchTo - mIndicatorPos) + mIndicatorSize
260 | //因而这里乘以 2 否则绘制出来的大小会只有实际大小的一半
261 | mIndicatorSize *= 2;
262 | //默认动画时间为500ms
263 | mDuration = array.getInteger(R.styleable.IndicatorView_duration, 500);
264 | mDotCount = array.getInteger(R.styleable.IndicatorView_dotNum, 3);
265 | //判断小圆点个数是否超过上限30
266 | mDotCount = mDotCount > maxDotCount ? maxDotCount : mDotCount < minDotNum ? minDotNum : mDotCount;
267 | mIndicatorPos = array.getInteger(R.styleable.IndicatorView_indicatorPos, 0);
268 | //在 xml 中指定位置时从 1 开始
269 | mIndicatorPos = mIndicatorPos == 0 ? 0 : mIndicatorPos - 1;
270 | mLineVisible = array.getBoolean(R.styleable.IndicatorView_lineVisible, true);
271 |
272 | //释放资源
273 | array.recycle();
274 |
275 | mPaint = new Paint();
276 | indicatorHolder = new IndicatorHolder();
277 | mIndicatorColors = new int[mDotCount];
278 | for (int i = 0; i < mIndicatorColors.length; i++) {
279 | mIndicatorColors[i] = mIndicatorColor;
280 | }
281 | clickableAreas = new int[mDotCount][2];
282 |
283 |
284 | }
285 |
286 | @Override
287 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
288 | int widthMode = MeasureSpec.getMode(widthMeasureSpec);
289 | int widthSize = MeasureSpec.getSize(widthMeasureSpec);
290 | int heightMode = MeasureSpec.getMode(heightMeasureSpec);
291 | int heightSize = MeasureSpec.getSize(heightMeasureSpec);
292 | int width;
293 | int height;
294 |
295 | //默认的小圆点触摸反馈动画会放大小圆点,多留些空间给缩放动画(
296 | // 如果你发现你的小圆点在一些情况下显示不全时可在xml中增大padding或修改下面两个变量的值
297 | // int expandTerminalPadding = getPaddingLeft() + mIndicatorSize / 6;//左右两端
298 | // int expandSidePadding = getPaddingTop() + mIndicatorSize / 5;//上下两侧
299 | // setPadding(expandTerminalPadding, expandSidePadding, expandTerminalPadding, expandSidePadding);
300 |
301 | if (widthMode == MeasureSpec.EXACTLY) {
302 | width = widthSize;
303 | } else {//xml中宽度设为warp_content
304 | if (mIndicatorOrientation == INDICATOR_ORIENTATION_VERTICAL) //纵向
305 | width = getPaddingLeft() + getPaddingRight() + mIndicatorSize;
306 | else
307 | width = getPaddingLeft() + ((mDotCount - 1) * mLineLength + mIndicatorSize) + getPaddingRight();
308 | }
309 |
310 | if (heightMode == MeasureSpec.EXACTLY) {
311 | height = heightSize;
312 | } else {
313 | if (mIndicatorOrientation == INDICATOR_ORIENTATION_VERTICAL) //纵向
314 | height = ((mDotCount - 1) * mLineLength + mIndicatorSize) + getPaddingBottom() + getPaddingTop();
315 | else
316 | height = getPaddingTop() + mIndicatorSize + getPaddingBottom();
317 | }
318 |
319 |
320 | //兼容 api 11
321 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
322 | width = Math.max(width, getMinimumWidth());
323 | height = Math.max(height, getMinimumHeight());
324 | } else {
325 | width = Math.max(width, widthSize);
326 | height = Math.max(height, heightSize);
327 | }
328 |
329 | setMeasuredDimension(width, height);
330 |
331 | }
332 |
333 | @Override
334 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
335 | super.onLayout(changed, left, top, right, bottom);
336 |
337 | //计算出上下左右边界
338 | if (mIndicatorOrientation == INDICATOR_ORIENTATION_VERTICAL) {
339 | mBorderTop = getPaddingTop() + mIndicatorSize / 2;
340 | mBorderBottom = mBorderTop + mLineLength * (mDotCount - 1);
341 | } else {
342 | mBorderLeft = getPaddingLeft() + mIndicatorSize / 2;
343 | mBorderRight = mBorderLeft + mLineLength * (mDotCount - 1);
344 | }
345 |
346 | //在 onLayout 中获取 View 的测量高和测量宽
347 | if (indicatorHolder != null) {
348 | indicatorHolder.setColor(mIndicatorColors[mIndicatorPos]);
349 | if (mIndicatorOrientation == INDICATOR_ORIENTATION_VERTICAL) { //纵向
350 | indicatorHolder.setCenterX(getMeasuredWidth() / 2);
351 | indicatorHolder.setCenterY(mIndicatorPos * mLineLength + getPaddingBottom() + mIndicatorSize / 2);
352 | } else {
353 | indicatorHolder.setCenterX(mIndicatorPos * mLineLength + getPaddingLeft() + mIndicatorSize / 2);
354 | indicatorHolder.setCenterY(getMeasuredHeight() / 2);
355 | }
356 | indicatorHolder.setHeight(mIndicatorSize);
357 | indicatorHolder.setWidth(mIndicatorSize);
358 | indicatorHolder.setAlpha(255);
359 | }
360 |
361 | }
362 |
363 | //画线段
364 | private void drawLine(Canvas canvas) {
365 | mPaint.setColor(mLineColor);
366 |
367 | if (mIndicatorOrientation == INDICATOR_ORIENTATION_VERTICAL) { //纵向,从上往下绘制
368 | for (int i = 0; i < mDotCount - 1; i++) {
369 | int top = getPaddingTop() + mIndicatorSize / 2 + mLineLength * (i + 1);
370 | int bottom = getPaddingTop() + mIndicatorSize / 2 + mLineLength * i;
371 | int left = (getWidth() - mLineWidth) / 2;
372 | int right = (getWidth() + mLineWidth) / 2;
373 |
374 | canvas.drawRect(left, top, right, bottom, mPaint);
375 | }
376 | } else { //横向,从左往右绘制
377 | for (int i = 0; i < mDotCount - 1; i++) {
378 | int top = (getHeight() - mLineWidth) / 2;
379 | int bottom = (getHeight() + mLineWidth) / 2;
380 | int left = getPaddingLeft() + mIndicatorSize / 2 + mLineLength * i;
381 | int right = getPaddingLeft() + mIndicatorSize / 2 + mLineLength * (i + 1);
382 |
383 | canvas.drawRect(left, top, right, bottom, mPaint);
384 | }
385 | }
386 | }
387 |
388 | //画小圆点
389 | private void drawDots(Canvas canvas) {
390 |
391 | switchToTemp = switchTo;//用于 mChangeListener 回调判断,见 onTouchEvent 方法
392 |
393 | if (mIndicatorOrientation == INDICATOR_ORIENTATION_VERTICAL) { //纵向 从上往下绘制
394 | for (int i = 0; i < clickableAreas.length; i++) {
395 | int cx = getWidth() / 2;
396 | int cy = i * mLineLength + getPaddingBottom() + mIndicatorSize / 2;
397 |
398 | if (switchTo != -1 && i == switchTo) {
399 | mPaint.setColor(mIndicatorColors[switchTo]);
400 | } else
401 | mPaint.setColor(mDotColor);
402 |
403 | canvas.drawCircle(cx, cy, mDotSize / 2, mPaint);
404 | clickableAreas[i][0] = cx;
405 | clickableAreas[i][1] = cy;
406 | }
407 | } else {//横向,从左往右绘制
408 | for (int i = 0; i < clickableAreas.length; i++) {
409 | int cx = i * mLineLength + getPaddingLeft() + mIndicatorSize / 2;
410 | int cy = getHeight() / 2;
411 |
412 | if (switchTo != -1 && i == switchTo) {
413 | mPaint.setColor(mIndicatorColors[switchTo]);
414 | } else
415 | mPaint.setColor(mDotColor);
416 | canvas.drawCircle(cx, cy, mDotSize / 2, mPaint);
417 |
418 | clickableAreas[i][0] = cx;
419 | clickableAreas[i][1] = cy;
420 | }
421 | }
422 | }
423 |
424 | //画指示点
425 | private void drawIndicator(Canvas canvas) {
426 | mPaint.setColor(indicatorHolder.getColor());
427 | mPaint.setAlpha(indicatorHolder.getAlpha());
428 |
429 | // canvas.drawOval(
430 | // indicatorHolder.getCenterX() - indicatorHolder.getWidth() / 2,
431 | // indicatorHolder.getCenterY() - indicatorHolder.getHeight() / 2,
432 | // indicatorHolder.getCenterX() + indicatorHolder.getWidth() / 2,
433 | // indicatorHolder.getCenterY() + indicatorHolder.getHeight() / 2,
434 | // mPaint
435 | // );
436 | //
437 |
438 | float left = indicatorHolder.getCenterX() - indicatorHolder.getWidth() / 2;
439 | float top = indicatorHolder.getCenterY() - indicatorHolder.getHeight() / 2;
440 | float right = indicatorHolder.getCenterX() + indicatorHolder.getWidth() / 2;
441 | float bottom = indicatorHolder.getCenterY() + indicatorHolder.getHeight() / 2;
442 |
443 | //兼容 api 11,不使用 canvas.drawOval
444 | RectF rectF = new RectF();
445 | rectF.left = left;
446 | rectF.top = top;
447 | rectF.right = right;
448 | rectF.bottom = bottom;
449 |
450 | canvas.drawOval(rectF, mPaint);
451 | }
452 |
453 | @Override
454 | protected void onDraw(Canvas canvas) {
455 | super.onDraw(canvas);
456 |
457 | //去锯齿
458 | mPaint.setAntiAlias(true);
459 |
460 | //画线段(如果可见)
461 | if (mLineVisible) {
462 | drawLine(canvas);
463 | }
464 |
465 | //画小圆点
466 | drawDots(canvas);
467 |
468 | //画指示点
469 | drawIndicator(canvas);
470 |
471 | }
472 |
473 | @Override
474 | public boolean onTouchEvent(MotionEvent event) {
475 |
476 | if (!mTouchEnable)
477 | return true;
478 |
479 | //动画正在进行时不在响应点击事件
480 | if (haveIndicatorPressAniming)
481 | return true;
482 |
483 | int ex = (int) event.getX();
484 | int ey = (int) event.getY();
485 | int temp = mLineLength / 2;
486 | switchTo = 0;
487 | boolean inBound = false;
488 | //判断当前手指所在的小圆点是哪个
489 | if (mIndicatorOrientation != INDICATOR_ORIENTATION_VERTICAL) { //横向
490 | for (; switchTo < mDotCount; switchTo++) {
491 | int[] xy = clickableAreas[switchTo];
492 | //只对x坐标位置进行判断,这样即使用户手指在控件外面(先在控件内触摸后不抬起而是滑到控件外面)滑动也能判断
493 | if (ex <= xy[0] + temp && ex >= xy[0] - temp) {
494 | inBound = true;
495 | break;
496 | }
497 | }
498 |
499 | //在边界外点击,并且没有拖拽时不接受触摸事件
500 | if (!inBound && !haveIndicatorDraged)
501 | return false;
502 |
503 | //超出边界时要检查
504 | if (switchTo == mDotCount)
505 | if (indicatorHolder.getCenterX() > mBorderRight)
506 | switchTo -= 1;
507 | else
508 | switchTo = 0;
509 |
510 | } else {
511 | for (; switchTo < mDotCount; switchTo++) {
512 | int[] xy = clickableAreas[switchTo];
513 | //只对y坐标位置进行判断,这样即使用户手指在控件外面(先在控件内触摸后不抬起而是滑到控件外面)滑动也能判断
514 | if (ey <= xy[1] + temp && ey >= xy[1] - temp) {
515 | inBound = true;
516 | break;
517 | }
518 | }
519 |
520 | if (!inBound && !haveIndicatorDraged)
521 | return false;
522 |
523 | if (switchTo == mDotCount)
524 | if (indicatorHolder.getCenterY() > mBorderTop)
525 | switchTo -= 1;
526 | else
527 | switchTo = 0;
528 | }
529 |
530 | if (switchTo != switchToTemp && switchTo != mIndicatorPos) {
531 | if (mChangeListener != null)
532 | mChangeListener.onIndicatorChange(switchTo, mIndicatorPos);
533 | }
534 |
535 | if (switchTo != mIndicatorPos && !mDotClickEnable && !haveIndicatorDraged) {
536 | return true;
537 | }
538 |
539 | if (event.getAction() == MotionEvent.ACTION_DOWN) {
540 | //按下且不是指示点所在的小圆点
541 | if (mIndicatorPos != switchTo) {
542 | startSwitchAnimation();
543 | if (mListener != null)
544 | mListener.onDotClickChange(this, switchTo);
545 | } else {//按下且是指示点所在的小圆点
546 | if (mIndicatorDragEnable)
547 | startPressAnimation();
548 | }
549 | } else if (event.getAction() == MotionEvent.ACTION_UP) { //手抬起
550 | if (mIndicatorDragEnable)
551 | if (mSeekListener != null)
552 | mSeekListener.onSopTrackingTouch(this);
553 |
554 | if (switchTo != mIndicatorPos || haveIndicatorDraged) {
555 | haveIndicatorDraged = false;
556 | if (mIndicatorDragEnable)
557 | startSwitchAnimation();
558 | }
559 | } else { //按着+拖拽
560 | if (mIndicatorDragEnable) {
561 | haveIndicatorDraged = true;
562 | if (mIndicatorOrientation == INDICATOR_ORIENTATION_VERTICAL) { //纵向
563 | indicatorHolder.setCenterY(ey);
564 | if (mSeekListener != null)
565 | mSeekListener.onSeekChange(this, (getHeight() - (getPaddingBottom() + mIndicatorSize / 2)) - indicatorHolder.getCenterY(), switchTo);
566 | } else {
567 | indicatorHolder.setCenterX(ex);
568 | if (mSeekListener != null)
569 | mSeekListener.onSeekChange(this, indicatorHolder.getCenterX() - (getPaddingLeft() + mIndicatorSize / 2), switchTo);
570 | }
571 | }
572 | }
573 |
574 | return true;
575 | }
576 |
577 | /**
578 | * 指示点触摸(挤压)动画
579 | */
580 | private void startPressAnimation() {
581 | if (mPressAnimator == null) {
582 | //缩放
583 | int terminal = mIndicatorSize;
584 | int center = mIndicatorSize * 3 / 2;
585 | ValueAnimator scaleAnimH = ObjectAnimator.ofInt(indicatorHolder, "height", terminal, center, terminal);
586 | ValueAnimator scaleAnimW = ObjectAnimator.ofInt(indicatorHolder, "width", terminal, center, terminal);
587 |
588 | //颜色渐变
589 | int terminalColor = mIndicatorColor;
590 | int centerColor = mDotColor;
591 | ValueAnimator colorAnim = null;
592 | // ofArgb 方法需要做兼容性处理
593 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
594 | colorAnim = ObjectAnimator.ofArgb(indicatorHolder, "color", terminalColor, centerColor, terminalColor);
595 | } else {
596 | colorAnim = ObjectAnimator.ofInt(indicatorHolder, "color", terminalColor, centerColor, terminalColor);
597 | colorAnim.setEvaluator(new ArgbEvaluator());
598 | }
599 |
600 | AnimatorSet defaultIndicatorPressAnim = new AnimatorSet();
601 | defaultIndicatorPressAnim.addListener(new Animator.AnimatorListener() {
602 | @Override
603 | public void onAnimationStart(Animator animation) {
604 | haveIndicatorPressAniming = true;
605 | if (mIndicatorDragEnable)
606 | if (mSeekListener != null)
607 | mSeekListener.onStartTrackingTouch(IndicatorView.this);
608 | }
609 |
610 | @Override
611 | public void onAnimationEnd(Animator animation) {
612 | haveIndicatorPressAniming = false;
613 | }
614 |
615 | @Override
616 | public void onAnimationCancel(Animator animation) {
617 | haveIndicatorPressAniming = false;
618 |
619 | }
620 |
621 | @Override
622 | public void onAnimationRepeat(Animator animation) {
623 |
624 | }
625 | });
626 | defaultIndicatorPressAnim.setDuration(500);
627 | defaultIndicatorPressAnim.play(scaleAnimH).with(scaleAnimW).with(colorAnim);
628 | defaultIndicatorPressAnim.start();
629 | } else { //自定义动画
630 | AnimatorSet customfAnim = mPressAnimator.onIndicatorPress(this, indicatorHolder);
631 | customfAnim.addListener(new Animator.AnimatorListener() {
632 |
633 | @Override
634 | public void onAnimationStart(Animator animation) {
635 | haveIndicatorPressAniming = true;
636 | if (mIndicatorDragEnable)
637 | if (mSeekListener != null)
638 | mSeekListener.onStartTrackingTouch(IndicatorView.this);
639 | }
640 |
641 | @Override
642 | public void onAnimationEnd(Animator animation) {
643 | haveIndicatorPressAniming = false;
644 | }
645 |
646 | @Override
647 | public void onAnimationCancel(Animator animation) {
648 | haveIndicatorPressAniming = false;
649 |
650 | }
651 |
652 | @Override
653 | public void onAnimationRepeat(Animator animation) {
654 |
655 | }
656 | });
657 | //进行挤压动画时控件不再响应触摸事件,因而动画时间不能太长
658 | customfAnim.setDuration(customfAnim.getDuration() > 700 ? 700 : customfAnim.getDuration());
659 | customfAnim.start();
660 | }
661 |
662 | }
663 |
664 | /**
665 | * 指示点切换动画
666 | */
667 | private void startSwitchAnimation() {
668 |
669 | //平移
670 | int end;
671 | ValueAnimator trainsAnim;
672 | ValueAnimator colorAnim;
673 | if (mIndicatorOrientation == INDICATOR_ORIENTATION_VERTICAL) { //纵向
674 | int start = indicatorHolder.getCenterY();
675 | end = switchTo * mLineLength + getPaddingBottom() + mIndicatorSize / 2;
676 | trainsAnim = ObjectAnimator.ofInt(indicatorHolder, "centerY", start, end);
677 | } else {
678 | int start = indicatorHolder.getCenterX();
679 | end = switchTo * mLineLength + getPaddingLeft() + mIndicatorSize / 2;
680 | trainsAnim = ObjectAnimator.ofInt(indicatorHolder, "centerX", start, end);
681 | }
682 |
683 | //颜色渐变
684 | int startColor = indicatorHolder.getColor();
685 | int endColor = mIndicatorColors[switchTo];
686 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
687 | colorAnim = ObjectAnimator.ofArgb(indicatorHolder, "color", startColor, endColor);
688 | } else {
689 | colorAnim = ObjectAnimator.ofInt(indicatorHolder, "color", startColor, endColor);
690 | colorAnim.setEvaluator(new ArgbEvaluator());
691 | }
692 |
693 | AnimatorSet movingAnim = new AnimatorSet();
694 | movingAnim.setDuration(mDuration);
695 | movingAnim.play(trainsAnim).with(colorAnim);
696 |
697 | tempLineColor = mLineColor;
698 | AnimatorSet defaultIndicatorSwitchAnim = new AnimatorSet();
699 | defaultIndicatorSwitchAnim.addListener(new Animator.AnimatorListener() {
700 | @Override
701 | public void onAnimationStart(Animator animation) {
702 | if (mChangeLineColorWhileSwitch)
703 | mLineColor = mIndicatorColors[switchTo];
704 | haveIndicatorPressAniming = true;
705 | }
706 |
707 | @Override
708 | public void onAnimationEnd(Animator animation) {
709 | animEnd();
710 | }
711 |
712 | @Override
713 | public void onAnimationCancel(Animator animation) {
714 | animEnd();
715 | }
716 |
717 | @Override
718 | public void onAnimationRepeat(Animator animation) {
719 |
720 | }
721 | });
722 |
723 | if (mSwitchAnimator == null) {
724 | switch (mIndicatorSwitchAnim) {
725 | case INDICATOR_SWITCH_ANIM_NONE:
726 | if (mIndicatorOrientation == INDICATOR_ORIENTATION_VERTICAL) //纵向
727 | indicatorHolder.setCenterY(end);
728 | else
729 | indicatorHolder.setCenterX(end);
730 | animEnd();
731 | break;
732 | case INDICATOR_SWITCH_ANIM_SQUEEZE:
733 | //“挤扁”
734 | ValueAnimator heightAnim;
735 | ValueAnimator widthAnim;
736 | int centerH;
737 | int centerW;
738 | if (mIndicatorOrientation == INDICATOR_ORIENTATION_VERTICAL) { //纵向
739 | centerH = Math.abs(indicatorHolder.getCenterY() - clickableAreas[switchTo][1]);
740 | centerW = mLineWidth;
741 | } else {
742 | centerH = mLineWidth;
743 | //indicatorHolder.getCenterX()的值在动画过程中会被trainsAnim动画不断改变
744 | //centerW:指示点当前所在位置和目标点间的距离
745 | centerW = Math.abs(indicatorHolder.getCenterX() - clickableAreas[switchTo][0]);
746 | }
747 | heightAnim = ObjectAnimator.ofInt(indicatorHolder, "height", mIndicatorSize, centerH, 0);
748 | widthAnim = ObjectAnimator.ofInt(indicatorHolder, "width", mIndicatorSize, centerW, 0);
749 | heightAnim.setDuration(mDuration);
750 | widthAnim.setDuration(mDuration);
751 |
752 | //缩放
753 | ValueAnimator scaleAnimH = ObjectAnimator.ofInt(indicatorHolder, "height", mDotSize, mIndicatorSize);
754 | ValueAnimator scaleAnimW = ObjectAnimator.ofInt(indicatorHolder, "width", mDotSize, mIndicatorSize);
755 | AnimatorSet scaleSet = new AnimatorSet();
756 | scaleSet.play(scaleAnimH).with(scaleAnimW);
757 | scaleSet.setDuration(500);
758 |
759 | defaultIndicatorSwitchAnim.play(movingAnim).with(heightAnim).with(widthAnim);
760 | defaultIndicatorSwitchAnim.play(scaleSet).after(movingAnim);
761 | defaultIndicatorSwitchAnim.start();
762 | break;
763 | case INDICATOR_SWITCH_ANIM_TRANSLATION:
764 | defaultIndicatorSwitchAnim.play(movingAnim);
765 | defaultIndicatorSwitchAnim.start();
766 | break;
767 | }
768 |
769 | } else { //自定义
770 | tempLineColor = mLineColor;
771 | AnimatorSet customAnim = mSwitchAnimator.onIndicatorSwitch(this, indicatorHolder);
772 | customAnim.play(movingAnim);
773 | customAnim.addListener(new Animator.AnimatorListener() {
774 | @Override
775 | public void onAnimationStart(Animator animation) {
776 | mLineColor = indicatorHolder.getColor();
777 | haveIndicatorPressAniming = true;
778 | }
779 |
780 | @Override
781 | public void onAnimationEnd(Animator animation) {
782 | animEnd();
783 | }
784 |
785 | @Override
786 | public void onAnimationCancel(Animator animation) {
787 | animEnd();
788 | }
789 |
790 | @Override
791 | public void onAnimationRepeat(Animator animation) {
792 |
793 | }
794 | });
795 | customAnim.start();
796 | }
797 |
798 | }
799 |
800 | /**
801 | * 指示点切换动画结束或取消时重置和恢复一些变量的值
802 | */
803 | private void animEnd() {
804 | mLineColor = tempLineColor;
805 | mIndicatorPos = switchTo;
806 | switchTo = -1;
807 | haveIndicatorPressAniming = false;
808 | }
809 |
810 | /**
811 | * 属性动画的目标对象类-指示点,属性动画通过不断调用该类的setXXX方法改变指示点的属性值并重绘控件以实现动画
812 | */
813 | public class IndicatorHolder {
814 | private int centerX;
815 | private int centerY;
816 | private int height;
817 | private int color;
818 | private int width;
819 | private int alpha;
820 |
821 | public void setAlpha(int alpha) {
822 | this.alpha = alpha;
823 | invalidate();
824 | }
825 |
826 | public int getAlpha() {
827 |
828 | return alpha;
829 | }
830 |
831 | public void setHeight(int height) {
832 | this.height = height / 2;
833 | invalidate();
834 | }
835 |
836 | public void setWidth(int width) {
837 | this.width = width / 2;
838 | invalidate();
839 | }
840 |
841 | public void setCenterY(int centerY) {
842 | this.centerY = centerY;
843 | invalidate();
844 | }
845 |
846 | public void setColor(int color) {
847 | this.color = color;
848 | invalidate();
849 | }
850 |
851 | public void setCenterX(int centerX) {
852 | this.centerX = centerX;
853 | invalidate();
854 | }
855 |
856 | public int getColor() {
857 | return color;
858 | }
859 |
860 | public int getHeight() {
861 | return height;
862 | }
863 |
864 | public int getWidth() {
865 | return width;
866 | }
867 |
868 | public int getCenterX() {
869 | return centerX;
870 | }
871 |
872 | public int getCenterY() {
873 | return centerY;
874 | }
875 |
876 | }
877 |
878 | public void setIndicatorPos(int indicatorPos) {
879 | if (indicatorPos != mIndicatorPos) {
880 | switchTo = indicatorPos;
881 | startSwitchAnimation();
882 | }
883 | }
884 |
885 | public void setDotColor(int dotColor) {
886 | this.mDotColor = dotColor;
887 | invalidate();
888 | }
889 |
890 | public void setLineColor(int lineColor) {
891 | this.mLineColor = lineColor;
892 | tempLineColor = mLineColor;
893 | invalidate();
894 | }
895 |
896 | public void setLineVisible(boolean lineVisible) {
897 | this.mLineVisible = lineVisible;
898 | invalidate();
899 | }
900 |
901 | public void setLineHeight(int lineHeight) {
902 | this.mLineWidth = lineHeight;
903 | invalidate();
904 | }
905 |
906 | /**
907 | * 在进行指示点切换过程中是否改变线段颜色
908 | *
909 | * @param chage false 为不改变
910 | */
911 | public void changeLineColorWhileSwitch(boolean chage) {
912 | this.mChangeLineColorWhileSwitch = chage;
913 | }
914 |
915 | /**
916 | * 将指示点在各个位置的颜色全部设置为同一颜色
917 | *
918 | * @param color 颜色
919 | */
920 | public void setIndicatorColor(int color) {
921 | this.mIndicatorColor = color;
922 | this.indicatorHolder.setColor(color);
923 | for (int i = 0; i < mIndicatorColors.length; i++) {
924 | mIndicatorColors[i] = color;
925 | }
926 | invalidate();
927 | }
928 |
929 | /**
930 | * 修改指定位置处指示点的颜色
931 | *
932 | * @param index 下标 (“水平视图”时从左往右依次为 0 - n,“纵向视图”时从上往下依次为 0 - n)
933 | * @param color 颜色
934 | */
935 | public void setIndicatorColor(int index, int color) {
936 | mIndicatorColors[index] = color;
937 | invalidate();
938 | }
939 |
940 | /**
941 | * 为所有指示点设置颜色
942 | *
943 | * @param colors 颜色值
944 | */
945 | public void setIndicatorColor(int... colors) {
946 |
947 | if (colors.length < mDotCount) {
948 | for (int i = 0; i < colors.length; i++) {
949 | mIndicatorColors[i] = colors[i];
950 | }
951 | } else {
952 | for (int i = 0; i < mDotCount; i++) {
953 | mIndicatorColors[i] = colors[i];
954 | }
955 | }
956 |
957 | invalidate();
958 | }
959 |
960 | public void setIndicatorSwitchAnim(int anim) {
961 | if (anim >= INDICATOR_SWITCH_ANIM_NONE && anim <= INDICATOR_SWITCH_ANIM_SQUEEZE)
962 | this.mIndicatorSwitchAnim = anim;
963 | }
964 |
965 | /**
966 | * 动态修改圆点个数,如果圆点个数增加,那么指示点位置被保留;减小且原先指示位置大于新圆点个数时最后一个位置成为指示点
967 | *
968 | * @param count 新的圆点个数
969 | */
970 | public void setDotCount(int count) {
971 | setDotCount(count, count <= mIndicatorPos ? count : mIndicatorPos);
972 | }
973 |
974 | /**
975 | * 动态修改指示点个数,指定新的指示点位置
976 | *
977 | * @param count 新的圆点个数
978 | * @param indicatorPos 指示点位置 1 ~ count
979 | */
980 | public void setDotCount(int count, int indicatorPos) {
981 |
982 | if (count >= minDotNum && count <= maxDotCount && count != mDotCount) {
983 | //注意:如果将mDotCount变小,那么指定指示点的自定义颜色会丢失
984 | mIndicatorColors = Arrays.copyOf(mIndicatorColors, count);
985 | if (count > mDotCount) {
986 | Arrays.fill(mIndicatorColors, mDotCount - 1, count, mIndicatorColor);
987 | }
988 |
989 | mDotCount = count;
990 | if (indicatorPos >= 1 && indicatorPos <= count) {
991 | mIndicatorPos = indicatorPos - 1;
992 | }
993 |
994 | clickableAreas = new int[mDotCount][2];
995 | this.requestLayout();
996 | }
997 |
998 | }
999 |
1000 | public int getDotColor() {
1001 | return mDotColor;
1002 | }
1003 |
1004 | public int getLineColor() {
1005 | return mLineColor;
1006 | }
1007 |
1008 | public boolean isLineVisible() {
1009 | return mLineVisible;
1010 | }
1011 |
1012 | public int getDotPixelSize() {
1013 | return mDotSize;
1014 | }
1015 |
1016 | public int getLinePixelWidth() {
1017 | return mLineLength;
1018 | }
1019 |
1020 | public int getLinePixelHeight() {
1021 | return mLineWidth;
1022 | }
1023 |
1024 | public int[] getIndicatorColors() {
1025 | return mIndicatorColors;
1026 | }
1027 |
1028 | /**
1029 | * 获得指示点的颜色值,该颜色值只有在 xml 中指定或调用{@link #setIndicatorColor(int color)}方法时才会改变
1030 | * 如果你想获得当前指示点的颜色值应使用{@link #getCurrentIndicatorColor()}或
1031 | * 使用{@link #getIndicatorColors()}方法获得所有指示点在对应位置的颜色值
1032 | *
1033 | * @return 颜色
1034 | */
1035 | @Deprecated
1036 | public int getIndicatorColor() {
1037 | return mIndicatorColor;
1038 | }
1039 |
1040 | public int getCurrentIndicatorColor() {
1041 | return mIndicatorColors[mIndicatorPos];
1042 | }
1043 |
1044 | public int getIndicatorPixeSize() {
1045 | return mIndicatorSize;
1046 | }
1047 |
1048 | public int getDotCount() {
1049 | return mDotCount;
1050 | }
1051 |
1052 | public int getIndicatorPos() {
1053 | return mIndicatorPos;
1054 | }
1055 |
1056 | public int getmIndicatorOrientation() {
1057 | return mIndicatorOrientation;
1058 | }
1059 |
1060 | }
1061 |
--------------------------------------------------------------------------------