├── .gitignore ├── README.md ├── README_zh.md ├── apk └── sample.apk ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── xw │ │ └── samlpe │ │ └── bubbleseekbar │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── xw │ │ │ └── samlpe │ │ │ └── bubbleseekbar │ │ │ ├── DemoFragment1.java │ │ │ ├── DemoFragment2.java │ │ │ ├── DemoFragment3.java │ │ │ ├── DemoFragment4.java │ │ │ ├── MainActivity.java │ │ │ └── ObservableScrollView.java │ └── res │ │ ├── drawable │ │ ├── selector_radio_text_color.xml │ │ ├── shape_divider_shadow.xml │ │ └── shape_divider_vertical.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── fragment_demo_1.xml │ │ ├── fragment_demo_2.xml │ │ ├── fragment_demo_3.xml │ │ └── fragment_demo_4.xml │ │ ├── menu │ │ └── menu_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── xw │ └── samlpe │ └── bubbleseekbar │ └── ExampleUnitTest.java ├── bubbleseekbar ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── xw │ │ └── repo │ │ ├── BubbleConfigBuilder.java │ │ ├── BubbleSeekBar.java │ │ └── BubbleUtils.java │ └── res │ └── values │ ├── attr.xml │ ├── colors.xml │ └── strings.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshot ├── demo1.gif ├── demo2.gif ├── demo3.gif └── demo4.gif └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Download](https://api.bintray.com/packages/woxingxiao/maven/bubbleseekbar/images/download.svg?version=3.4)](https://bintray.com/woxingxiao/maven/bubbleseekbar/3.0/link) 2 | [![Download](https://api.bintray.com/packages/woxingxiao/maven/bubbleseekbar/images/download.svg?version=3.4-lite)](https://bintray.com/woxingxiao/maven/bubbleseekbar/3.0-lite/link) 3 | [![License](http://img.shields.io/badge/License-Apache%202.0-brightgreen.svg?style=flat)](https://opensource.org/licenses/Apache-2.0) 4 | 5 | [**中文说明**](https://github.com/woxingxiao/BubbleSeekBar/blob/master/README_zh.md) 6 | 7 | **A beautiful Android custom seek bar, which has a bubble view with progress appearing upon when seeking. Highly customizable, mostly demands has been considered. `star` or `pull request` will be welcomed** 8 | **** 9 | ## Screenshot 10 | ![demo1](https://github.com/woxingxiao/BubbleSeekBar/blob/master/screenshot/demo1.gif) 11 | ![demo2](https://github.com/woxingxiao/BubbleSeekBar/blob/master/screenshot/demo2.gif) 12 | ****** 13 | ![demo3](https://github.com/woxingxiao/BubbleSeekBar/blob/master/screenshot/demo3.gif) 14 | ![demo4](https://github.com/woxingxiao/BubbleSeekBar/blob/master/screenshot/demo4.gif) 15 | 16 | ## Download 17 | The **LATEST_VERSION**: [![Download](https://api.bintray.com/packages/woxingxiao/maven/bubbleseekbar/images/download.svg)](https://bintray.com/woxingxiao/maven/bubbleseekbar/_latestVersion) 18 | ```groovy 19 | dependencies { 20 | // lite version (recommended) 21 | // e.g. compile 'com.xw.repo:bubbleseekbar:3.4-lite' 22 | compile 'com.xw.repo:bubbleseekbar:${LATEST_VERSION}-lite' 23 | 24 | // enhanced version 25 | // e.g. compile 'com.xw.repo:bubbleseekbar:3.4' 26 | // compile 'com.xw.repo:bubbleseekbar:${LATEST_VERSION}' 27 | } 28 | ``` 29 | 30 | ## Usage 31 | ### xml 32 | ```xml 33 | 50 | ``` 51 | ```xml 52 | 65 | ``` 66 | ### java (not for **_lite_** version) 67 | ```java 68 | mBbubbleSeekBar.getConfigBuilder() 69 | .min(0.0) 70 | .max(50) 71 | .progress(20) 72 | .sectionCount(5) 73 | .trackColor(ContextCompat.getColor(getContext(), R.color.color_gray)) 74 | .secondTrackColor(ContextCompat.getColor(getContext(), R.color.color_blue)) 75 | .thumbColor(ContextCompat.getColor(getContext(), R.color.color_blue)) 76 | .showSectionText() 77 | .sectionTextColor(ContextCompat.getColor(getContext(), R.color.colorPrimary)) 78 | .sectionTextSize(18) 79 | .showThumbText() 80 | .thumbTextColor(ContextCompat.getColor(getContext(), R.color.color_red)) 81 | .thumbTextSize(18) 82 | .bubbleColor(ContextCompat.getColor(getContext(), R.color.color_green)) 83 | .bubbleTextSize(18) 84 | .showSectionMark() 85 | .seekBySection() 86 | .autoAdjustSectionMark() 87 | .sectionTextPosition(BubbleSeekBar.TextPosition.BELOW_SECTION_MARK) 88 | .build(); 89 | ``` 90 | Check out the demo for more details. Or download the apk: [**sample.apk**](https://github.com/woxingxiao/BubbleSeekBar/raw/master/apk/sample.apk) 91 | ## Attentions 92 | - There are two versions of this library.The differences as follow: 93 | 94 | version | init | getter/setter 95 | -------- | ---|--- 96 | lite|xml|min, max, progress 97 | enhanced|xml, java|all attrs 98 | 99 | **_lite_** version is recommended. 100 | 101 | - You must correct the offsets by setting `ScrollListener` when `BubbleSeekBar`'s parent view is scrollable, otherwise the position of bubble appears maybe be wrong. For example: 102 | ```java 103 | mContainer.setOnYourContainerScrollListener(new OnYourContainerScrollListener() { 104 | @Override 105 | public void onScroll() { 106 | // call this method to correct offsets 107 | mBubbleSeekBar.correctOffsetWhenContainerOnScrolling(); 108 | } 109 | }); 110 | ``` 111 | - When set `bsb_touch_to_seek` attribute to be `true` , you better not to click **too fast** because the animation may not have enough time to play. 112 | - This library depends `support:appcompat-v7` via **`provided`**, so you don't need to worry about compatibility. 113 | 114 | ## Attributes 115 | ```xml 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | nce"/> 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | ``` 151 | ## License 152 | ``` 153 | Copyright 2017 woxingxiao 154 | 155 | Licensed under the Apache License, Version 2.0 (the "License"); 156 | you may not use this file except in compliance with the License. 157 | You may obtain a copy of the License at 158 | 159 | http://www.apache.org/licenses/LICENSE-2.0 160 | 161 | Unless required by applicable law or agreed to in writing, software 162 | distributed under the License is distributed on an "AS IS" BASIS, 163 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 164 | See the License for the specific language governing permissions and 165 | limitations under the License. 166 | ``` 167 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | [![Download](https://api.bintray.com/packages/woxingxiao/maven/bubbleseekbar/images/download.svg?version=3.4)](https://bintray.com/woxingxiao/maven/bubbleseekbar/3.0/link) 2 | [![Download](https://api.bintray.com/packages/woxingxiao/maven/bubbleseekbar/images/download.svg?version=3.4-lite)](https://bintray.com/woxingxiao/maven/bubbleseekbar/3.0-lite/link) 3 | [![License](http://img.shields.io/badge/License-Apache%202.0-brightgreen.svg?style=flat)](https://opensource.org/licenses/Apache-2.0) 4 | 5 | **自定义`SeekBar`,进度变化由可视化气泡样式呈现,定制化程度较高,适合大部分需求。欢迎`star` or `pull request`** 6 | **** 7 | ## Screenshot 8 | ![demo1](https://github.com/woxingxiao/BubbleSeekBar/blob/master/screenshot/demo1.gif) 9 | ![demo2](https://github.com/woxingxiao/BubbleSeekBar/blob/master/screenshot/demo2.gif) 10 | ******* 11 | ![demo3](https://github.com/woxingxiao/BubbleSeekBar/blob/master/screenshot/demo3.gif) 12 | ![demo4](https://github.com/woxingxiao/BubbleSeekBar/blob/master/screenshot/demo4.gif) 13 | ## Download 14 | The **LATEST_VERSION**:[![Download](https://api.bintray.com/packages/woxingxiao/maven/bubbleseekbar/images/download.svg)](https://bintray.com/woxingxiao/maven/bubbleseekbar/_latestVersion) 15 | ```groovy 16 | dependencies { 17 |     // lite version 轻量版(推荐) 18 |     // 例如:compile 'com.xw.repo:bubbleseekbar:3.4-lite' 19 | compile 'com.xw.repo:bubbleseekbar:${LATEST_VERSION}-lite' 20 | 21 |     // enhanced version 增强版 22 |     // 例如:compile 'com.xw.repo:bubbleseekbar:3.4' 23 | // compile 'com.xw.repo:bubbleseekbar:${LATEST_VERSION}' 24 | } 25 | ``` 26 | ## Usage 27 | ### xml 28 | ```xml 29 | 46 | ``` 47 | ```xml 48 | 61 | ``` 62 | ### java (not for **_lite_** version) 63 | ```java 64 | mBbubbleSeekBar.getConfigBuilder() 65 | .min(0.0) 66 | .max(50) 67 | .progress(20) 68 | .sectionCount(5) 69 | .trackColor(ContextCompat.getColor(getContext(), R.color.color_gray)) 70 | .secondTrackColor(ContextCompat.getColor(getContext(), R.color.color_blue)) 71 | .thumbColor(ContextCompat.getColor(getContext(), R.color.color_blue)) 72 | .showSectionText() 73 | .sectionTextColor(ContextCompat.getColor(getContext(), R.color.colorPrimary)) 74 | .sectionTextSize(18) 75 | .showThumbText() 76 | .thumbTextColor(ContextCompat.getColor(getContext(), R.color.color_red)) 77 | .thumbTextSize(18) 78 | .bubbleColor(ContextCompat.getColor(getContext(), R.color.color_green)) 79 | .bubbleTextSize(18) 80 | .showSectionMark() 81 | .seekBySection() 82 | .autoAdjustSectionMark() 83 | .sectionTextPosition(BubbleSeekBar.TextPosition.BELOW_SECTION_MARK) 84 | .build(); 85 | ``` 86 | 查看demo获知更多使用细节。或者下载安装apk:[**sample.apk**](https://github.com/woxingxiao/BubbleSeekBar/raw/master/apk/sample.apk) 87 | 88 | ## Attentions 89 | - 下列是两个版本的差异对比: 90 | 91 | version | init | getter/setter 92 | -------- | ---|--- 93 | lite|xml|min, max, progress 94 | enhanced|xml, java|all attrs 95 | 96 | 推荐使用 **_lite_** 版本。 97 | 98 | - 如果`BubbleSeekBar`的外部容器是可滑动的控件,需要设置滑动监听来修正气泡的偏移,否则滑动后气泡出现位置可能错乱。方法如下: 99 | ```java 100 | mContainer.setOnYourContainerScrollListener(new OnYourContainerScrollListener() { 101 | @Override 102 | public void onScroll() { 103 | // 调用修正偏移方法 104 | mBubbleSeekBar.correctOffsetWhenContainerOnScrolling(); 105 | } 106 | }); 107 | ``` 108 | - 当设置`bsb_touch_to_seek`属性为`true`时, 最好不要点击**太快**去seek进度,否则动画可能没有足够时间播放。 109 | - 本库依赖`support:appcompat-v7`通过 **`provided`** 的方式,所以不必担心兼容性。 110 | 111 | ## Attributes 112 | ```xml 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | nce"/> 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | ``` 148 | -------- 149 | > **人生苦短,请选择科学上网。推荐一下本人正在使用的,稳定高速,便宜好用。[推介链接](https://portal.shadowsocks.com.hk/aff.php?aff=8881)**   150 | 151 | ## License 152 | ``` 153 | Copyright 2017 woxingxiao 154 | 155 | Licensed under the Apache License, Version 2.0 (the "License"); 156 | you may not use this file except in compliance with the License. 157 | You may obtain a copy of the License at 158 | 159 | http://www.apache.org/licenses/LICENSE-2.0 160 | 161 | Unless required by applicable law or agreed to in writing, software 162 | distributed under the License is distributed on an "AS IS" BASIS, 163 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 164 | See the License for the specific language governing permissions and 165 | limitations under the License. 166 | ``` 167 | -------------------------------------------------------------------------------- /apk/sample.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sathishmscict/BubbleSeekBar/d3796790eb8d9329a84b3f0fe4100c3e5542778d/apk/sample.apk -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.2" 6 | defaultConfig { 7 | applicationId "com.xw.samlpe.bubbleseekbar" 8 | minSdkVersion 14 9 | targetSdkVersion 25 10 | versionCode 6 11 | versionName "1.5" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | 22 | android.applicationVariants.all { variant -> 23 | variant.outputs.each { output -> 24 | if (output.outputFile != null && output.outputFile.name.endsWith('.apk')) { 25 | def name = "${rootDir}/apk/sample.apk" 26 | output.outputFile = file(name) 27 | } 28 | } 29 | } 30 | } 31 | 32 | dependencies { 33 | compile fileTree(include: ['*.jar'], dir: 'libs') 34 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 35 | exclude group: 'com.android.support', module: 'support-annotations' 36 | }) 37 | compile 'com.android.support:appcompat-v7:25.3.1' 38 | compile 'com.android.support:design:25.3.1' 39 | testCompile 'junit:junit:4.12' 40 | compile project(':bubbleseekbar') 41 | } 42 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Android\android-sdk-windows/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/xw/samlpe/bubbleseekbar/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.xw.samlpe.bubbleseekbar; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.xw.samlpe.bubbleseekbar", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/xw/samlpe/bubbleseekbar/DemoFragment1.java: -------------------------------------------------------------------------------- 1 | package com.xw.samlpe.bubbleseekbar; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.design.widget.Snackbar; 6 | import android.support.v4.app.Fragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.Button; 11 | 12 | import com.xw.repo.BubbleSeekBar; 13 | 14 | import java.util.Random; 15 | 16 | /** 17 | * DemoFragment1 18 | * <>

19 | * Created by woxingxiao on 2017-03-11. 20 | */ 21 | 22 | public class DemoFragment1 extends Fragment { 23 | 24 | public static DemoFragment1 newInstance() { 25 | return new DemoFragment1(); 26 | } 27 | 28 | @Nullable 29 | @Override 30 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 31 | 32 | View view = inflater.inflate(R.layout.fragment_demo_1, container, false); 33 | 34 | final BubbleSeekBar bubbleSeekBar = (BubbleSeekBar) view.findViewById(R.id.demo_1_seek_bar); 35 | bubbleSeekBar.setProgress(20); 36 | Button button = (Button) view.findViewById(R.id.demo_1_button); 37 | 38 | button.setOnClickListener(new View.OnClickListener() { 39 | @Override 40 | public void onClick(View v) { 41 | int progress = new Random().nextInt((int) bubbleSeekBar.getMax()); 42 | bubbleSeekBar.setProgress(progress); 43 | Snackbar.make(v, "set random progress = " + progress, Snackbar.LENGTH_SHORT).show(); 44 | } 45 | }); 46 | 47 | return view; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/xw/samlpe/bubbleseekbar/DemoFragment2.java: -------------------------------------------------------------------------------- 1 | package com.xw.samlpe.bubbleseekbar; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | /** 11 | * DemoFragment2 12 | * <>

13 | * Created by woxingxiao on 2017-03-11. 14 | */ 15 | 16 | public class DemoFragment2 extends Fragment { 17 | 18 | public static DemoFragment2 newInstance() { 19 | return new DemoFragment2(); 20 | } 21 | 22 | @Nullable 23 | @Override 24 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 25 | return inflater.inflate(R.layout.fragment_demo_2, container, false); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/xw/samlpe/bubbleseekbar/DemoFragment3.java: -------------------------------------------------------------------------------- 1 | package com.xw.samlpe.bubbleseekbar; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v4.content.ContextCompat; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | 11 | import com.xw.repo.BubbleSeekBar; 12 | 13 | /** 14 | * DemoFragment3 15 | * <>

16 | * Created by woxingxiao on 2017-03-11. 17 | */ 18 | 19 | public class DemoFragment3 extends Fragment { 20 | 21 | public static DemoFragment3 newInstance() { 22 | return new DemoFragment3(); 23 | } 24 | 25 | @Nullable 26 | @Override 27 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 28 | 29 | View view = inflater.inflate(R.layout.fragment_demo_3, container, false); 30 | BubbleSeekBar bubbleSeekBar1 = (BubbleSeekBar) view.findViewById(R.id.demo_3_seek_bar_1); 31 | BubbleSeekBar bubbleSeekBar2 = (BubbleSeekBar) view.findViewById(R.id.demo_3_seek_bar_2); 32 | BubbleSeekBar bubbleSeekBar3 = (BubbleSeekBar) view.findViewById(R.id.demo_3_seek_bar_3); 33 | BubbleSeekBar bubbleSeekBar4 = (BubbleSeekBar) view.findViewById(R.id.demo_3_seek_bar_4); 34 | 35 | bubbleSeekBar1.getConfigBuilder() 36 | .min(0) 37 | .max(50) 38 | .progress(20) 39 | .sectionCount(5) 40 | .trackColor(ContextCompat.getColor(getContext(), R.color.color_gray)) 41 | .secondTrackColor(ContextCompat.getColor(getContext(), R.color.color_blue)) 42 | .thumbColor(ContextCompat.getColor(getContext(), R.color.color_blue)) 43 | .showSectionText() 44 | .sectionTextColor(ContextCompat.getColor(getContext(), R.color.colorPrimary)) 45 | .sectionTextSize(18) 46 | .showThumbText() 47 | .thumbTextColor(ContextCompat.getColor(getContext(), R.color.color_red)) 48 | .thumbTextSize(18) 49 | .bubbleColor(ContextCompat.getColor(getContext(), R.color.color_green)) 50 | .bubbleTextSize(18) 51 | .showSectionMark() 52 | .seekBySection() 53 | .autoAdjustSectionMark() 54 | .sectionTextPosition(BubbleSeekBar.TextPosition.BELOW_SECTION_MARK) 55 | .build(); 56 | 57 | bubbleSeekBar2.getConfigBuilder() 58 | .min(-50) 59 | .max(50) 60 | .sectionCount(10) 61 | .sectionTextInterval(2) 62 | .trackColor(ContextCompat.getColor(getContext(), R.color.color_red_light)) 63 | .secondTrackColor(ContextCompat.getColor(getContext(), R.color.color_red)) 64 | .seekBySection() 65 | .showSectionText() 66 | .sectionTextPosition(BubbleSeekBar.TextPosition.BELOW_SECTION_MARK) 67 | .build(); 68 | 69 | bubbleSeekBar3.getConfigBuilder() 70 | .min(1) 71 | .max(1.5f) 72 | .floatType() 73 | .sectionCount(10) 74 | .secondTrackColor(ContextCompat.getColor(getContext(), R.color.color_green)) 75 | .showSectionText() 76 | .showThumbText() 77 | .build(); 78 | 79 | bubbleSeekBar4.getConfigBuilder() 80 | .min(-0.4f) 81 | .max(0.4f) 82 | .progress(0) 83 | .floatType() 84 | .sectionCount(10) 85 | .sectionTextInterval(2) 86 | .showSectionText() 87 | .sectionTextPosition(BubbleSeekBar.TextPosition.BELOW_SECTION_MARK) 88 | .autoAdjustSectionMark() 89 | .build(); 90 | 91 | return view; 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /app/src/main/java/com/xw/samlpe/bubbleseekbar/DemoFragment4.java: -------------------------------------------------------------------------------- 1 | package com.xw.samlpe.bubbleseekbar; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.TextView; 10 | 11 | import com.xw.repo.BubbleSeekBar; 12 | 13 | import java.util.Locale; 14 | 15 | /** 16 | * DemoFragment4 17 | * <>

18 | * Created by woxingxiao on 2017-03-11. 19 | */ 20 | 21 | public class DemoFragment4 extends Fragment { 22 | 23 | public static DemoFragment4 newInstance() { 24 | return new DemoFragment4(); 25 | } 26 | 27 | @Nullable 28 | @Override 29 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 30 | 31 | View view = inflater.inflate(R.layout.fragment_demo_4, container, false); 32 | ObservableScrollView mObsScrollView = (ObservableScrollView) view.findViewById(R.id.demo_4_obs_scroll_view); 33 | final BubbleSeekBar bubbleSeekBar1 = (BubbleSeekBar) view.findViewById(R.id.demo_4_seek_bar_1); 34 | final BubbleSeekBar bubbleSeekBar2 = (BubbleSeekBar) view.findViewById(R.id.demo_4_seek_bar_2); 35 | final BubbleSeekBar bubbleSeekBar3 = (BubbleSeekBar) view.findViewById(R.id.demo_4_seek_bar_3); 36 | final TextView progressText1 = (TextView) view.findViewById(R.id.demo_4_progress_text_1); 37 | final TextView progressText2 = (TextView) view.findViewById(R.id.demo_4_progress_text_2); 38 | final TextView progressText3 = (TextView) view.findViewById(R.id.demo_4_progress_text_3); 39 | 40 | mObsScrollView.setOnScrollChangedListener(new ObservableScrollView.OnScrollChangedListener() { 41 | @Override 42 | public void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy) { 43 | bubbleSeekBar1.correctOffsetWhenContainerOnScrolling(); 44 | } 45 | }); 46 | bubbleSeekBar2.setOnProgressChangedListener(new BubbleSeekBar.OnProgressChangedListenerAdapter() { 47 | @Override 48 | public void onProgressChanged(int progress, float progressFloat) { 49 | String s = String.format(Locale.CHINA, "onChanged int:%d, float:%.1f", progress, progressFloat); 50 | progressText1.setText(s); 51 | } 52 | 53 | @Override 54 | public void getProgressOnActionUp(int progress, float progressFloat) { 55 | String s = String.format(Locale.CHINA, "onActionUp int:%d, float:%.1f", progress, progressFloat); 56 | progressText2.setText(s); 57 | } 58 | 59 | @Override 60 | public void getProgressOnFinally(int progress, float progressFloat) { 61 | String s = String.format(Locale.CHINA, "onFinally int:%d, float:%.1f", progress, progressFloat); 62 | progressText3.setText(s); 63 | } 64 | }); 65 | 66 | // trigger by set progress or seek by finger 67 | bubbleSeekBar3.setProgress(bubbleSeekBar3.getMax()); 68 | 69 | return view; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/com/xw/samlpe/bubbleseekbar/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.xw.samlpe.bubbleseekbar; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.app.FragmentManager; 6 | import android.support.v4.app.FragmentTransaction; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.support.v7.widget.Toolbar; 9 | import android.view.Menu; 10 | import android.view.MenuItem; 11 | import android.view.View; 12 | 13 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 14 | 15 | private String mTag; 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.activity_main); 21 | 22 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 23 | setSupportActionBar(toolbar); 24 | 25 | findViewById(R.id.main_tab_btn_1).setOnClickListener(this); 26 | findViewById(R.id.main_tab_btn_2).setOnClickListener(this); 27 | findViewById(R.id.main_tab_btn_3).setOnClickListener(this); 28 | findViewById(R.id.main_tab_btn_4).setOnClickListener(this); 29 | 30 | if (savedInstanceState == null) { 31 | FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); 32 | ft.add(R.id.container, DemoFragment1.newInstance(), "demo1"); 33 | ft.commit(); 34 | mTag = "demo1"; 35 | } 36 | } 37 | 38 | @Override 39 | public void onClick(View v) { 40 | switch (v.getId()) { 41 | case R.id.main_tab_btn_1: 42 | switchContent("demo1"); 43 | break; 44 | case R.id.main_tab_btn_2: 45 | switchContent("demo2"); 46 | break; 47 | case R.id.main_tab_btn_3: 48 | switchContent("demo3"); 49 | break; 50 | case R.id.main_tab_btn_4: 51 | switchContent("demo4"); 52 | break; 53 | } 54 | } 55 | 56 | public void switchContent(String toTag) { 57 | if (mTag.equals(toTag)) 58 | return; 59 | 60 | FragmentManager fm = getSupportFragmentManager(); 61 | Fragment from = fm.findFragmentByTag(mTag); 62 | Fragment to = fm.findFragmentByTag(toTag); 63 | 64 | FragmentTransaction ft = fm.beginTransaction(); 65 | if (to == null) { 66 | if ("demo1".equals(toTag)) { 67 | to = DemoFragment1.newInstance(); 68 | } else if ("demo2".equals(toTag)) { 69 | to = DemoFragment2.newInstance(); 70 | } else if ("demo3".equals(toTag)) { 71 | to = DemoFragment3.newInstance(); 72 | } else { 73 | to = DemoFragment4.newInstance(); 74 | } 75 | } 76 | if (!to.isAdded()) { 77 | ft.hide(from).add(R.id.container, to, toTag); 78 | } else { 79 | ft.hide(from).show(to); 80 | } 81 | ft.commit(); 82 | 83 | mTag = toTag; 84 | } 85 | 86 | @Override 87 | public boolean onCreateOptionsMenu(Menu menu) { 88 | // Inflate the menu; this adds items to the action bar if it is present. 89 | getMenuInflater().inflate(R.menu.menu_main, menu); 90 | return true; 91 | } 92 | 93 | @Override 94 | public boolean onOptionsItemSelected(MenuItem item) { 95 | // Handle action bar item clicks here. The action bar will 96 | // automatically handle clicks on the Home/Up button, so long 97 | // as you specify a parent activity in AndroidManifest.xml. 98 | int id = item.getItemId(); 99 | 100 | //noinspection SimplifiableIfStatement 101 | if (id == R.id.action_settings) { 102 | return true; 103 | } 104 | 105 | return super.onOptionsItemSelected(item); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /app/src/main/java/com/xw/samlpe/bubbleseekbar/ObservableScrollView.java: -------------------------------------------------------------------------------- 1 | package com.xw.samlpe.bubbleseekbar; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.MotionEvent; 6 | import android.widget.ScrollView; 7 | 8 | public class ObservableScrollView extends ScrollView { 9 | 10 | private OnScrollChangedListener mOnScrollChangedListener; 11 | 12 | public ObservableScrollView(Context context) { 13 | super(context); 14 | } 15 | 16 | public ObservableScrollView(Context context, AttributeSet attrs, int defStyle) { 17 | super(context, attrs, defStyle); 18 | } 19 | 20 | public ObservableScrollView(Context context, AttributeSet attrs) { 21 | super(context, attrs); 22 | } 23 | 24 | public void setOnScrollChangedListener(OnScrollChangedListener onScrollChangedListener) { 25 | this.mOnScrollChangedListener = onScrollChangedListener; 26 | } 27 | 28 | @Override 29 | protected void onScrollChanged(int x, int y, int oldx, int oldy) { 30 | super.onScrollChanged(x, y, oldx, oldy); 31 | if (mOnScrollChangedListener != null) { 32 | mOnScrollChangedListener.onScrollChanged(this, x, y, oldx, oldy); 33 | } 34 | } 35 | 36 | @Override 37 | public boolean onInterceptTouchEvent(MotionEvent ev) { 38 | return false; // 此处为了演示,阻止ScrollView拦截Touch事件 39 | } 40 | 41 | interface OnScrollChangedListener { 42 | 43 | void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy); 44 | 45 | } 46 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_radio_text_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_divider_shadow.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_divider_vertical.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 22 | 23 | 27 | 28 | 37 | 38 | 48 | 49 | 58 | 59 | 68 | 69 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_demo_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 21 | 22 | 28 | 29 | 37 | 38 | 44 | 45 | 54 | 55 | 60 | 61 | 74 | 75 |