├── .gitignore
├── LICENSE.txt
├── README.md
├── RangeBarSample
├── .classpath
├── .gitignore
├── .project
├── AndroidManifest.xml
├── assets
│ └── Roboto-Thin.ttf
├── build.gradle
├── ic_launcher-web.png
├── proguard-project.txt
├── project.properties
├── res
│ ├── drawable-hdpi
│ │ └── ic_launcher.png
│ ├── drawable-mdpi
│ │ └── ic_launcher.png
│ ├── drawable-xhdpi
│ │ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ │ └── ic_launcher.png
│ ├── layout
│ │ └── activity_main.xml
│ ├── menu
│ │ └── main.xml
│ ├── values-large
│ │ └── dimens.xml
│ ├── values-normal
│ │ └── dimens.xml
│ ├── values-small
│ │ └── dimens.xml
│ ├── values-sw600dp
│ │ └── dimens.xml
│ ├── values-sw720dp-land
│ │ └── dimens.xml
│ ├── values-v11
│ │ └── styles.xml
│ ├── values-v14
│ │ └── styles.xml
│ ├── values-xlarge
│ │ └── dimens.xml
│ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
└── src
│ └── com
│ └── example
│ └── rangebarsample
│ ├── ColorPickerDialog.java
│ ├── Component.java
│ └── MainActivity.java
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── rangebar
├── .classpath
├── .gitignore
├── .project
├── AndroidManifest.xml
├── build.gradle
├── proguard-project.txt
├── project.properties
├── res
│ ├── drawable-xhdpi
│ │ ├── seek_thumb_normal.png
│ │ └── seek_thumb_pressed.png
│ ├── values-v11
│ │ └── styles.xml
│ ├── values-v14
│ │ └── styles.xml
│ └── values
│ │ ├── attrs.xml
│ │ ├── strings.xml
│ │ └── styles.xml
└── src
│ └── com
│ └── edmodo
│ └── rangebar
│ ├── Bar.java
│ ├── ConnectingLine.java
│ ├── MeasureSpecMode.java
│ ├── RangeBar.java
│ └── Thumb.java
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # built application files
3 | *.apk
4 | *.ap_
5 |
6 | # files for the dex VM
7 | *.dex
8 |
9 | # Java class files
10 | *.class
11 |
12 | # generated files
13 | bin/
14 | gen/
15 | out/
16 |
17 | # Local configuration file (sdk path, etc)
18 | local.properties
19 |
20 | # Mac OS X internal files
21 | .DS_Store
22 |
23 | # Eclipse generated files/folders
24 | .metadata/
25 | .settings/
26 |
27 | #IntelliJ IDEA
28 | .idea
29 | *.iml
30 | *.ipr
31 | *.iws
32 | out
33 |
34 | # Gradle folder
35 | .gradle/
36 | build/
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 | AnimatedRangeBar
10 | ================
11 |
12 | The `AnimatedRangeBar` is similar to an enhanced `SeekBar` widget, though it doesn't make use of the `SeekBar`. It provides for the selection of a range of values rather than a single value. The selectable range values are discrete values designated by tick marks; the thumb (handle) will snap to the nearest tick mark.
13 |
14 | [](https://github.com/DevLight-Mobile-Agency)
15 |
16 | [](https://github.com/DevLight-Mobile-Agency/AnimatedRangeBar/blob/master/LICENSE.txt)
17 |
18 |
19 |
20 |
21 |
22 | You can check the sample app [here](https://github.com/DevLight-Mobile-Agency/AnimatedRangeBar/tree/master/RangeBarSample).
23 |
24 | Download
25 | ========
26 |
27 | Just fork and download code and be ready to use it.
28 |
29 | Android SDK Version
30 | ===================
31 | `AnimatedRangeBar` requires a minimum SDK version of 7.
32 |
33 | Sample
34 | ======
35 | Developers can customize the following attributes (both via `XML` and programmatically):
36 | - bar color
37 | - bar thickness
38 | - tick height
39 | - number of ticks
40 | - connecting line thickness
41 | - connecting line color
42 | - thumb normal image
43 | - thumb pressed image
44 |
45 | If any of the following attributes are specified, the thumb images will be ignored and be replaced with a circle whose properties can be specified as follows:
46 | - thumb radius
47 | - thumb normal color
48 | - thumb pressed color
49 | - thumb animate
50 |
51 | Finally, the following property can be set programmatically, but not via `XML`:
52 | - thumb indices (the location of the thumbs on the `RangeBar`)
53 |
54 | Wiki
55 | ====
56 | For more information, see the linked Github Wiki page.
57 | https://github.com/edmodo/range-bar/wiki
58 |
59 | Author
60 | ======
61 |
62 | Created by [Basil Miller](https://github.com/GIGAMOLE) - [@gigamole](mailto:gigamole53@gmail.com)
63 |
64 | Fork
65 | ====
66 | Forked from [edmodo/range-bar](https://github.com/edmodo/range-bar)
67 |
68 | Company
69 | =======
70 |
71 | [](https://www.facebook.com/devlightagency) [](https://twitter.com/DevLightIO) [](https://www.linkedin.com/company/devlight)
72 |
73 | [Here](https://github.com/DevLight-Mobile-Agency) you can see open source work developed by Devlight LLC.
74 | This and another works is an exclusive property of Devlight LLC.
75 |
76 | If you want to use this library in applications which will be available on Google Play, please report us or author of the library about it.
77 |
78 | Whether you're searching for a new partner or trusted team for creating your new great product we are always ready to start work with you.
79 |
80 | You can contact us: info@devlight.io or opensource@devlight.io.
81 | Thanks in advance.
82 |
83 | Devlight LLC, 2016
84 | [devlight.io](http://devlight.io)
--------------------------------------------------------------------------------
/RangeBarSample/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/RangeBarSample/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # built application files
3 | *.apk
4 | *.ap_
5 |
6 | # files for the dex VM
7 | *.dex
8 |
9 | # Java class files
10 | *.class
11 |
12 | # generated files
13 | bin/
14 | gen/
15 | out/
16 |
17 | # Local configuration file (sdk path, etc)
18 | local.properties
19 |
20 | # Mac OS X internal files
21 | .DS_Store
22 |
23 | # Eclipse generated files/folders
24 | .metadata/
25 | .settings/
26 |
27 | #IntelliJ IDEA
28 | .idea
29 | *.iml
30 | *.ipr
31 | *.iws
32 | out
33 |
34 | # Gradle folder
35 | .gradle/
36 | build/
--------------------------------------------------------------------------------
/RangeBarSample/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | RangeBarSample
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/RangeBarSample/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/RangeBarSample/assets/Roboto-Thin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devlight/AnimatedRangeBar/0087f967911fa2cf3eafc298d8bb645a0c3c234f/RangeBarSample/assets/Roboto-Thin.ttf
--------------------------------------------------------------------------------
/RangeBarSample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'android'
2 |
3 | dependencies {
4 | compile project(':rangebar')
5 | }
6 |
7 | android {
8 |
9 | compileSdkVersion 19
10 | buildToolsVersion "19.1"
11 |
12 | defaultConfig {
13 | minSdkVersion 7
14 | targetSdkVersion 19
15 | }
16 |
17 | sourceSets {
18 | main {
19 | manifest.srcFile 'AndroidManifest.xml'
20 | java.srcDirs = ['src']
21 | resources.srcDirs = ['src']
22 | aidl.srcDirs = ['src']
23 | renderscript.srcDirs = ['src']
24 | res.srcDirs = ['res']
25 | assets.srcDirs = ['assets']
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/RangeBarSample/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devlight/AnimatedRangeBar/0087f967911fa2cf3eafc298d8bb645a0c3c234f/RangeBarSample/ic_launcher-web.png
--------------------------------------------------------------------------------
/RangeBarSample/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/RangeBarSample/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-17
15 | android.library.reference.1=../rangebar
16 |
--------------------------------------------------------------------------------
/RangeBarSample/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devlight/AnimatedRangeBar/0087f967911fa2cf3eafc298d8bb645a0c3c234f/RangeBarSample/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/RangeBarSample/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devlight/AnimatedRangeBar/0087f967911fa2cf3eafc298d8bb645a0c3c234f/RangeBarSample/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/RangeBarSample/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devlight/AnimatedRangeBar/0087f967911fa2cf3eafc298d8bb645a0c3c234f/RangeBarSample/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/RangeBarSample/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devlight/AnimatedRangeBar/0087f967911fa2cf3eafc298d8bb645a0c3c234f/RangeBarSample/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/RangeBarSample/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
19 |
20 |
27 |
28 |
36 |
37 |
43 |
44 |
49 |
50 |
55 |
56 |
61 |
62 |
69 |
70 |
71 |
76 |
77 |
82 |
83 |
90 |
91 |
92 |
93 |
103 |
104 |
108 |
109 |
114 |
115 |
119 |
120 |
126 |
127 |
131 |
132 |
138 |
139 |
143 |
144 |
150 |
151 |
155 |
156 |
162 |
163 |
169 |
170 |
176 |
177 |
183 |
184 |
190 |
191 |
198 |
199 |
200 |
201 |
--------------------------------------------------------------------------------
/RangeBarSample/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/RangeBarSample/res/values-large/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 22sp
8 |
9 |
--------------------------------------------------------------------------------
/RangeBarSample/res/values-normal/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 16sp
8 |
9 |
--------------------------------------------------------------------------------
/RangeBarSample/res/values-small/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 14sp
8 |
9 |
--------------------------------------------------------------------------------
/RangeBarSample/res/values-sw600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/RangeBarSample/res/values-sw720dp-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 128dp
8 |
9 |
10 |
--------------------------------------------------------------------------------
/RangeBarSample/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/RangeBarSample/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/RangeBarSample/res/values-xlarge/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 22sp
8 |
9 |
--------------------------------------------------------------------------------
/RangeBarSample/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ffffff
4 | #33b5e5
5 |
6 |
--------------------------------------------------------------------------------
/RangeBarSample/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16dp
5 | 16dp
6 |
7 |
8 |
--------------------------------------------------------------------------------
/RangeBarSample/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | RangeBar Sample
5 | Settings
6 | RangeBar
7 | tickCount = 7
8 | tickHeight = 24
9 | barWeight = 2
10 | barColor = #CCCCCC
11 | connectingLineWeight = 4
12 | connectingLineColor = #33B5E5
13 | thumbRadius = N/A
14 | thumbColorNormal = N/A
15 | thumbColorPressed = N/A
16 | New
17 | Default
18 | Select a Color
19 | Reset Thumb Colors
20 | 0
21 | leftIndex
22 | 6
23 | rightIndex
24 | Refresh Indices
25 |
26 |
--------------------------------------------------------------------------------
/RangeBarSample/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
28 |
29 |
--------------------------------------------------------------------------------
/RangeBarSample/src/com/example/rangebarsample/ColorPickerDialog.java:
--------------------------------------------------------------------------------
1 |
2 | package com.example.rangebarsample;
3 |
4 | import android.app.Dialog;
5 | import android.content.Context;
6 | import android.graphics.Canvas;
7 | import android.graphics.Color;
8 | import android.graphics.LinearGradient;
9 | import android.graphics.Paint;
10 | import android.graphics.Shader;
11 | import android.os.Bundle;
12 | import android.view.MotionEvent;
13 | import android.view.View;
14 |
15 | /**
16 | * Creates a color picker dialog to be used to select a color to be returned.
17 | * Code originates from
18 | * http://www.yougli.net/android/a-photoshop-like-color-picker
19 | * -for-your-android-application/ and is open source and available for
20 | * developers to modify and distribute.
21 | *
22 | * @author www.youglie.net
23 | */
24 | public class ColorPickerDialog extends Dialog {
25 | public interface OnColorChangedListener {
26 | void colorChanged(Component component, int color);
27 | }
28 |
29 | private OnColorChangedListener mListener;
30 | private int mInitialColor, mDefaultColor;
31 | private static Component mComponent;
32 |
33 | private static class ColorPickerView extends View {
34 | private Paint mPaint;
35 | private float mCurrentHue = 0;
36 | private int mCurrentX = 0, mCurrentY = 0;
37 | private int mCurrentColor, mDefaultColor;
38 | private final int[] mHueBarColors = new int[258];
39 | private int[] mMainColors = new int[65536];
40 | private OnColorChangedListener mListener;
41 |
42 | ColorPickerView(Context c, OnColorChangedListener l, int color, int defaultColor) {
43 | super(c);
44 | mListener = l;
45 | mDefaultColor = defaultColor;
46 |
47 | // Get the current hue from the current color and update the main
48 | // color field
49 | float[] hsv = new float[3];
50 | Color.colorToHSV(color, hsv);
51 | mCurrentHue = hsv[0];
52 | updateMainColors();
53 |
54 | mCurrentColor = color;
55 |
56 | // Initialize the colors of the hue slider bar
57 | int index = 0;
58 | for (float i = 0; i < 256; i += 256 / 42) // Red (#f00) to pink
59 | // (#f0f)
60 | {
61 | mHueBarColors[index] = Color.rgb(255, 0, (int) i);
62 | index++;
63 | }
64 | for (float i = 0; i < 256; i += 256 / 42) // Pink (#f0f) to blue
65 | // (#00f)
66 | {
67 | mHueBarColors[index] = Color.rgb(255 - (int) i, 0, 255);
68 | index++;
69 | }
70 | for (float i = 0; i < 256; i += 256 / 42) // Blue (#00f) to light
71 | // blue (#0ff)
72 | {
73 | mHueBarColors[index] = Color.rgb(0, (int) i, 255);
74 | index++;
75 | }
76 | for (float i = 0; i < 256; i += 256 / 42) // Light blue (#0ff) to
77 | // green (#0f0)
78 | {
79 | mHueBarColors[index] = Color.rgb(0, 255, 255 - (int) i);
80 | index++;
81 | }
82 | for (float i = 0; i < 256; i += 256 / 42) // Green (#0f0) to yellow
83 | // (#ff0)
84 | {
85 | mHueBarColors[index] = Color.rgb((int) i, 255, 0);
86 | index++;
87 | }
88 | for (float i = 0; i < 256; i += 256 / 42) // Yellow (#ff0) to red
89 | // (#f00)
90 | {
91 | mHueBarColors[index] = Color.rgb(255, 255 - (int) i, 0);
92 | index++;
93 | }
94 |
95 | // Initializes the Paint that will draw the View
96 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
97 | mPaint.setTextAlign(Paint.Align.CENTER);
98 | mPaint.setTextSize(12);
99 | }
100 |
101 | // Get the current selected color from the hue bar
102 | private int getCurrentMainColor()
103 | {
104 | int translatedHue = 255 - (int) (mCurrentHue * 255 / 360);
105 | int index = 0;
106 | for (float i = 0; i < 256; i += 256 / 42)
107 | {
108 | if (index == translatedHue)
109 | return Color.rgb(255, 0, (int) i);
110 | index++;
111 | }
112 | for (float i = 0; i < 256; i += 256 / 42)
113 | {
114 | if (index == translatedHue)
115 | return Color.rgb(255 - (int) i, 0, 255);
116 | index++;
117 | }
118 | for (float i = 0; i < 256; i += 256 / 42)
119 | {
120 | if (index == translatedHue)
121 | return Color.rgb(0, (int) i, 255);
122 | index++;
123 | }
124 | for (float i = 0; i < 256; i += 256 / 42)
125 | {
126 | if (index == translatedHue)
127 | return Color.rgb(0, 255, 255 - (int) i);
128 | index++;
129 | }
130 | for (float i = 0; i < 256; i += 256 / 42)
131 | {
132 | if (index == translatedHue)
133 | return Color.rgb((int) i, 255, 0);
134 | index++;
135 | }
136 | for (float i = 0; i < 256; i += 256 / 42)
137 | {
138 | if (index == translatedHue)
139 | return Color.rgb(255, 255 - (int) i, 0);
140 | index++;
141 | }
142 | return Color.RED;
143 | }
144 |
145 | // Update the main field colors depending on the current selected hue
146 | private void updateMainColors()
147 | {
148 | int mainColor = getCurrentMainColor();
149 | int index = 0;
150 | int[] topColors = new int[256];
151 | for (int y = 0; y < 256; y++)
152 | {
153 | for (int x = 0; x < 256; x++)
154 | {
155 | if (y == 0)
156 | {
157 | mMainColors[index] = Color.rgb(255 - (255 - Color.red(mainColor)) * x / 255,
158 | 255 - (255 - Color.green(mainColor)) * x / 255,
159 | 255 - (255 - Color.blue(mainColor)) * x / 255);
160 | topColors[x] = mMainColors[index];
161 | }
162 | else
163 | mMainColors[index] = Color.rgb((255 - y) * Color.red(topColors[x]) / 255,
164 | (255 - y) * Color.green(topColors[x]) / 255,
165 | (255 - y) * Color.blue(topColors[x]) / 255);
166 | index++;
167 | }
168 | }
169 | }
170 |
171 | @Override
172 | protected void onDraw(Canvas canvas) {
173 | int translatedHue = 255 - (int) (mCurrentHue * 255 / 360);
174 | // Display all the colors of the hue bar with lines
175 | for (int x = 0; x < 256; x++)
176 | {
177 | // If this is not the current selected hue, display the actual
178 | // color
179 | if (translatedHue != x)
180 | {
181 | mPaint.setColor(mHueBarColors[x]);
182 | mPaint.setStrokeWidth(1);
183 | }
184 | else // else display a slightly larger black line
185 | {
186 | mPaint.setColor(Color.BLACK);
187 | mPaint.setStrokeWidth(3);
188 | }
189 | canvas.drawLine(x + 10, 0, x + 10, 40, mPaint);
190 | }
191 |
192 | // Display the main field colors using LinearGradient
193 | for (int x = 0; x < 256; x++)
194 | {
195 | int[] colors = new int[2];
196 | colors[0] = mMainColors[x];
197 | colors[1] = Color.BLACK;
198 | Shader shader = new LinearGradient(0, 50, 0, 306, colors, null, Shader.TileMode.REPEAT);
199 | mPaint.setShader(shader);
200 | canvas.drawLine(x + 10, 50, x + 10, 306, mPaint);
201 | }
202 | mPaint.setShader(null);
203 |
204 | // Display the circle around the currently selected color in the
205 | // main field
206 | if (mCurrentX != 0 && mCurrentY != 0)
207 | {
208 | mPaint.setStyle(Paint.Style.STROKE);
209 | mPaint.setColor(Color.BLACK);
210 | canvas.drawCircle(mCurrentX, mCurrentY, 10, mPaint);
211 | }
212 |
213 | // Draw a 'button' with the currently selected color
214 | mPaint.setStyle(Paint.Style.FILL);
215 | mPaint.setColor(mCurrentColor);
216 | canvas.drawRect(10, 316, 138, 356, mPaint);
217 |
218 | // Set the text color according to the brightness of the color
219 | if (Color.red(mCurrentColor) + Color.green(mCurrentColor) + Color.blue(mCurrentColor) < 384)
220 | mPaint.setColor(Color.WHITE);
221 | else
222 | mPaint.setColor(Color.BLACK);
223 | canvas.drawText(getResources().getString(R.string.confirmNewColor), 74, 340, mPaint);
224 |
225 | // Draw a 'button' with the default color
226 | mPaint.setStyle(Paint.Style.FILL);
227 | mPaint.setColor(mDefaultColor);
228 | canvas.drawRect(138, 316, 266, 356, mPaint);
229 |
230 | // Set the text color according to the brightness of the color
231 | if (Color.red(mDefaultColor) + Color.green(mDefaultColor) + Color.blue(mDefaultColor) < 384)
232 | mPaint.setColor(Color.WHITE);
233 | else
234 | mPaint.setColor(Color.BLACK);
235 | canvas.drawText(getResources().getString(R.string.confirmDefaultColor), 202, 340, mPaint);
236 | }
237 |
238 | @Override
239 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
240 | setMeasuredDimension(276, 366);
241 | }
242 |
243 | @Override
244 | public boolean onTouchEvent(MotionEvent event) {
245 | if (event.getAction() != MotionEvent.ACTION_DOWN)
246 | return true;
247 | float x = event.getX();
248 | float y = event.getY();
249 |
250 | // If the touch event is located in the hue bar
251 | if (x > 10 && x < 266 && y > 0 && y < 40)
252 | {
253 | // Update the main field colors
254 | mCurrentHue = (255 - x) * 360 / 255;
255 | updateMainColors();
256 |
257 | // Update the current selected color
258 | int transX = mCurrentX - 10;
259 | int transY = mCurrentY - 60;
260 | int index = 256 * (transY - 1) + transX;
261 | if (index > 0 && index < mMainColors.length)
262 | mCurrentColor = mMainColors[256 * (transY - 1) + transX];
263 |
264 | // Force the redraw of the dialog
265 | invalidate();
266 | }
267 |
268 | // If the touch event is located in the main field
269 | if (x > 10 && x < 266 && y > 50 && y < 306)
270 | {
271 | mCurrentX = (int) x;
272 | mCurrentY = (int) y;
273 | int transX = mCurrentX - 10;
274 | int transY = mCurrentY - 60;
275 | int index = 256 * (transY - 1) + transX;
276 | if (index > 0 && index < mMainColors.length)
277 | {
278 | // Update the current color
279 | mCurrentColor = mMainColors[index];
280 | // Force the redraw of the dialog
281 | invalidate();
282 | }
283 | }
284 |
285 | // If the touch event is located in the left button, notify the
286 | // listener with the current color
287 | if (x > 10 && x < 138 && y > 316 && y < 356)
288 | mListener.colorChanged(mComponent, mCurrentColor);
289 |
290 | // If the touch event is located in the right button, notify the
291 | // listener with the default color
292 | if (x > 138 && x < 266 && y > 316 && y < 356)
293 | mListener.colorChanged(mComponent, mDefaultColor);
294 |
295 | return true;
296 | }
297 | }
298 |
299 | public ColorPickerDialog(Context context,
300 | OnColorChangedListener listener,
301 | Component component,
302 | int initialColor,
303 | int defaultColor) {
304 | super(context);
305 |
306 | mListener = listener;
307 | mComponent = component;
308 | mInitialColor = initialColor;
309 | mDefaultColor = defaultColor;
310 | }
311 |
312 | @Override
313 | protected void onCreate(Bundle savedInstanceState) {
314 | super.onCreate(savedInstanceState);
315 | OnColorChangedListener l = new OnColorChangedListener() {
316 | public void colorChanged(Component component, int color) {
317 | mListener.colorChanged(component, color);
318 | dismiss();
319 | }
320 | };
321 |
322 | setContentView(new ColorPickerView(getContext(), l, mInitialColor, mDefaultColor));
323 | setTitle(R.string.colorPickerTitle);
324 | }
325 | }
326 |
--------------------------------------------------------------------------------
/RangeBarSample/src/com/example/rangebarsample/Component.java:
--------------------------------------------------------------------------------
1 |
2 | package com.example.rangebarsample;
3 |
4 | /**
5 | * Enumeration of the components to be changed in colorChanged. Only needed for
6 | * the RangeBar Sample Activity, not for the library project RangeBar itself.
7 | *
8 | * @author deric
9 | */
10 | public enum Component {
11 | BAR_COLOR, CONNECTING_LINE_COLOR, THUMB_COLOR_NORMAL, THUMB_COLOR_PRESSED,
12 | }
13 |
--------------------------------------------------------------------------------
/RangeBarSample/src/com/example/rangebarsample/MainActivity.java:
--------------------------------------------------------------------------------
1 |
2 | package com.example.rangebarsample;
3 |
4 | import android.app.Activity;
5 | import android.graphics.Typeface;
6 | import android.os.Bundle;
7 | import android.view.Gravity;
8 | import android.view.Menu;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.view.ViewGroup.LayoutParams;
12 | import android.view.Window;
13 | import android.widget.Button;
14 | import android.widget.EditText;
15 | import android.widget.SeekBar;
16 | import android.widget.SeekBar.OnSeekBarChangeListener;
17 | import android.widget.TextView;
18 |
19 | import com.edmodo.rangebar.RangeBar;
20 |
21 | public class MainActivity extends Activity implements ColorPickerDialog.OnColorChangedListener {
22 |
23 | // Corresponds to Color.LTGRAY
24 | private static final int DEFAULT_BAR_COLOR = 0xffcccccc;
25 |
26 | // Corresponds to android.R.color.holo_blue_light.
27 | private static final int DEFAULT_CONNECTING_LINE_COLOR = 0xff33b5e5;
28 | private static final int HOLO_BLUE = 0xff33b5e5;
29 |
30 | // Sets the initial values such that the image will be drawn
31 | private static final int DEFAULT_THUMB_COLOR_NORMAL = -1;
32 | private static final int DEFAULT_THUMB_COLOR_PRESSED = -1;
33 |
34 | // Sets variables to save the colors of each attribute
35 | private int mBarColor = DEFAULT_BAR_COLOR;
36 | private int mConnectingLineColor = DEFAULT_CONNECTING_LINE_COLOR;
37 | private int mThumbColorNormal = DEFAULT_THUMB_COLOR_NORMAL;
38 | private int mThumbColorPressed = DEFAULT_THUMB_COLOR_PRESSED;
39 |
40 | // Initializes the RangeBar in the application
41 | private RangeBar rangebar;
42 |
43 | // Saves the state upon rotating the screen/restarting the activity
44 | @Override
45 | protected void onSaveInstanceState(Bundle bundle) {
46 | super.onSaveInstanceState(bundle);
47 | bundle.putInt("BAR_COLOR", mBarColor);
48 | bundle.putInt("CONNECTING_LINE_COLOR", mConnectingLineColor);
49 | bundle.putInt("THUMB_COLOR_NORMAL", mThumbColorNormal);
50 | bundle.putInt("THUMB_COLOR_PRESSED", mThumbColorPressed);
51 | }
52 |
53 | // Restores the state upon rotating the screen/restarting the activity
54 | @Override
55 | protected void onRestoreInstanceState(Bundle bundle) {
56 | super.onRestoreInstanceState(bundle);
57 | mBarColor = bundle.getInt("BAR_COLOR");
58 | mConnectingLineColor = bundle.getInt("CONNECTING_LINE_COLOR");
59 | mThumbColorNormal = bundle.getInt("THUMB_COLOR_NORMAL");
60 | mThumbColorPressed = bundle.getInt("THUMB_COLOR_PRESSED");
61 |
62 | // Change the text colors to the appropriate colors, and the text as
63 | // well
64 | colorChanged(Component.BAR_COLOR, mBarColor);
65 | colorChanged(Component.CONNECTING_LINE_COLOR, mConnectingLineColor);
66 | colorChanged(Component.THUMB_COLOR_NORMAL, mThumbColorNormal);
67 | colorChanged(Component.THUMB_COLOR_PRESSED, mThumbColorPressed);
68 |
69 | // Gets the RangeBar
70 | rangebar = (RangeBar) findViewById(R.id.rangebar1);
71 |
72 | // Gets the index value TextViews
73 | final TextView leftIndexValue = (TextView) findViewById(R.id.leftIndexValue);
74 | final TextView rightIndexValue = (TextView) findViewById(R.id.rightIndexValue);
75 | // Resets the index values every time the activity is changed
76 | leftIndexValue.setText("" + rangebar.getLeftIndex());
77 | rightIndexValue.setText("" + rangebar.getRightIndex());
78 |
79 | // Sets focus to the main layout, not the index text fields
80 | findViewById(R.id.mylayout).requestFocus();
81 |
82 | }
83 |
84 | @Override
85 | protected void onCreate(Bundle savedInstanceState) {
86 | super.onCreate(savedInstanceState);
87 |
88 | // Removes title bar and sets content view
89 | this.requestWindowFeature(Window.FEATURE_NO_TITLE);
90 | setContentView(R.layout.activity_main);
91 |
92 | // Sets fonts for all
93 | Typeface font = Typeface.createFromAsset(getAssets(), "Roboto-Thin.ttf");
94 | ViewGroup root = (ViewGroup) findViewById(R.id.mylayout);
95 | setFont(root, font);
96 |
97 | // Gets the buttons references for the buttons
98 | final Button barColor = (Button) findViewById(R.id.barColor);
99 | final Button connectingLineColor = (Button) findViewById(R.id.connectingLineColor);
100 | final Button thumbColorNormal = (Button) findViewById(R.id.thumbColorNormal);
101 | final Button thumbColorPressed = (Button) findViewById(R.id.thumbColorPressed);
102 | final Button resetThumbColors = (Button) findViewById(R.id.resetThumbColors);
103 | final Button refreshButton = (Button) findViewById(R.id.refresh);
104 |
105 | //Sets the buttons to bold.
106 | refreshButton.setTypeface(font,Typeface.BOLD);
107 | barColor.setTypeface(font,Typeface.BOLD);
108 | connectingLineColor.setTypeface(font,Typeface.BOLD);
109 | thumbColorNormal.setTypeface(font,Typeface.BOLD);
110 | thumbColorPressed.setTypeface(font,Typeface.BOLD);
111 | resetThumbColors.setTypeface(font,Typeface.BOLD);
112 |
113 | // Sets initial colors for the Color buttons
114 | barColor.setTextColor(DEFAULT_BAR_COLOR);
115 | connectingLineColor.setTextColor(DEFAULT_CONNECTING_LINE_COLOR);
116 | thumbColorNormal.setTextColor(HOLO_BLUE);
117 | thumbColorPressed.setTextColor(HOLO_BLUE);
118 |
119 | // Gets the RangeBar
120 | rangebar = (RangeBar) findViewById(R.id.rangebar1);
121 |
122 | // Setting Index Values -------------------------------
123 |
124 | // Gets the index value TextViews
125 | final EditText leftIndexValue = (EditText) findViewById(R.id.leftIndexValue);
126 | final EditText rightIndexValue = (EditText) findViewById(R.id.rightIndexValue);
127 |
128 | // Sets the display values of the indices
129 | rangebar.setOnRangeBarChangeListener(new RangeBar.OnRangeBarChangeListener() {
130 | @Override
131 | public void onIndexChangeListener(RangeBar rangeBar, int leftThumbIndex, int rightThumbIndex) {
132 |
133 | leftIndexValue.setText("" + leftThumbIndex);
134 | rightIndexValue.setText("" + rightThumbIndex);
135 | }
136 | });
137 |
138 | // Sets the indices themselves upon input from the user
139 | refreshButton.setOnClickListener(new View.OnClickListener() {
140 | public void onClick(View v) {
141 |
142 | // Gets the String values of all the texts
143 | String leftIndex = leftIndexValue.getText().toString();
144 | String rightIndex = rightIndexValue.getText().toString();
145 |
146 | // Catches any IllegalArgumentExceptions; if fails, should throw
147 | // a dialog warning the user
148 | try {
149 | if (!leftIndex.isEmpty() && !rightIndex.isEmpty())
150 | {
151 | int leftIntIndex = Integer.parseInt(leftIndex);
152 | int rightIntIndex = Integer.parseInt(rightIndex);
153 | rangebar.setThumbIndices(leftIntIndex, rightIntIndex);
154 | }
155 | } catch (IllegalArgumentException e) {
156 | }
157 | }
158 | });
159 |
160 | // Setting Number Attributes -------------------------------
161 |
162 | // Sets tickCount
163 | final TextView tickCount = (TextView) findViewById(R.id.tickCount);
164 | SeekBar tickCountSeek = (SeekBar) findViewById(R.id.tickCountSeek);
165 | tickCountSeek.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
166 | @Override
167 | public void onProgressChanged(SeekBar tickCountSeek, int progress, boolean fromUser) {
168 | try {
169 | rangebar.setTickCount(progress);
170 | } catch (IllegalArgumentException e) {
171 | }
172 | tickCount.setText("tickCount = " + progress);
173 | }
174 |
175 | @Override
176 | public void onStartTrackingTouch(SeekBar seekBar) {
177 | }
178 |
179 | @Override
180 | public void onStopTrackingTouch(SeekBar seekBar) {
181 | }
182 | });
183 |
184 | // Sets tickHeight
185 | final TextView tickHeight = (TextView) findViewById(R.id.tickHeight);
186 | SeekBar tickHeightSeek = (SeekBar) findViewById(R.id.tickHeightSeek);
187 | tickHeightSeek.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
188 | @Override
189 | public void onProgressChanged(SeekBar tickHeightSeek, int progress, boolean fromUser) {
190 | rangebar.setTickHeight(progress);
191 | tickHeight.setText("tickHeight = " + progress);
192 | }
193 |
194 | @Override
195 | public void onStartTrackingTouch(SeekBar seekBar) {
196 | }
197 |
198 | @Override
199 | public void onStopTrackingTouch(SeekBar seekBar) {
200 | }
201 | });
202 |
203 | // Sets barWeight
204 | final TextView barWeight = (TextView) findViewById(R.id.barWeight);
205 | SeekBar barWeightSeek = (SeekBar) findViewById(R.id.barWeightSeek);
206 | barWeightSeek.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
207 |
208 | @Override
209 | public void onProgressChanged(SeekBar barWeightSeek, int progress, boolean fromUser) {
210 | rangebar.setBarWeight(progress);
211 | barWeight.setText("barWeight = " + progress);
212 | }
213 |
214 | @Override
215 | public void onStartTrackingTouch(SeekBar seekBar) {
216 | }
217 |
218 | @Override
219 | public void onStopTrackingTouch(SeekBar seekBar) {
220 | }
221 | });
222 |
223 | // Sets connectingLineWeight
224 | final TextView connectingLineWeight = (TextView) findViewById(R.id.connectingLineWeight);
225 | SeekBar connectingLineWeightSeek = (SeekBar) findViewById(R.id.connectingLineWeightSeek);
226 | connectingLineWeightSeek.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
227 | @Override
228 | public void onProgressChanged(SeekBar connectingLineWeightSeek, int progress, boolean fromUser) {
229 | rangebar.setConnectingLineWeight(progress);
230 | connectingLineWeight.setText("connectingLineWeight = " + progress);
231 | }
232 |
233 | @Override
234 | public void onStartTrackingTouch(SeekBar seekBar) {
235 | }
236 |
237 | @Override
238 | public void onStopTrackingTouch(SeekBar seekBar) {
239 | }
240 | });
241 |
242 | // Sets thumbRadius
243 | final TextView thumbRadius = (TextView) findViewById(R.id.thumbRadius);
244 | SeekBar thumbRadiusSeek = (SeekBar) findViewById(R.id.thumbRadiusSeek);
245 | thumbRadiusSeek.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
246 | @Override
247 | public void onProgressChanged(SeekBar thumbRadiusSeek, int progress, boolean fromUser) {
248 | if (progress == 0) {
249 | rangebar.setThumbRadius(-1);
250 | thumbRadius.setText("thumbRadius = N/A");
251 | }
252 | else {
253 | rangebar.setThumbRadius(progress);
254 | thumbRadius.setText("thumbRadius = " + progress);
255 | }
256 | }
257 |
258 | @Override
259 | public void onStartTrackingTouch(SeekBar seekBar) {
260 | }
261 |
262 | @Override
263 | public void onStopTrackingTouch(SeekBar seekBar) {
264 | }
265 | });
266 |
267 | // Setting Color Attributes---------------------------------
268 |
269 | // Sets barColor
270 | barColor.setOnClickListener(new View.OnClickListener() {
271 | public void onClick(View v) {
272 | initColorPicker(Component.BAR_COLOR, mBarColor, mBarColor);
273 | }
274 | });
275 |
276 | // Sets connectingLineColor
277 | connectingLineColor.setOnClickListener(new View.OnClickListener() {
278 | public void onClick(View v) {
279 | initColorPicker(Component.CONNECTING_LINE_COLOR, mConnectingLineColor, mConnectingLineColor);
280 | }
281 | });
282 |
283 | // Sets thumbColorNormal
284 | thumbColorNormal.setOnClickListener(new View.OnClickListener() {
285 | public void onClick(View v) {
286 | initColorPicker(Component.THUMB_COLOR_NORMAL, mThumbColorNormal, mThumbColorNormal);
287 | }
288 | });
289 |
290 | // Sets thumbColorPressed
291 | thumbColorPressed.setOnClickListener(new View.OnClickListener() {
292 | public void onClick(View v) {
293 | initColorPicker(Component.THUMB_COLOR_PRESSED, mThumbColorPressed, mThumbColorPressed);
294 | }
295 | });
296 |
297 | // Resets the thumbColors if selected
298 | resetThumbColors.setOnClickListener(new View.OnClickListener() {
299 | public void onClick(View v) {
300 |
301 | rangebar.setThumbColorNormal(-1);
302 | rangebar.setThumbColorPressed(-1);
303 |
304 | mThumbColorNormal = -1;
305 | mThumbColorPressed = -1;
306 |
307 | thumbColorNormal.setText("thumbColorNormal = N/A");
308 | thumbColorPressed.setText("thumbColorPressed = N/A");
309 | thumbColorNormal.setTextColor(HOLO_BLUE);
310 | thumbColorPressed.setTextColor(HOLO_BLUE);
311 | }
312 | });
313 |
314 | }
315 |
316 | /**
317 | * Sets the changed color using the ColorPickerDialog.
318 | *
319 | * @param component Component specifying which input is being used
320 | * @param newColor Integer specifying the new color to be selected.
321 | */
322 | @Override
323 | public void colorChanged(Component component, int newColor) {
324 |
325 | String hexColor = String.format("#%06X", (0xFFFFFF & newColor));
326 |
327 | switch (component)
328 | {
329 | case BAR_COLOR:
330 | mBarColor = newColor;
331 | rangebar.setBarColor(newColor);
332 | final TextView barColorText = (TextView) findViewById(R.id.barColor);
333 | barColorText.setText("barColor = " + hexColor);
334 | barColorText.setTextColor(newColor);
335 | break;
336 |
337 | case CONNECTING_LINE_COLOR:
338 | mConnectingLineColor = newColor;
339 | rangebar.setConnectingLineColor(newColor);
340 | final TextView connectingLineColorText = (TextView) findViewById(R.id.connectingLineColor);
341 | connectingLineColorText.setText("connectingLineColor = " + hexColor);
342 | connectingLineColorText.setTextColor(newColor);
343 | break;
344 |
345 | case THUMB_COLOR_NORMAL:
346 | mThumbColorNormal = newColor;
347 | rangebar.setThumbColorNormal(newColor);
348 | final TextView thumbColorNormalText = (TextView) findViewById(R.id.thumbColorNormal);
349 |
350 | if (newColor == -1) {
351 | thumbColorNormalText.setText("thumbColorNormal = N/A");
352 | thumbColorNormalText.setTextColor(HOLO_BLUE);
353 | }
354 | else {
355 | thumbColorNormalText.setText("thumbColorNormal = " + hexColor);
356 | thumbColorNormalText.setTextColor(newColor);
357 | }
358 | break;
359 |
360 | case THUMB_COLOR_PRESSED:
361 | mThumbColorPressed = newColor;
362 | rangebar.setThumbColorPressed(newColor);
363 | final TextView thumbColorPressedText = (TextView) findViewById(R.id.thumbColorPressed);
364 |
365 | if (newColor == -1) {
366 | thumbColorPressedText.setText("thumbColorPressed = N/A");
367 | thumbColorPressedText.setTextColor(HOLO_BLUE);
368 | }
369 | else {
370 | thumbColorPressedText.setText("thumbColorPressed = " + hexColor);
371 | thumbColorPressedText.setTextColor(newColor);
372 | }
373 | }
374 | }
375 |
376 | /**
377 | * Sets the font on all TextViews in the ViewGroup. Searches recursively for
378 | * all inner ViewGroups as well. Just add a check for any other views you
379 | * want to set as well (EditText, etc.)
380 | */
381 | private void setFont(ViewGroup group, Typeface font) {
382 | int count = group.getChildCount();
383 | View v;
384 | for (int i = 0; i < count; i++) {
385 | v = group.getChildAt(i);
386 | if (v instanceof TextView || v instanceof EditText || v instanceof Button) {
387 | ((TextView) v).setTypeface(font);
388 | } else if (v instanceof ViewGroup)
389 | setFont((ViewGroup) v, font);
390 | }
391 | }
392 |
393 | @Override
394 | public boolean onCreateOptionsMenu(Menu menu) {
395 | // Inflate the menu; this adds items to the action bar if it is present.
396 | getMenuInflater().inflate(R.menu.main, menu);
397 | return true;
398 | }
399 |
400 | /**
401 | * Initiates the colorPicker from within a button function.
402 | *
403 | * @param component Component specifying which input is being used
404 | * @param initialColor Integer specifying the initial color choice. *
405 | * @param defaultColor Integer specifying the default color choice.
406 | */
407 | private void initColorPicker(Component component, int initialColor, int defaultColor)
408 | {
409 | ColorPickerDialog colorPicker = new ColorPickerDialog(this,
410 | this,
411 | component,
412 | initialColor,
413 | defaultColor);
414 | colorPicker.show();
415 |
416 | }
417 |
418 | }
419 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 |
3 | repositories {
4 | mavenCentral()
5 | }
6 | dependencies {
7 | // Plug-in release notes: http://tools.android.com/tech-docs/new-build-system
8 | classpath 'com.android.tools.build:gradle:2.1.3'
9 | }
10 | }
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devlight/AnimatedRangeBar/0087f967911fa2cf3eafc298d8bb645a0c3c234f/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Sep 19 15:56:33 EEST 2016
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-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/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 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
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 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/rangebar/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/rangebar/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # built application files
3 | *.apk
4 | *.ap_
5 |
6 | # files for the dex VM
7 | *.dex
8 |
9 | # Java class files
10 | *.class
11 |
12 | # generated files
13 | bin/
14 | gen/
15 | out/
16 |
17 | # Local configuration file (sdk path, etc)
18 | local.properties
19 |
20 | # Mac OS X internal files
21 | .DS_Store
22 |
23 | # Eclipse generated files/folders
24 | .metadata/
25 | .settings/
26 |
27 | #IntelliJ IDEA
28 | .idea
29 | *.iml
30 | *.ipr
31 | *.iws
32 | out
33 |
34 | # Gradle folder
35 | .gradle/
36 | build/
--------------------------------------------------------------------------------
/rangebar/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | RangeBar
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/rangebar/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/rangebar/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'android-library'
2 | apply plugin: 'maven'
3 | apply plugin: 'signing'
4 |
5 | version = "1.0.0"
6 | group = "com.edmodo"
7 |
8 | android {
9 |
10 | compileSdkVersion 19
11 | buildToolsVersion "19.1"
12 |
13 | defaultConfig {
14 | minSdkVersion 7
15 | targetSdkVersion 19
16 | }
17 |
18 | sourceSets {
19 | main {
20 | manifest.srcFile 'AndroidManifest.xml'
21 | java.srcDirs = ['src']
22 | res.srcDirs = ['res']
23 | }
24 | }
25 | }
26 |
27 | repositories {
28 | mavenCentral()
29 | }
30 |
31 | signing {
32 | required { has("release") && gradle.taskGraph.hasTask("uploadArchives") }
33 | sign configurations.archives
34 | }
35 |
36 | task publishLocal(type: Upload) {
37 | configuration = configurations.archives
38 | repositories.mavenDeployer {
39 | repository(url: "file://$buildDir/repo")
40 | }
41 | }
--------------------------------------------------------------------------------
/rangebar/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/rangebar/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-19
15 | android.library=true
16 |
--------------------------------------------------------------------------------
/rangebar/res/drawable-xhdpi/seek_thumb_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devlight/AnimatedRangeBar/0087f967911fa2cf3eafc298d8bb645a0c3c234f/rangebar/res/drawable-xhdpi/seek_thumb_normal.png
--------------------------------------------------------------------------------
/rangebar/res/drawable-xhdpi/seek_thumb_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devlight/AnimatedRangeBar/0087f967911fa2cf3eafc298d8bb645a0c3c234f/rangebar/res/drawable-xhdpi/seek_thumb_pressed.png
--------------------------------------------------------------------------------
/rangebar/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/rangebar/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/rangebar/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/rangebar/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | RangeBar
4 |
5 |
--------------------------------------------------------------------------------
/rangebar/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
--------------------------------------------------------------------------------
/rangebar/src/com/edmodo/rangebar/Bar.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013, Edmodo, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License.
5 | * You may obtain a copy of the License in the LICENSE file, or at:
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
10 | * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
11 | * governing permissions and limitations under the License.
12 | */
13 |
14 | package com.edmodo.rangebar;
15 |
16 | import android.content.Context;
17 | import android.graphics.Canvas;
18 | import android.graphics.Paint;
19 | import android.util.TypedValue;
20 |
21 | /**
22 | * This class represents the underlying gray bar in the RangeBar (without the
23 | * thumbs).
24 | */
25 | class Bar {
26 |
27 | // Member Variables ////////////////////////////////////////////////////////
28 |
29 | private final Paint mPaint;
30 |
31 | // Left-coordinate of the horizontal bar.
32 | private final float mLeftX;
33 | private final float mRightX;
34 | private final float mY;
35 |
36 | private int mNumSegments;
37 | private float mTickDistance;
38 | private final float mTickHeight;
39 | private final float mTickStartY;
40 | private final float mTickEndY;
41 |
42 | // Constructor /////////////////////////////////////////////////////////////
43 |
44 | Bar(Context ctx,
45 | float x,
46 | float y,
47 | float length,
48 | int tickCount,
49 | float tickHeightDP,
50 | float BarWeight,
51 | int BarColor) {
52 |
53 | mLeftX = x;
54 | mRightX = x + length;
55 | mY = y;
56 |
57 | mNumSegments = tickCount - 1;
58 | mTickDistance = length / mNumSegments;
59 | mTickHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
60 | tickHeightDP,
61 | ctx.getResources().getDisplayMetrics());
62 | mTickStartY = mY - mTickHeight / 2f;
63 | mTickEndY = mY + mTickHeight / 2f;
64 |
65 | // Initialize the paint.
66 | mPaint = new Paint();
67 | mPaint.setColor(BarColor);
68 | mPaint.setStrokeWidth(BarWeight);
69 | mPaint.setAntiAlias(true);
70 | }
71 |
72 | // Package-Private Methods /////////////////////////////////////////////////
73 |
74 | /**
75 | * Draws the bar on the given Canvas.
76 | *
77 | * @param canvas Canvas to draw on; should be the Canvas passed into {#link
78 | * View#onDraw()}
79 | */
80 | void draw(Canvas canvas) {
81 |
82 | canvas.drawLine(mLeftX, mY, mRightX, mY, mPaint);
83 |
84 | drawTicks(canvas);
85 | }
86 |
87 | /**
88 | * Get the x-coordinate of the left edge of the bar.
89 | *
90 | * @return x-coordinate of the left edge of the bar
91 | */
92 | float getLeftX() {
93 | return mLeftX;
94 | }
95 |
96 | /**
97 | * Get the x-coordinate of the right edge of the bar.
98 | *
99 | * @return x-coordinate of the right edge of the bar
100 | */
101 | float getRightX() {
102 | return mRightX;
103 | }
104 |
105 | float getNearestTickCoordinate(Thumb thumb) {
106 |
107 | final int nearestTickIndex = getNearestTickIndex(thumb);
108 |
109 | final float nearestTickCoordinate = mLeftX + (nearestTickIndex * mTickDistance);
110 |
111 | return nearestTickCoordinate;
112 | }
113 |
114 | float getNearestTickCoordinate(final float x) {
115 |
116 | final int nearestTickIndex = getNearestTickIndex(x);
117 |
118 | final float nearestTickCoordinate = mLeftX + (nearestTickIndex * mTickDistance);
119 |
120 | return nearestTickCoordinate;
121 | }
122 |
123 |
124 | /**
125 | * Gets the zero-based index of the nearest tick to the given thumb.
126 | *
127 | * @param thumb the Thumb to find the nearest tick for
128 | * @return the zero-based index of the nearest tick
129 | */
130 | int getNearestTickIndex(Thumb thumb) {
131 |
132 | final int nearestTickIndex = (int) ((thumb.getX() - mLeftX + mTickDistance / 2f) / mTickDistance);
133 |
134 | return nearestTickIndex;
135 | }
136 |
137 | int getNearestTickIndex(final float x) {
138 |
139 | final int nearestTickIndex = (int) ((x - mLeftX + mTickDistance / 2f) / mTickDistance);
140 |
141 | return nearestTickIndex;
142 | }
143 |
144 | /**
145 | * Set the number of ticks that will appear in the RangeBar.
146 | *
147 | * @param tickCount the number of ticks
148 | */
149 | void setTickCount(int tickCount) {
150 |
151 | final float barLength = mRightX - mLeftX;
152 |
153 | mNumSegments = tickCount - 1;
154 | mTickDistance = barLength / mNumSegments;
155 | }
156 |
157 | // Private Methods /////////////////////////////////////////////////////////
158 |
159 | /**
160 | * Draws the tick marks on the bar.
161 | *
162 | * @param canvas Canvas to draw on; should be the Canvas passed into {#link
163 | * View#onDraw()}
164 | */
165 | private void drawTicks(Canvas canvas) {
166 |
167 | // Loop through and draw each tick (except final tick).
168 | for (int i = 0; i < mNumSegments; i++) {
169 | final float x = i * mTickDistance + mLeftX;
170 | canvas.drawLine(x, mTickStartY, x, mTickEndY, mPaint);
171 | }
172 | // Draw final tick. We draw the final tick outside the loop to avoid any
173 | // rounding discrepancies.
174 | canvas.drawLine(mRightX, mTickStartY, mRightX, mTickEndY, mPaint);
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/rangebar/src/com/edmodo/rangebar/ConnectingLine.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013, Edmodo, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License.
5 | * You may obtain a copy of the License in the LICENSE file, or at:
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
10 | * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
11 | * governing permissions and limitations under the License.
12 | */
13 |
14 | package com.edmodo.rangebar;
15 |
16 | import android.content.Context;
17 | import android.content.res.Resources;
18 | import android.graphics.Canvas;
19 | import android.graphics.Paint;
20 | import android.util.TypedValue;
21 |
22 | /**
23 | * Class representing the blue connecting line between the two thumbs.
24 | */
25 | class ConnectingLine {
26 |
27 | // Member Variables ////////////////////////////////////////////////////////
28 |
29 | private final Paint mPaint;
30 |
31 | private final float mConnectingLineWeight;
32 | private final float mY;
33 |
34 | // Constructor /////////////////////////////////////////////////////////////
35 |
36 | ConnectingLine(Context ctx, float y, float connectingLineWeight, int connectingLineColor) {
37 |
38 | final Resources res = ctx.getResources();
39 |
40 | mConnectingLineWeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
41 | connectingLineWeight,
42 | res.getDisplayMetrics());
43 |
44 | // Initialize the paint, set values
45 | mPaint = new Paint();
46 | mPaint.setColor(connectingLineColor);
47 | mPaint.setStrokeWidth(mConnectingLineWeight);
48 | mPaint.setAntiAlias(true);
49 |
50 | mY = y;
51 | }
52 |
53 | // Package-Private Methods /////////////////////////////////////////////////
54 |
55 | /**
56 | * Draw the connecting line between the two thumbs.
57 | *
58 | * @param canvas the Canvas to draw to
59 | * @param leftThumb the left thumb
60 | * @param rightThumb the right thumb
61 | */
62 | void draw(Canvas canvas, Thumb leftThumb, Thumb rightThumb) {
63 | canvas.drawLine(leftThumb.getX(), mY, rightThumb.getX(), mY, mPaint);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/rangebar/src/com/edmodo/rangebar/MeasureSpecMode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013, Edmodo, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License.
5 | * You may obtain a copy of the License in the LICENSE file, or at:
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
10 | * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
11 | * governing permissions and limitations under the License.
12 | */
13 |
14 | package com.edmodo.rangebar;
15 |
16 | import android.view.View;
17 |
18 | /**
19 | * Helper enum class for transforming a measureSpec mode integer value into a
20 | * human-readable String. The human-readable String is simply the name of the
21 | * enum value.
22 | */
23 | public enum MeasureSpecMode {
24 |
25 | AT_MOST(View.MeasureSpec.AT_MOST),
26 | EXACTLY(View.MeasureSpec.EXACTLY),
27 | UNSPECIFIED(View.MeasureSpec.UNSPECIFIED);
28 |
29 | // Member Variables ////////////////////////////////////////////////////////
30 |
31 | private final int mModeValue;
32 |
33 | // Constructor /////////////////////////////////////////////////////////////
34 |
35 | private MeasureSpecMode(int modeValue) {
36 | mModeValue = modeValue;
37 | }
38 |
39 | // Public Methods //////////////////////////////////////////////////////////
40 |
41 | /**
42 | * Gets the int value associated with this mode.
43 | *
44 | * @return the int value associated with this mode
45 | */
46 | public int getModeValue() {
47 | return mModeValue;
48 | }
49 |
50 | /**
51 | * Gets the MeasureSpecMode value that corresponds with the given
52 | * measureSpec int value.
53 | *
54 | * @param measureSpec the measure specification passed by the platform to
55 | * {@link View#onMeasure(int, int)}
56 | * @return the MeasureSpecMode that matches with that measure spec
57 | */
58 | public static MeasureSpecMode getMode(int measureSpec) {
59 |
60 | final int modeValue = View.MeasureSpec.getMode(measureSpec);
61 |
62 | for (MeasureSpecMode mode : MeasureSpecMode.values()) {
63 | if (mode.getModeValue() == modeValue) {
64 | return mode;
65 | }
66 | }
67 | return null;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/rangebar/src/com/edmodo/rangebar/RangeBar.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013, Edmodo, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License.
5 | * You may obtain a copy of the License in the LICENSE file, or at:
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
10 | * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
11 | * governing permissions and limitations under the License.
12 | */
13 |
14 | package com.edmodo.rangebar;
15 |
16 | import android.animation.ValueAnimator;
17 | import android.annotation.TargetApi;
18 | import android.content.Context;
19 | import android.content.res.TypedArray;
20 | import android.graphics.Canvas;
21 | import android.graphics.Color;
22 | import android.os.Build;
23 | import android.os.Bundle;
24 | import android.os.Parcelable;
25 | import android.util.AttributeSet;
26 | import android.util.Log;
27 | import android.view.MotionEvent;
28 | import android.view.View;
29 |
30 | /**
31 | * The RangeBar is a double-sided version of a {@link android.widget.SeekBar}
32 | * with discrete values. Whereas the thumb for the SeekBar can be dragged to any
33 | * position in the bar, the RangeBar only allows its thumbs to be dragged to
34 | * discrete positions (denoted by tick marks) in the bar. When released, a
35 | * RangeBar thumb will snap to the nearest tick mark.
36 | *
37 | * Clients of the RangeBar can attach a
38 | * {@link RangeBar#OnRangeBarChangeListener} to be notified when the thumbs have
39 | * been moved.
40 | */
41 | public class RangeBar extends View {
42 |
43 | // Member Variables ////////////////////////////////////////////////////////
44 |
45 | private static final String TAG = "RangeBar";
46 |
47 | // Default values for variables
48 | private static final int DEFAULT_TICK_COUNT = 3;
49 | private static final float DEFAULT_TICK_HEIGHT_DP = 24;
50 | private static final float DEFAULT_BAR_WEIGHT_PX = 2;
51 | private static final int DEFAULT_BAR_COLOR = Color.LTGRAY;
52 | private static final float DEFAULT_CONNECTING_LINE_WEIGHT_PX = 4;
53 | private static final int DEFAULT_THUMB_IMAGE_NORMAL = R.drawable.seek_thumb_normal;
54 | private static final int DEFAULT_THUMB_IMAGE_PRESSED = R.drawable.seek_thumb_pressed;
55 |
56 | // Corresponds to android.R.color.holo_blue_light.
57 | private static final int DEFAULT_CONNECTING_LINE_COLOR = 0xff33b5e5;
58 |
59 | // Indicator value tells Thumb.java whether it should draw the circle or not
60 | private static final float DEFAULT_THUMB_RADIUS_DP = -1;
61 | private static final int DEFAULT_THUMB_COLOR_NORMAL = -1;
62 | private static final int DEFAULT_THUMB_COLOR_PRESSED = -1;
63 |
64 | // Instance variables for all of the customizable attributes
65 | private int mTickCount = DEFAULT_TICK_COUNT;
66 | private float mTickHeightDP = DEFAULT_TICK_HEIGHT_DP;
67 | private float mBarWeight = DEFAULT_BAR_WEIGHT_PX;
68 | private int mBarColor = DEFAULT_BAR_COLOR;
69 | private float mConnectingLineWeight = DEFAULT_CONNECTING_LINE_WEIGHT_PX;
70 | private int mConnectingLineColor = DEFAULT_CONNECTING_LINE_COLOR;
71 | private int mThumbImageNormal = DEFAULT_THUMB_IMAGE_NORMAL;
72 | private int mThumbImagePressed = DEFAULT_THUMB_IMAGE_PRESSED;
73 |
74 | private float mThumbRadiusDP = DEFAULT_THUMB_RADIUS_DP;
75 | private int mThumbColorNormal = DEFAULT_THUMB_COLOR_NORMAL;
76 | private int mThumbColorPressed = DEFAULT_THUMB_COLOR_PRESSED;
77 |
78 | // setTickCount only resets indices before a thumb has been pressed or a
79 | // setThumbIndices() is called, to correspond with intended usage
80 | private boolean mFirstSetTickCount = true;
81 |
82 | private int mDefaultWidth = 500;
83 | private int mDefaultHeight = 100;
84 |
85 | private Thumb mLeftThumb;
86 | private Thumb mRightThumb;
87 | private Bar mBar;
88 | private ConnectingLine mConnectingLine;
89 |
90 | private RangeBar.OnRangeBarChangeListener mListener;
91 | private int mLeftIndex = 0;
92 | private int mRightIndex = mTickCount - 1;
93 |
94 | private boolean mIsThumbAnimate;
95 | private boolean mIsAvailable;
96 |
97 | {
98 | if (mIsAvailable = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
99 | mUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
100 | @Override
101 | public void onAnimationUpdate(final ValueAnimator animation) {
102 | final int newLeftIndex = mBar.getNearestTickIndex(mLeftThumb);
103 | final int newRightIndex = mBar.getNearestTickIndex(mRightThumb);
104 |
105 | // If either of the indices have changed, update and call the listener.
106 | if (newLeftIndex != mLeftIndex || newRightIndex != mRightIndex) {
107 |
108 | mLeftIndex = newLeftIndex;
109 | mRightIndex = newRightIndex;
110 |
111 | if (mListener != null) {
112 | mListener.onIndexChangeListener(RangeBar.this, mLeftIndex, mRightIndex);
113 | }
114 | }
115 | postInvalidate();
116 | }
117 | };
118 | }
119 | }
120 |
121 | private ValueAnimator.AnimatorUpdateListener mUpdateListener;
122 |
123 |
124 | // Constructors ////////////////////////////////////////////////////////////
125 |
126 | public RangeBar(Context context) {
127 | super(context);
128 | }
129 |
130 | public RangeBar(Context context, AttributeSet attrs) {
131 | super(context, attrs);
132 | rangeBarInit(context, attrs);
133 | }
134 |
135 | public RangeBar(Context context, AttributeSet attrs, int defStyle) {
136 | super(context, attrs, defStyle);
137 | rangeBarInit(context, attrs);
138 | }
139 |
140 | // View Methods ////////////////////////////////////////////////////////////
141 |
142 | @Override
143 | public Parcelable onSaveInstanceState() {
144 |
145 | final Bundle bundle = new Bundle();
146 |
147 | bundle.putParcelable("instanceState", super.onSaveInstanceState());
148 |
149 | bundle.putInt("TICK_COUNT", mTickCount);
150 | bundle.putFloat("TICK_HEIGHT_DP", mTickHeightDP);
151 | bundle.putFloat("BAR_WEIGHT", mBarWeight);
152 | bundle.putInt("BAR_COLOR", mBarColor);
153 | bundle.putFloat("CONNECTING_LINE_WEIGHT", mConnectingLineWeight);
154 | bundle.putInt("CONNECTING_LINE_COLOR", mConnectingLineColor);
155 |
156 | bundle.putInt("THUMB_IMAGE_NORMAL", mThumbImageNormal);
157 | bundle.putInt("THUMB_IMAGE_PRESSED", mThumbImagePressed);
158 |
159 | bundle.putFloat("THUMB_RADIUS_DP", mThumbRadiusDP);
160 | bundle.putInt("THUMB_COLOR_NORMAL", mThumbColorNormal);
161 | bundle.putInt("THUMB_COLOR_PRESSED", mThumbColorPressed);
162 |
163 | bundle.putInt("LEFT_INDEX", mLeftIndex);
164 | bundle.putInt("RIGHT_INDEX", mRightIndex);
165 |
166 | bundle.putBoolean("FIRST_SET_TICK_COUNT", mFirstSetTickCount);
167 | bundle.putBoolean("THUMB_ANIMATE", mIsThumbAnimate);
168 | bundle.putBoolean("IS_AVAILABLE", mIsAvailable);
169 |
170 | return bundle;
171 | }
172 |
173 | @Override
174 | public void onRestoreInstanceState(Parcelable state) {
175 |
176 | if (state instanceof Bundle) {
177 |
178 | final Bundle bundle = (Bundle) state;
179 |
180 | mTickCount = bundle.getInt("TICK_COUNT");
181 | mTickHeightDP = bundle.getFloat("TICK_HEIGHT_DP");
182 | mBarWeight = bundle.getFloat("BAR_WEIGHT");
183 | mBarColor = bundle.getInt("BAR_COLOR");
184 | mConnectingLineWeight = bundle.getFloat("CONNECTING_LINE_WEIGHT");
185 | mConnectingLineColor = bundle.getInt("CONNECTING_LINE_COLOR");
186 |
187 | mThumbImageNormal = bundle.getInt("THUMB_IMAGE_NORMAL");
188 | mThumbImagePressed = bundle.getInt("THUMB_IMAGE_PRESSED");
189 |
190 | mThumbRadiusDP = bundle.getFloat("THUMB_RADIUS_DP");
191 | mThumbColorNormal = bundle.getInt("THUMB_COLOR_NORMAL");
192 | mThumbColorPressed = bundle.getInt("THUMB_COLOR_PRESSED");
193 |
194 | mLeftIndex = bundle.getInt("LEFT_INDEX");
195 | mRightIndex = bundle.getInt("RIGHT_INDEX");
196 | mFirstSetTickCount = bundle.getBoolean("FIRST_SET_TICK_COUNT");
197 | mIsThumbAnimate = bundle.getBoolean("THUMB_ANIMATE");
198 | mIsAvailable = bundle.getBoolean("IS_AVAILABLE");
199 |
200 | setThumbIndices(mLeftIndex, mRightIndex);
201 |
202 | super.onRestoreInstanceState(bundle.getParcelable("instanceState"));
203 |
204 | } else {
205 |
206 | super.onRestoreInstanceState(state);
207 | }
208 | }
209 |
210 | @Override
211 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
212 |
213 | int width;
214 | int height;
215 |
216 | // Get measureSpec mode and size values.
217 | final int measureWidthMode = MeasureSpec.getMode(widthMeasureSpec);
218 | final int measureHeightMode = MeasureSpec.getMode(heightMeasureSpec);
219 | final int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
220 | final int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
221 |
222 | // The RangeBar width should be as large as possible.
223 | if (measureWidthMode == MeasureSpec.AT_MOST) {
224 | width = measureWidth;
225 | } else if (measureWidthMode == MeasureSpec.EXACTLY) {
226 | width = measureWidth;
227 | } else {
228 | width = mDefaultWidth;
229 | }
230 |
231 | // The RangeBar height should be as small as possible.
232 | if (measureHeightMode == MeasureSpec.AT_MOST) {
233 | height = Math.min(mDefaultHeight, measureHeight);
234 | } else if (measureHeightMode == MeasureSpec.EXACTLY) {
235 | height = measureHeight;
236 | } else {
237 | height = mDefaultHeight;
238 | }
239 |
240 | setMeasuredDimension(width, height);
241 | }
242 |
243 | @Override
244 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
245 | super.onSizeChanged(w, h, oldw, oldh);
246 | if (isInEditMode())
247 | return;
248 |
249 | final Context ctx = getContext();
250 |
251 | // This is the initial point at which we know the size of the View.
252 |
253 | // Create the two thumb objects.
254 | final float yPos = h / 2f;
255 | mLeftThumb = new Thumb(ctx,
256 | yPos,
257 | mThumbColorNormal,
258 | mThumbColorPressed,
259 | mThumbRadiusDP,
260 | mThumbImageNormal,
261 | mThumbImagePressed,
262 | mUpdateListener);
263 | mRightThumb = new Thumb(ctx,
264 | yPos,
265 | mThumbColorNormal,
266 | mThumbColorPressed,
267 | mThumbRadiusDP,
268 | mThumbImageNormal,
269 | mThumbImagePressed,
270 | mUpdateListener);
271 |
272 | // Create the underlying bar.
273 | final float marginLeft = mLeftThumb.getHalfWidth();
274 | final float barLength = w - 2 * marginLeft;
275 | mBar = new Bar(ctx, marginLeft, yPos, barLength, mTickCount, mTickHeightDP, mBarWeight, mBarColor);
276 |
277 | // Initialize thumbs to the desired indices
278 | mLeftThumb.setX(marginLeft + (mLeftIndex / (float) (mTickCount - 1)) * barLength);
279 | mRightThumb.setX(marginLeft + (mRightIndex / (float) (mTickCount - 1)) * barLength);
280 |
281 | // Set the thumb indices.
282 | final int newLeftIndex = mBar.getNearestTickIndex(mLeftThumb);
283 | final int newRightIndex = mBar.getNearestTickIndex(mRightThumb);
284 |
285 | // Call the listener.
286 | if (newLeftIndex != mLeftIndex || newRightIndex != mRightIndex) {
287 |
288 | mLeftIndex = newLeftIndex;
289 | mRightIndex = newRightIndex;
290 |
291 | if (mListener != null) {
292 | mListener.onIndexChangeListener(this, mLeftIndex, mRightIndex);
293 | }
294 | }
295 |
296 | // Create the line connecting the two thumbs.
297 | mConnectingLine = new ConnectingLine(ctx, yPos, mConnectingLineWeight, mConnectingLineColor);
298 | }
299 |
300 | @Override
301 | protected void onDraw(Canvas canvas) {
302 | super.onDraw(canvas);
303 | if (isInEditMode())
304 | return;
305 |
306 | mBar.draw(canvas);
307 | mConnectingLine.draw(canvas, mLeftThumb, mRightThumb);
308 | mLeftThumb.draw(canvas);
309 | mRightThumb.draw(canvas);
310 |
311 | }
312 |
313 | @Override
314 | public boolean onTouchEvent(MotionEvent event) {
315 |
316 | // If this View is not enabled, don't allow for touch interactions.
317 | if (!isEnabled()) {
318 | return false;
319 | }
320 |
321 | switch (event.getAction()) {
322 |
323 | case MotionEvent.ACTION_DOWN:
324 | onActionDown(event.getX(), event.getY());
325 | return true;
326 |
327 | case MotionEvent.ACTION_UP:
328 | case MotionEvent.ACTION_CANCEL:
329 | this.getParent().requestDisallowInterceptTouchEvent(false);
330 | onActionUp(event.getX(), event.getY());
331 | return true;
332 |
333 | case MotionEvent.ACTION_MOVE:
334 | onActionMove(event.getX());
335 | this.getParent().requestDisallowInterceptTouchEvent(true);
336 | return true;
337 |
338 | default:
339 | return false;
340 | }
341 | }
342 |
343 | // Public Methods //////////////////////////////////////////////////////////
344 |
345 | /**
346 | * Sets a listener to receive notifications of changes to the RangeBar. This
347 | * will overwrite any existing set listeners.
348 | *
349 | * @param listener the RangeBar notification listener; null to remove any
350 | * existing listener
351 | */
352 | public void setOnRangeBarChangeListener(RangeBar.OnRangeBarChangeListener listener) {
353 | mListener = listener;
354 | }
355 |
356 | /**
357 | * Sets the number of ticks in the RangeBar.
358 | *
359 | * @param tickCount Integer specifying the number of ticks.
360 | */
361 | public void setTickCount(int tickCount) {
362 |
363 | if (isValidTickCount(tickCount)) {
364 | mTickCount = tickCount;
365 |
366 | // Prevents resetting the indices when creating new activity, but
367 | // allows it on the first setting.
368 | if (mFirstSetTickCount) {
369 | mLeftIndex = 0;
370 | mRightIndex = mTickCount - 1;
371 |
372 | if (mListener != null) {
373 | mListener.onIndexChangeListener(this, mLeftIndex, mRightIndex);
374 | }
375 | }
376 | if (indexOutOfRange(mLeftIndex, mRightIndex)) {
377 | mLeftIndex = 0;
378 | mRightIndex = mTickCount - 1;
379 |
380 | if (mListener != null)
381 | mListener.onIndexChangeListener(this, mLeftIndex, mRightIndex);
382 | }
383 |
384 | createBar();
385 | createThumbs();
386 | } else {
387 | Log.e(TAG, "tickCount less than 2; invalid tickCount.");
388 | throw new IllegalArgumentException("tickCount less than 2; invalid tickCount.");
389 | }
390 | }
391 |
392 | /**
393 | * Sets the height of the ticks in the range bar.
394 | *
395 | * @param tickHeight Float specifying the height of each tick mark in dp.
396 | */
397 | public void setTickHeight(float tickHeight) {
398 |
399 | mTickHeightDP = tickHeight;
400 | createBar();
401 | }
402 |
403 | /**
404 | * Set the weight of the bar line and the tick lines in the range bar.
405 | *
406 | * @param barWeight Float specifying the weight of the bar and tick lines in
407 | * px.
408 | */
409 | public void setBarWeight(float barWeight) {
410 |
411 | mBarWeight = barWeight;
412 | createBar();
413 | }
414 |
415 | /**
416 | * Set the color of the bar line and the tick lines in the range bar.
417 | *
418 | * @param barColor Integer specifying the color of the bar line.
419 | */
420 | public void setBarColor(int barColor) {
421 |
422 | mBarColor = barColor;
423 | createBar();
424 | }
425 |
426 | /**
427 | * Set the weight of the connecting line between the thumbs.
428 | *
429 | * @param connectingLineWeight Float specifying the weight of the connecting
430 | * line.
431 | */
432 | public void setConnectingLineWeight(float connectingLineWeight) {
433 |
434 | mConnectingLineWeight = connectingLineWeight;
435 | createConnectingLine();
436 | }
437 |
438 | /**
439 | * Set the color of the connecting line between the thumbs.
440 | *
441 | * @param connectingLineColor Integer specifying the color of the connecting
442 | * line.
443 | */
444 | public void setConnectingLineColor(int connectingLineColor) {
445 |
446 | mConnectingLineColor = connectingLineColor;
447 | createConnectingLine();
448 | }
449 |
450 | /**
451 | * If this is set, the thumb images will be replaced with a circle of the
452 | * specified radius. Default width = 20dp.
453 | *
454 | * @param thumbRadius Float specifying the radius of the thumbs to be drawn.
455 | */
456 | public void setThumbRadius(float thumbRadius) {
457 |
458 | mThumbRadiusDP = thumbRadius;
459 | createThumbs();
460 | }
461 |
462 | /**
463 | * Sets the normal thumb picture by taking in a reference ID to an image.
464 | *
465 | * @param thumbNormalID Integer specifying the resource ID of the image to
466 | * be drawn as the normal thumb.
467 | */
468 | public void setThumbImageNormal(int thumbImageNormalID) {
469 | mThumbImageNormal = thumbImageNormalID;
470 | createThumbs();
471 | }
472 |
473 | /**
474 | * Sets the pressed thumb picture by taking in a reference ID to an image.
475 | *
476 | * @param pressedThumbID Integer specifying the resource ID of the image to
477 | * be drawn as the pressed thumb.
478 | */
479 | public void setThumbImagePressed(int thumbImagePressedID) {
480 | mThumbImagePressed = thumbImagePressedID;
481 | createThumbs();
482 | }
483 |
484 | /**
485 | * If this is set, the thumb images will be replaced with a circle. The
486 | * normal image will be of the specified color.
487 | *
488 | * @param thumbColorNormal Integer specifying the normal color of the circle
489 | * to be drawn.
490 | */
491 | public void setThumbColorNormal(int thumbColorNormal) {
492 | mThumbColorNormal = thumbColorNormal;
493 | createThumbs();
494 | }
495 |
496 | /**
497 | * If this is set, the thumb images will be replaced with a circle. The
498 | * pressed image will be of the specified color.
499 | *
500 | * @param thumbColorPressed Integer specifying the pressed color of the
501 | * circle to be drawn.
502 | */
503 | public void setThumbColorPressed(int thumbColorPressed) {
504 | mThumbColorPressed = thumbColorPressed;
505 | createThumbs();
506 | }
507 |
508 | /**
509 | * Sets the location of each thumb according to the developer's choice.
510 | * Numbered from 0 to mTickCount - 1 from the left.
511 | *
512 | * @param leftThumbIndex Integer specifying the index of the left thumb
513 | * @param rightThumbIndex Integer specifying the index of the right thumb
514 | */
515 | public void setThumbIndices(int leftThumbIndex, int rightThumbIndex) {
516 | if (indexOutOfRange(leftThumbIndex, rightThumbIndex)) {
517 |
518 | Log.e(TAG, "A thumb index is out of bounds. Check that it is between 0 and mTickCount - 1");
519 | throw new IllegalArgumentException("A thumb index is out of bounds. Check that it is between 0 and mTickCount - 1");
520 |
521 | } else {
522 |
523 | if (mFirstSetTickCount == true)
524 | mFirstSetTickCount = false;
525 |
526 | mLeftIndex = leftThumbIndex;
527 | mRightIndex = rightThumbIndex;
528 | createThumbs();
529 |
530 | if (mListener != null) {
531 | mListener.onIndexChangeListener(this, mLeftIndex, mRightIndex);
532 | }
533 | }
534 |
535 | invalidate();
536 | requestLayout();
537 | }
538 |
539 | /**
540 | * Gets the index of the left-most thumb.
541 | *
542 | * @return the 0-based index of the left thumb
543 | */
544 | public int getLeftIndex() {
545 | return mLeftIndex;
546 | }
547 |
548 | /**
549 | * Gets the index of the right-most thumb.
550 | *
551 | * @return the 0-based index of the right thumb
552 | */
553 | public int getRightIndex() {
554 | return mRightIndex;
555 | }
556 |
557 | // Private Methods /////////////////////////////////////////////////////////
558 |
559 | /**
560 | * Does all the functions of the constructor for RangeBar. Called by both
561 | * RangeBar constructors in lieu of copying the code for each constructor.
562 | *
563 | * @param context Context from the constructor.
564 | * @param attrs AttributeSet from the constructor.
565 | * @return none
566 | */
567 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
568 | private void rangeBarInit(Context context, AttributeSet attrs) {
569 | TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.RangeBar, 0, 0);
570 |
571 | try {
572 |
573 | // Sets the values of the user-defined attributes based on the XML
574 | // attributes.
575 | final Integer tickCount = ta.getInteger(R.styleable.RangeBar_tickCount, DEFAULT_TICK_COUNT);
576 |
577 | if (isValidTickCount(tickCount)) {
578 |
579 | // Similar functions performed above in setTickCount; make sure
580 | // you know how they interact
581 | mTickCount = tickCount;
582 | mLeftIndex = 0;
583 | mRightIndex = mTickCount - 1;
584 |
585 | if (mListener != null) {
586 | mListener.onIndexChangeListener(this, mLeftIndex, mRightIndex);
587 | }
588 |
589 | } else {
590 |
591 | Log.e(TAG, "tickCount less than 2; invalid tickCount. XML input ignored.");
592 | }
593 |
594 | mTickHeightDP = ta.getDimension(R.styleable.RangeBar_tickHeight, DEFAULT_TICK_HEIGHT_DP);
595 | mBarWeight = ta.getDimension(R.styleable.RangeBar_barWeight, DEFAULT_BAR_WEIGHT_PX);
596 | mBarColor = ta.getColor(R.styleable.RangeBar_barColor, DEFAULT_BAR_COLOR);
597 | mConnectingLineWeight = ta.getDimension(R.styleable.RangeBar_connectingLineWeight,
598 | DEFAULT_CONNECTING_LINE_WEIGHT_PX);
599 | mConnectingLineColor = ta.getColor(R.styleable.RangeBar_connectingLineColor,
600 | DEFAULT_CONNECTING_LINE_COLOR);
601 | mThumbRadiusDP = ta.getDimension(R.styleable.RangeBar_thumbRadius, DEFAULT_THUMB_RADIUS_DP);
602 | mThumbImageNormal = ta.getResourceId(R.styleable.RangeBar_thumbImageNormal,
603 | DEFAULT_THUMB_IMAGE_NORMAL);
604 | mThumbImagePressed = ta.getResourceId(R.styleable.RangeBar_thumbImagePressed,
605 | DEFAULT_THUMB_IMAGE_PRESSED);
606 | mThumbColorNormal = ta.getColor(R.styleable.RangeBar_thumbColorNormal, DEFAULT_THUMB_COLOR_NORMAL);
607 | mThumbColorPressed = ta.getColor(R.styleable.RangeBar_thumbColorPressed,
608 | DEFAULT_THUMB_COLOR_PRESSED);
609 | mIsThumbAnimate = ta.getBoolean(R.styleable.RangeBar_thumbAnimate, true);
610 | } finally {
611 |
612 | ta.recycle();
613 | }
614 |
615 | }
616 |
617 | /**
618 | * Creates a new mBar
619 | *
620 | * @param none
621 | */
622 | private void createBar() {
623 |
624 | mBar = new Bar(getContext(),
625 | getMarginLeft(),
626 | getYPos(),
627 | getBarLength(),
628 | mTickCount,
629 | mTickHeightDP,
630 | mBarWeight,
631 | mBarColor);
632 | invalidate();
633 | }
634 |
635 | /**
636 | * Creates a new ConnectingLine.
637 | *
638 | * @param none
639 | */
640 | private void createConnectingLine() {
641 |
642 | mConnectingLine = new ConnectingLine(getContext(),
643 | getYPos(),
644 | mConnectingLineWeight,
645 | mConnectingLineColor);
646 | invalidate();
647 | }
648 |
649 | /**
650 | * Creates two new Thumbs.
651 | *
652 | * @param none
653 | */
654 | private void createThumbs() {
655 |
656 | Context ctx = getContext();
657 | float yPos = getYPos();
658 |
659 | mLeftThumb = new Thumb(ctx,
660 | yPos,
661 | mThumbColorNormal,
662 | mThumbColorPressed,
663 | mThumbRadiusDP,
664 | mThumbImageNormal,
665 | mThumbImagePressed,
666 | mUpdateListener);
667 | mRightThumb = new Thumb(ctx,
668 | yPos,
669 | mThumbColorNormal,
670 | mThumbColorPressed,
671 | mThumbRadiusDP,
672 | mThumbImageNormal,
673 | mThumbImagePressed,
674 | mUpdateListener);
675 |
676 | float marginLeft = getMarginLeft();
677 | float barLength = getBarLength();
678 |
679 | // Initialize thumbs to the desired indices
680 | mLeftThumb.setX(marginLeft + (mLeftIndex / (float) (mTickCount - 1)) * barLength);
681 | mRightThumb.setX(marginLeft + (mRightIndex / (float) (mTickCount - 1)) * barLength);
682 |
683 | invalidate();
684 | }
685 |
686 | /**
687 | * Get marginLeft in each of the public attribute methods.
688 | *
689 | * @param none
690 | * @return float marginLeft
691 | */
692 | private float getMarginLeft() {
693 | return ((mLeftThumb != null) ? mLeftThumb.getHalfWidth() : 0);
694 | }
695 |
696 | /**
697 | * Get yPos in each of the public attribute methods.
698 | *
699 | * @param none
700 | * @return float yPos
701 | */
702 | private float getYPos() {
703 | return (getHeight() / 2f);
704 | }
705 |
706 | /**
707 | * Get barLength in each of the public attribute methods.
708 | *
709 | * @param none
710 | * @return float barLength
711 | */
712 | private float getBarLength() {
713 | return (getWidth() - 2 * getMarginLeft());
714 | }
715 |
716 | /**
717 | * Returns if either index is outside the range of the tickCount.
718 | *
719 | * @param leftThumbIndex Integer specifying the left thumb index.
720 | * @param rightThumbIndex Integer specifying the right thumb index.
721 | * @return boolean If the index is out of range.
722 | */
723 | private boolean indexOutOfRange(int leftThumbIndex, int rightThumbIndex) {
724 | return (leftThumbIndex < 0 || leftThumbIndex >= mTickCount
725 | || rightThumbIndex < 0
726 | || rightThumbIndex >= mTickCount);
727 | }
728 |
729 | /**
730 | * If is invalid tickCount, rejects. TickCount must be greater than 1
731 | *
732 | * @param tickCount Integer
733 | * @return boolean: whether tickCount > 1
734 | */
735 | private boolean isValidTickCount(int tickCount) {
736 | return (tickCount > 1);
737 | }
738 |
739 | /**
740 | * Handles a {@link MotionEvent#ACTION_DOWN} event.
741 | *
742 | * @param x the x-coordinate of the down action
743 | * @param y the y-coordinate of the down action
744 | */
745 | private void onActionDown(float x, float y) {
746 |
747 | if (!mLeftThumb.isPressed() && mLeftThumb.isInTargetZone(x, y)) {
748 |
749 | pressThumb(mLeftThumb, x);
750 |
751 | } else if (!mLeftThumb.isPressed() && mRightThumb.isInTargetZone(x, y)) {
752 |
753 | pressThumb(mRightThumb, x);
754 | }
755 | }
756 |
757 | /**
758 | * Handles a {@link MotionEvent#ACTION_UP} or
759 | * {@link MotionEvent#ACTION_CANCEL} event.
760 | *
761 | * @param x the x-coordinate of the up action
762 | * @param y the y-coordinate of the up action
763 | */
764 | private void onActionUp(float x, float y) {
765 |
766 | if (mLeftThumb.isPressed()) {
767 | releaseThumb(mLeftThumb);
768 | } else if (mRightThumb.isPressed()) {
769 | releaseThumb(mRightThumb);
770 | } else {
771 |
772 | float leftThumbXDistance = Math.abs(mLeftThumb.getX() - x);
773 | float rightThumbXDistance = Math.abs(mRightThumb.getX() - x);
774 |
775 | if (leftThumbXDistance < rightThumbXDistance) {
776 | if (mIsAvailable && mIsThumbAnimate)
777 | releaseThumbAnimate(mLeftThumb, x);
778 | else {
779 | mLeftThumb.setX(x);
780 | releaseThumb(mLeftThumb);
781 | }
782 | } else {
783 | if (mIsAvailable && mIsThumbAnimate)
784 | releaseThumbAnimate(mRightThumb, x);
785 | else {
786 | mRightThumb.setX(x);
787 | releaseThumb(mRightThumb);
788 | }
789 | }
790 |
791 | // Get the updated nearest tick marks for each thumb.
792 | final int newLeftIndex = mBar.getNearestTickIndex(mLeftThumb);
793 | final int newRightIndex = mBar.getNearestTickIndex(mRightThumb);
794 |
795 | // If either of the indices have changed, update and call the listener.
796 | if (newLeftIndex != mLeftIndex || newRightIndex != mRightIndex) {
797 |
798 | mLeftIndex = newLeftIndex;
799 | mRightIndex = newRightIndex;
800 |
801 | if (mListener != null) {
802 | mListener.onIndexChangeListener(this, mLeftIndex, mRightIndex);
803 | }
804 | }
805 | }
806 | }
807 |
808 | /**
809 | * Handles a {@link MotionEvent#ACTION_MOVE} event.
810 | *
811 | * @param x the x-coordinate of the move event
812 | */
813 | private void onActionMove(float x) {
814 |
815 | // Move the pressed thumb to the new x-position.
816 | if (mLeftThumb.isPressed()) {
817 | moveThumb(mLeftThumb, x);
818 | } else if (mRightThumb.isPressed()) {
819 | moveThumb(mRightThumb, x);
820 | }
821 |
822 | // If the thumbs have switched order, fix the references.
823 | if (mLeftThumb.getX() > mRightThumb.getX()) {
824 | final Thumb temp = mLeftThumb;
825 | mLeftThumb = mRightThumb;
826 | mRightThumb = temp;
827 | }
828 |
829 | // Get the updated nearest tick marks for each thumb.
830 | final int newLeftIndex = mBar.getNearestTickIndex(mLeftThumb);
831 | final int newRightIndex = mBar.getNearestTickIndex(mRightThumb);
832 |
833 | // If either of the indices have changed, update and call the listener.
834 | if (newLeftIndex != mLeftIndex || newRightIndex != mRightIndex) {
835 |
836 | mLeftIndex = newLeftIndex;
837 | mRightIndex = newRightIndex;
838 |
839 | if (mListener != null) {
840 | mListener.onIndexChangeListener(this, mLeftIndex, mRightIndex);
841 | }
842 | }
843 | }
844 |
845 | /**
846 | * Set the thumb to be in the pressed state and calls invalidate() to redraw
847 | * the canvas to reflect the updated state.
848 | *
849 | * @param thumb the thumb to press
850 | */
851 | private void pressThumb(Thumb thumb, final float startX) {
852 | if (mFirstSetTickCount)
853 | mFirstSetTickCount = false;
854 | thumb.press();
855 | if (mIsAvailable && mIsThumbAnimate)
856 | thumb.startThumb(startX);
857 | else invalidate();
858 | }
859 |
860 | /**
861 | * Set the thumb to be in the normal/un-pressed state and calls invalidate()
862 | * to redraw the canvas to reflect the updated state.
863 | *
864 | * @param thumb the thumb to release
865 | */
866 | private void releaseThumb(Thumb thumb) {
867 | final float nearestTickX = mBar.getNearestTickCoordinate(thumb);
868 | thumb.release();
869 | if (mIsAvailable && mIsThumbAnimate)
870 | thumb.finishThumb(nearestTickX);
871 | else {
872 | thumb.setX(nearestTickX);
873 | invalidate();
874 | }
875 | }
876 |
877 | private void releaseThumbAnimate(Thumb thumb, final float endX) {
878 | final float nearestTickX = mBar.getNearestTickCoordinate(endX);
879 | thumb.release();
880 | thumb.finishThumb(nearestTickX);
881 | }
882 |
883 | /**
884 | * Moves the thumb to the given x-coordinate.
885 | *
886 | * @param thumb the thumb to move
887 | * @param x the x-coordinate to move the thumb to
888 | */
889 | private void moveThumb(Thumb thumb, float x) {
890 |
891 | // If the user has moved their finger outside the range of the bar,
892 | // do not move the thumbs past the edge.
893 | if (x < mBar.getLeftX() || x > mBar.getRightX()) {
894 | // Do nothing.
895 | } else {
896 | thumb.setX(x);
897 | invalidate();
898 | }
899 | }
900 |
901 | // Inner Classes ///////////////////////////////////////////////////////////
902 |
903 | /**
904 | * A callback that notifies clients when the RangeBar has changed. The
905 | * listener will only be called when either thumb's index has changed - not
906 | * for every movement of the thumb.
907 | */
908 | public static interface OnRangeBarChangeListener {
909 |
910 | public void onIndexChangeListener(RangeBar rangeBar, int leftThumbIndex, int rightThumbIndex);
911 | }
912 | }
913 |
--------------------------------------------------------------------------------
/rangebar/src/com/edmodo/rangebar/Thumb.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013, Edmodo, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License.
5 | * You may obtain a copy of the License in the LICENSE file, or at:
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
10 | * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
11 | * governing permissions and limitations under the License.
12 | */
13 |
14 | package com.edmodo.rangebar;
15 |
16 | import android.animation.ValueAnimator;
17 | import android.annotation.TargetApi;
18 | import android.content.Context;
19 | import android.content.res.Resources;
20 | import android.graphics.Bitmap;
21 | import android.graphics.BitmapFactory;
22 | import android.graphics.Canvas;
23 | import android.graphics.Paint;
24 | import android.os.Build;
25 | import android.util.TypedValue;
26 | import android.view.animation.Interpolator;
27 | import android.view.animation.OvershootInterpolator;
28 |
29 | /**
30 | * Represents a thumb in the RangeBar slider. This is the handle for the slider
31 | * that is pressed and slid.
32 | */
33 | public class Thumb {
34 |
35 | // Private Constants ///////////////////////////////////////////////////////
36 | private final static int OPEN_DURATION = 50;
37 | private final static int CLOSE_DURATION = 200;
38 |
39 | // The radius (in dp) of the touchable area around the thumb. We are basing
40 | // this value off of the recommended 48dp Rhythm. See:
41 | // http://developer.android.com/design/style/metrics-grids.html#48dp-rhythm
42 | private static final float MINIMUM_TARGET_RADIUS_DP = 24;
43 |
44 | // Sets the default values for radius, normal, pressed if circle is to be
45 | // drawn but no value is given.
46 | private static final float DEFAULT_THUMB_RADIUS_DP = 14;
47 |
48 | // Corresponds to android.R.color.holo_blue_light.
49 | private static final int DEFAULT_THUMB_COLOR_NORMAL = 0xff33b5e5;
50 | private static final int DEFAULT_THUMB_COLOR_PRESSED = 0xff33b5e5;
51 |
52 | // Member Variables ////////////////////////////////////////////////////////
53 |
54 | // Radius (in pixels) of the touch area of the thumb.
55 | private final float mTargetRadiusPx;
56 |
57 | // The normal and pressed images to display for the thumbs.
58 | private final Bitmap mImageNormal;
59 | private final Bitmap mImagePressed;
60 |
61 | // Variables to store half the width/height for easier calculation.
62 | private final float mHalfWidthNormal;
63 | private final float mHalfHeightNormal;
64 |
65 | private final float mHalfWidthPressed;
66 | private final float mHalfHeightPressed;
67 |
68 | // Indicates whether this thumb is currently pressed and active.
69 | private boolean mIsPressed = false;
70 |
71 | // The y-position of the thumb in the parent view. This should not change.
72 | private final float mY;
73 |
74 | // The current x-position of the thumb in the parent view.
75 | private float mX;
76 |
77 | // mPaint to draw the thumbs if attributes are selected
78 | private Paint mPaintNormal;
79 | private Paint mPaintPressed;
80 |
81 | // Radius of the new thumb if selected
82 | private float mThumbRadiusPx;
83 |
84 | // Toggle to select bitmap thumbImage or not
85 | private boolean mUseBitmap;
86 |
87 | // Colors of the thumbs if they are to be drawn
88 | private int mThumbColorNormal;
89 | private int mThumbColorPressed;
90 |
91 | private final Interpolator mInterpolator = new OvershootInterpolator();
92 | private ValueAnimator mAnimator;
93 | private ValueAnimator.AnimatorUpdateListener mInvalidateListener;
94 |
95 | private ValueAnimator.AnimatorUpdateListener mUpdateListener;
96 | {
97 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
98 | mUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
99 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
100 | @Override
101 | public void onAnimationUpdate(final ValueAnimator animation) {
102 | mX = (Float) animation.getAnimatedValue();
103 | }
104 | };
105 | }
106 | }
107 | // Constructors ////////////////////////////////////////////////////////////
108 |
109 | Thumb(Context ctx,
110 | float y,
111 | int thumbColorNormal,
112 | int thumbColorPressed,
113 | float thumbRadiusDP,
114 | int thumbImageNormal,
115 | int thumbImagePressed,
116 | final ValueAnimator.AnimatorUpdateListener invalidateListener) {
117 |
118 | final Resources res = ctx.getResources();
119 |
120 | mImageNormal = BitmapFactory.decodeResource(res, thumbImageNormal);
121 | mImagePressed = BitmapFactory.decodeResource(res, thumbImagePressed);
122 | mInvalidateListener = invalidateListener;
123 |
124 | // If any of the attributes are set, toggle bitmap off
125 | if (thumbRadiusDP == -1 && thumbColorNormal == -1 && thumbColorPressed == -1) {
126 |
127 | mUseBitmap = true;
128 |
129 | } else {
130 |
131 | mUseBitmap = false;
132 |
133 | // If one of the attributes are set, but the others aren't, set the
134 | // attributes to default
135 | if (thumbRadiusDP == -1)
136 | mThumbRadiusPx = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
137 | DEFAULT_THUMB_RADIUS_DP,
138 | res.getDisplayMetrics());
139 | else
140 | mThumbRadiusPx = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
141 | thumbRadiusDP,
142 | res.getDisplayMetrics());
143 |
144 | if (thumbColorNormal == -1)
145 | mThumbColorNormal = DEFAULT_THUMB_COLOR_NORMAL;
146 | else
147 | mThumbColorNormal = thumbColorNormal;
148 |
149 | if (thumbColorPressed == -1)
150 | mThumbColorPressed = DEFAULT_THUMB_COLOR_PRESSED;
151 | else
152 | mThumbColorPressed = thumbColorPressed;
153 |
154 | // Creates the paint and sets the Paint values
155 | mPaintNormal = new Paint();
156 | mPaintNormal.setColor(mThumbColorNormal);
157 | mPaintNormal.setAntiAlias(true);
158 |
159 | mPaintPressed = new Paint();
160 | mPaintPressed.setColor(mThumbColorPressed);
161 | mPaintPressed.setAntiAlias(true);
162 | }
163 |
164 | mHalfWidthNormal = mImageNormal.getWidth() / 2f;
165 | mHalfHeightNormal = mImageNormal.getHeight() / 2f;
166 |
167 | mHalfWidthPressed = mImagePressed.getWidth() / 2f;
168 | mHalfHeightPressed = mImagePressed.getHeight() / 2f;
169 |
170 | // Sets the minimum touchable area, but allows it to expand based on
171 | // image size
172 | int targetRadius = (int) Math.max(MINIMUM_TARGET_RADIUS_DP, thumbRadiusDP);
173 |
174 | mTargetRadiusPx = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
175 | targetRadius,
176 | res.getDisplayMetrics());
177 |
178 | mX = mHalfWidthNormal;
179 | mY = y;
180 | }
181 |
182 | // Package-Private Methods /////////////////////////////////////////////////
183 |
184 | float getHalfWidth() {
185 | return mHalfWidthNormal;
186 | }
187 |
188 | float getHalfHeight() {
189 | return mHalfHeightNormal;
190 | }
191 |
192 | void setX(float x) {
193 | mX = x;
194 | }
195 |
196 | float getX() {
197 | return mX;
198 | }
199 |
200 | boolean isPressed() {
201 | return mIsPressed;
202 | }
203 |
204 | void press() {
205 | mIsPressed = true;
206 | }
207 |
208 | void release() {
209 | mIsPressed = false;
210 | }
211 |
212 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
213 | public void startThumb(final float startX) {
214 | if (mAnimator != null && mAnimator.isRunning())
215 | mAnimator.cancel();
216 | mAnimator = ValueAnimator.ofFloat(mX, startX).setDuration(OPEN_DURATION);
217 | mAnimator.removeAllUpdateListeners();
218 | mAnimator.setInterpolator(null);
219 | mAnimator.addUpdateListener(mUpdateListener);
220 | mAnimator.addUpdateListener(mInvalidateListener);
221 | mAnimator.start();
222 | }
223 |
224 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
225 | public void finishThumb(final float endX) {
226 | if (mAnimator != null && mAnimator.isRunning())
227 | mAnimator.cancel();
228 | mAnimator = ValueAnimator.ofFloat(mX, endX).setDuration(CLOSE_DURATION);
229 | mAnimator.removeAllUpdateListeners();
230 | mAnimator.setInterpolator(mInterpolator);
231 | mAnimator.addUpdateListener(mUpdateListener);
232 | mAnimator.addUpdateListener(mInvalidateListener);
233 | mAnimator.start();
234 | }
235 |
236 | /**
237 | * Determines if the input coordinate is close enough to this thumb to
238 | * consider it a press.
239 | *
240 | * @param x the x-coordinate of the user touch
241 | * @param y the y-coordinate of the user touch
242 | * @return true if the coordinates are within this thumb's target area;
243 | * false otherwise
244 | */
245 | boolean isInTargetZone(float x, float y) {
246 |
247 | if (Math.abs(x - mX) <= mTargetRadiusPx && Math.abs(y - mY) <= mTargetRadiusPx) {
248 | return true;
249 | }
250 | return false;
251 | }
252 |
253 | /**
254 | * Draws this thumb on the provided canvas.
255 | *
256 | * @param canvas Canvas to draw on; should be the Canvas passed into {#link
257 | * View#onDraw()}
258 | */
259 | void draw(Canvas canvas) {
260 |
261 | // If a bitmap is to be printed. Determined by thumbRadius attribute.
262 | if (mUseBitmap) {
263 |
264 | final Bitmap bitmap = (mIsPressed) ? mImagePressed : mImageNormal;
265 |
266 | if (mIsPressed) {
267 | final float topPressed = mY - mHalfHeightPressed;
268 | final float leftPressed = mX - mHalfWidthPressed;
269 | canvas.drawBitmap(bitmap, leftPressed, topPressed, null);
270 | } else {
271 | final float topNormal = mY - mHalfHeightNormal;
272 | final float leftNormal = mX - mHalfWidthNormal;
273 | canvas.drawBitmap(bitmap, leftNormal, topNormal, null);
274 | }
275 |
276 | } else {
277 |
278 | // Otherwise use a circle to display.
279 | if (mIsPressed)
280 | canvas.drawCircle(mX, mY, mThumbRadiusPx, mPaintPressed);
281 | else
282 | canvas.drawCircle(mX, mY, mThumbRadiusPx, mPaintNormal);
283 | }
284 | }
285 | }
286 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include 'rangebar'
2 | include 'RangeBarSample'
--------------------------------------------------------------------------------