├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules-new.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── tistory │ │ └── dwfox │ │ └── dwrulerview │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── tistory │ │ │ └── dwfox │ │ │ └── dwrulerview │ │ │ └── MainActivity.java │ └── res │ │ ├── layout │ │ └── activity_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-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── tistory │ └── dwfox │ └── dwrulerview │ └── ExampleUnitTest.java ├── build.gradle ├── dwrulerviewlibrary ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── tistory │ │ └── dwfox │ │ └── dwrulerviewlibrary │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── tistory │ │ │ └── dwfox │ │ │ └── dwrulerviewlibrary │ │ │ ├── utils │ │ │ └── DWUtils.java │ │ │ └── view │ │ │ ├── DWRulerSeekbar.java │ │ │ ├── LineRulerView.java │ │ │ ├── ObservableHorizontalScrollView.java │ │ │ └── ScrollingValuePicker.java │ └── res │ │ ├── drawable │ │ └── indicator.png │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── tistory │ └── dwfox │ └── dwrulerviewlibrary │ └── ExampleUnitTest.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── projectFilesBackup └── .idea │ └── workspace.xml ├── screenshot ├── dwrulerview.gif ├── dwrulerview_s.gif ├── dwseekbar.gif └── youtube_image.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | DWRulerView -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 1.8 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 DWFOX 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-DWRulerView-brightgreen.svg?style=flat)](http://android-arsenal.com/details/1/4630) 2 | 3 | 4 | DWRulerView 5 | ========= 6 | [![Youtube](https://github.com/dwfox/DWRulerView/raw/master/screenshot/youtube_image.png)](http://www.youtube.com/watch?v=Udy_ThDo5kw) 7 | --- 8 | ### Demo 9 | - Ruler Number Picker & Ruler Seekbar 10 | 11 | 12 | ![Image](https://github.com/dwfox/DWRulerView/raw/master/screenshot/dwseekbar.gif) 13 | 14 | --- 15 | 16 | ### Usage 17 | - Ruler Number Picker 18 | ```java 19 | ScrollingValuePicker myScrollingValuePicker; 20 | myScrollingValuePicker = (ScrollingValuePicker) findViewById(R.id.myScrollingValuePicker); 21 | myScrollingValuePicker.setViewMultipleSize(LINE_RULER_MULTIPLE_SIZE); 22 | myScrollingValuePicker.setMaxValue(MIN_VALUE, MAX_VALUE); 23 | myScrollingValuePicker.setValueTypeMultiple(5); 24 | myScrollingValuePicker.getScrollView().setOnTouchListener(new View.OnTouchListener() { 25 | @Override 26 | public boolean onTouch(View v, MotionEvent event) { 27 | if (event.getAction() == MotionEvent.ACTION_UP) { 28 | myScrollingValuePicker.getScrollView().startScrollerTask(); 29 | } 30 | return false; 31 | } 32 | }); 33 | ``` 34 | 35 | - Ruler Seekbar 36 | ```java 37 | DWRulerSeekbar dwRulerSeekbar; 38 | dwRulerSeekbar = (DWRulerSeekbar) findViewById(R.id.dwRulerSeekbar); 39 | dwRulerSeekbar 40 | .setMinMaxValue((int) MIN_VALUE, (int) MAX_VALUE) 41 | //Get the value with the OnDWSeekbarListener 42 | .setDWRulerSeekbarListener(new DWRulerSeekbar.OnDWSeekBarListener() { 43 | @Override 44 | public void onStopSeekbarValue(int value) { 45 | seekbarText.setText("DWSeekBar Value : " + value); 46 | } 47 | }); 48 | ``` 49 | --- 50 | ### Get Value 51 | - Ruler Number Picker 52 | ```java 53 | myScrollingValuePicker.setOnScrollChangedListener(new ObservableHorizontalScrollView.OnScrollChangedListener() { 54 | 55 | @Override 56 | public void onScrollChanged(ObservableHorizontalScrollView view, int l, int t) {} 57 | 58 | @Override 59 | public void onScrollStopped(int l, int t) { 60 | text.setText("Value STOP : " + DWUtils.getValueAndScrollItemToCenter(myScrollingValuePicker.getScrollView() // set TextView 61 | , l 62 | , t 63 | , MAX_VALUE 64 | , MIN_VALUE 65 | , myScrollingValuePicker.getViewMultipleSize())); 66 | } 67 | }); 68 | ``` 69 | --- 70 | ### Gradle 71 | 72 | ```groovy 73 | allprojects { 74 | repositories { 75 | ... 76 | maven { url "https://jitpack.io" } 77 | } 78 | } 79 | ``` 80 | 81 | ```groovy 82 | dependencies { 83 | compile 'com.github.dwfox:DWRulerView:1.1.0' 84 | } 85 | ``` 86 | --- 87 | ### More Usage 88 | More Usage Here [[link](http://dwfox.tistory.com/50)] 89 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion "24.0.2" 6 | 7 | defaultConfig { 8 | applicationId "com.tistory.dwfox.dwrulerview" 9 | minSdkVersion 19 10 | targetSdkVersion 24 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | debug { 20 | minifyEnabled true 21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'proguard-rules-new.pro' 22 | } 23 | } 24 | } 25 | 26 | dependencies { 27 | compile fileTree(include: ['*.jar'], dir: 'libs') 28 | testCompile 'junit:junit:4.12' 29 | compile 'com.android.support:appcompat-v7:24.2.0' 30 | compile project(':dwrulerviewlibrary') 31 | } 32 | -------------------------------------------------------------------------------- /app/proguard-rules-new.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\DW\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -keepclassmembers class com.tistory.dwfox.dwrulerview.TestClass { 19 | public *; 20 | } 21 | -------------------------------------------------------------------------------- /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 C:\Users\DW\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/tistory/dwfox/dwrulerview/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.tistory.dwfox.dwrulerview; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/tistory/dwfox/dwrulerview/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.tistory.dwfox.dwrulerview; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.view.MotionEvent; 6 | import android.view.View; 7 | import android.widget.TextView; 8 | 9 | import com.tistory.dwfox.dwrulerviewlibrary.utils.DWUtils; 10 | import com.tistory.dwfox.dwrulerviewlibrary.view.DWRulerSeekbar; 11 | import com.tistory.dwfox.dwrulerviewlibrary.view.ObservableHorizontalScrollView; 12 | import com.tistory.dwfox.dwrulerviewlibrary.view.ScrollingValuePicker; 13 | 14 | public class MainActivity extends AppCompatActivity { 15 | 16 | private ScrollingValuePicker myScrollingValuePicker; 17 | private DWRulerSeekbar dwRulerSeekbar; 18 | 19 | private static final float MIN_VALUE = 5; 20 | private static final float MAX_VALUE = 33; 21 | private static final float LINE_RULER_MULTIPLE_SIZE = 3.5f; 22 | private TextView rulerText; 23 | private TextView seekbarText; 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.activity_main); 29 | 30 | rulerText = (TextView) findViewById(R.id.rulerview_value); 31 | seekbarText = (TextView) findViewById(R.id.seekbar_value); 32 | 33 | initRulerView(); 34 | initDWSeekbar(); 35 | } 36 | 37 | /** 38 | * initRulerView 39 | */ 40 | private void initRulerView() { 41 | myScrollingValuePicker = (ScrollingValuePicker) findViewById(R.id.myScrollingValuePicker); 42 | myScrollingValuePicker.setViewMultipleSize(LINE_RULER_MULTIPLE_SIZE); 43 | myScrollingValuePicker.setMaxValue(MIN_VALUE, MAX_VALUE); 44 | myScrollingValuePicker.setValueTypeMultiple(5); 45 | myScrollingValuePicker.getScrollView().setOnTouchListener(new View.OnTouchListener() { 46 | @Override 47 | public boolean onTouch(View v, MotionEvent event) { 48 | if (event.getAction() == MotionEvent.ACTION_UP) { 49 | myScrollingValuePicker.getScrollView().startScrollerTask(); 50 | } 51 | return false; 52 | } 53 | }); 54 | 55 | myScrollingValuePicker.setOnScrollChangedListener(new ObservableHorizontalScrollView.OnScrollChangedListener() { 56 | 57 | @Override 58 | public void onScrollChanged(ObservableHorizontalScrollView view, int l, int t) { 59 | } 60 | 61 | @Override 62 | public void onScrollStopped(int l, int t) { 63 | rulerText.setText("DWRulerView Value : " + 64 | DWUtils.getValueAndScrollItemToCenter(myScrollingValuePicker.getScrollView() 65 | , l 66 | , t 67 | , MAX_VALUE 68 | , MIN_VALUE 69 | , myScrollingValuePicker.getViewMultipleSize())); 70 | } 71 | }); 72 | } 73 | 74 | /** 75 | * initDWSeekbar 76 | */ 77 | private void initDWSeekbar() { 78 | dwRulerSeekbar = (DWRulerSeekbar) findViewById(R.id.dwRulerSeekbar); 79 | dwRulerSeekbar 80 | .setMinMaxValue((int) MIN_VALUE, (int) MAX_VALUE) 81 | .setDWRulerSeekbarListener(new DWRulerSeekbar.OnDWSeekBarListener() { 82 | @Override 83 | public void onStopSeekbarValue(int value) { 84 | seekbarText.setText("DWSeekBar Value : " + value); 85 | } 86 | }); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 20 | 21 | 32 | 33 | 39 | 40 | 46 | 47 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwfox/DWRulerView/4de51a1c112e9cf0cac13b3d1dc873f2e0d5c1e0/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwfox/DWRulerView/4de51a1c112e9cf0cac13b3d1dc873f2e0d5c1e0/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwfox/DWRulerView/4de51a1c112e9cf0cac13b3d1dc873f2e0d5c1e0/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwfox/DWRulerView/4de51a1c112e9cf0cac13b3d1dc873f2e0d5c1e0/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwfox/DWRulerView/4de51a1c112e9cf0cac13b3d1dc873f2e0d5c1e0/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | DWRulerView 3 | https://github.com/dwfox/DWRulerView 4 | http://dwfox.tistory.com/50 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/com/tistory/dwfox/dwrulerview/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.tistory.dwfox.dwrulerview; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | maven { url "https://jitpack.io" } 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:2.2.3' 10 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' 11 | // NOTE: Do not place your application dependencies here; they belong 12 | // in the individual module build.gradle files 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | jcenter() 19 | } 20 | } 21 | 22 | task clean(type: Delete) { 23 | delete rootProject.buildDir 24 | } 25 | -------------------------------------------------------------------------------- /dwrulerviewlibrary/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /dwrulerviewlibrary/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | 4 | group='com.github.dwfox' 5 | 6 | android { 7 | compileSdkVersion 24 8 | buildToolsVersion "24.0.2" 9 | 10 | defaultConfig { 11 | minSdkVersion 19 12 | targetSdkVersion 24 13 | versionCode 1 14 | versionName "1.0" 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | 22 | release { 23 | minifyEnabled false 24 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 25 | } 26 | } 27 | } 28 | 29 | dependencies { 30 | compile fileTree(dir: 'libs', include: ['*.jar']) 31 | testCompile 'junit:junit:4.12' 32 | compile 'com.android.support:appcompat-v7:24.2.0' 33 | } 34 | -------------------------------------------------------------------------------- /dwrulerviewlibrary/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 C:\Users\DW\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | 20 | -keepclassmembers class com.tistory.dwfox.dwrulerviewlibrary.view.LineRulerView { 21 | public *; 22 | } -------------------------------------------------------------------------------- /dwrulerviewlibrary/src/androidTest/java/com/tistory/dwfox/dwrulerviewlibrary/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.tistory.dwfox.dwrulerviewlibrary; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /dwrulerviewlibrary/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /dwrulerviewlibrary/src/main/java/com/tistory/dwfox/dwrulerviewlibrary/utils/DWUtils.java: -------------------------------------------------------------------------------- 1 | package com.tistory.dwfox.dwrulerviewlibrary.utils; 2 | 3 | import android.content.Context; 4 | 5 | import com.tistory.dwfox.dwrulerviewlibrary.view.ObservableHorizontalScrollView; 6 | 7 | /** 8 | * Created by Administrator on 2015-10-20. 9 | */ 10 | public class DWUtils { 11 | 12 | public static int dip2px(Context context, float dipValue) { 13 | final float scale = context.getResources().getDisplayMetrics().density; 14 | return (int) (dipValue * scale + 0.5f); 15 | } 16 | 17 | public static int px2dip(Context context, float pxValue) { 18 | final float scale = context.getResources().getDisplayMetrics().density; 19 | return (int) (pxValue / scale + 0.5f); 20 | } 21 | 22 | public static int sp2px(Context context, float spValue) { 23 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 24 | return (int) (spValue * fontScale + 0.5f); 25 | } 26 | 27 | public static float getRulerViewValue(ObservableHorizontalScrollView view, int l, int t, float MAX_VALUE, float MIN_VALUE) { 28 | 29 | float oneValue = (float) view.getWidth() * 3f / (MAX_VALUE - MIN_VALUE); 30 | int value = (int) (l / oneValue) + (int) MIN_VALUE; 31 | 32 | if (value > (MAX_VALUE)) value = (int) MAX_VALUE; 33 | else if (value < MIN_VALUE) value = (int) MIN_VALUE; 34 | 35 | return value; 36 | } 37 | 38 | 39 | public static int getValueAndScrollItemToCenter(ObservableHorizontalScrollView view, int l, int t, float MAX_VALUE, float MIN_VALUE, float multipleSize) { 40 | return getValueAndScrollItemToCenter(view, l, t, MAX_VALUE, MIN_VALUE, multipleSize, 1); 41 | } 42 | 43 | public static int getValueAndScrollItemToCenter(ObservableHorizontalScrollView view, int l, int t, float MAX_VALUE, float MIN_VALUE, float multipleSize, int valueMultiple) { 44 | float oneValue = (float) view.getWidth() * multipleSize / (MAX_VALUE - MIN_VALUE); 45 | int value = (int) (l / oneValue) + (int) MIN_VALUE; 46 | int offset = (int) (l % oneValue); 47 | 48 | 49 | if (offset > oneValue / 2) { 50 | value += 1; 51 | view.smoothScrollBy((int) oneValue - offset, 0); 52 | 53 | } else { 54 | view.smoothScrollBy(-offset, 0); 55 | } 56 | 57 | if (value > MAX_VALUE) { 58 | value = (int) MAX_VALUE; 59 | } 60 | 61 | return value * valueMultiple; 62 | } 63 | 64 | public static void scrollToValue(ObservableHorizontalScrollView view, float value, float MAX_VALUE, float MIN_VALUE, float multipleSize) { 65 | float oneValue = (float) view.getWidth() * multipleSize / (MAX_VALUE - MIN_VALUE); 66 | float valueWidth = oneValue * (value - MIN_VALUE); 67 | 68 | view.scrollBy((int) valueWidth, 0); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /dwrulerviewlibrary/src/main/java/com/tistory/dwfox/dwrulerviewlibrary/view/DWRulerSeekbar.java: -------------------------------------------------------------------------------- 1 | package com.tistory.dwfox.dwrulerviewlibrary.view; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Color; 7 | import android.graphics.drawable.BitmapDrawable; 8 | import android.graphics.drawable.Drawable; 9 | import android.os.Build; 10 | import android.support.annotation.RequiresApi; 11 | import android.util.AttributeSet; 12 | import android.view.ViewGroup; 13 | import android.view.ViewTreeObserver; 14 | import android.widget.RelativeLayout; 15 | import android.widget.SeekBar; 16 | 17 | import com.tistory.dwfox.dwrulerviewlibrary.R; 18 | 19 | /** 20 | * Created by DW on 2016-11-14. 21 | */ 22 | 23 | 24 | public class DWRulerSeekbar extends RelativeLayout implements SeekBar.OnSeekBarChangeListener { 25 | 26 | private int seekbarMinValue = 0; 27 | private int seekbarMaxValue = 50; 28 | 29 | private SeekBar seekBar; 30 | private Context context; 31 | 32 | private OnDWSeekBarListener listener; 33 | 34 | public interface OnDWSeekBarListener { 35 | public void onStopSeekbarValue(int value); 36 | } 37 | 38 | public DWRulerSeekbar(Context context) { 39 | super(context); 40 | this.context = context; 41 | init(); 42 | } 43 | 44 | public DWRulerSeekbar(Context context, AttributeSet attrs) { 45 | super(context, attrs); 46 | this.context = context; 47 | init(); 48 | } 49 | 50 | public DWRulerSeekbar(Context context, AttributeSet attrs, int defStyleAttr) { 51 | super(context, attrs, defStyleAttr); 52 | this.context = context; 53 | init(); 54 | } 55 | 56 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 57 | public DWRulerSeekbar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 58 | super(context, attrs, defStyleAttr, defStyleRes); 59 | this.context = context; 60 | init(); 61 | } 62 | 63 | 64 | private void init() { 65 | 66 | getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { 67 | @Override 68 | public boolean onPreDraw() { 69 | if (getHeight() > 0) { 70 | addCompoenet(); 71 | getViewTreeObserver().removeOnPreDrawListener(this); 72 | } 73 | return false; 74 | } 75 | }); 76 | } 77 | 78 | private void addCompoenet() { 79 | removeAllViews(); 80 | LineRulerView lineRulerView = new LineRulerView(context); 81 | LayoutParams rulerLayoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getHeight() / 3 * 2); 82 | rulerLayoutParams.addRule(ALIGN_PARENT_BOTTOM); 83 | lineRulerView.setLayoutParams(rulerLayoutParams); 84 | lineRulerView.setMinMaxValue(seekbarMinValue, seekbarMaxValue + 1); 85 | lineRulerView.setBackgroundColor(Color.DKGRAY); 86 | addView(lineRulerView); 87 | 88 | seekBar = new SeekBar(context); 89 | LayoutParams seekbarLayoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getHeight() / 3); 90 | seekbarLayoutParams.addRule(ALIGN_PARENT_TOP); 91 | seekBar.setLayoutParams(seekbarLayoutParams); 92 | seekBar.setBackgroundColor(Color.DKGRAY); 93 | seekBar.setProgressDrawable(null); 94 | seekBar.setPadding(0, 0, 0, 0); 95 | seekBar.setOnSeekBarChangeListener(this); 96 | seekBar.setMax(seekbarMaxValue - seekbarMinValue + 1); 97 | setSeekberThumb(seekBar, context.getResources()); 98 | addView(seekBar); 99 | } 100 | 101 | private void setSeekberThumb(final SeekBar seekBar, final Resources res) { 102 | seekBar.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { 103 | @Override 104 | public boolean onPreDraw() { 105 | if (seekBar.getHeight() > 0) { 106 | Drawable thumb = res.getDrawable(R.drawable.indicator); 107 | int h = seekBar.getMeasuredHeight(); 108 | int w = h; 109 | Bitmap bmpOrg = ((BitmapDrawable) thumb).getBitmap(); 110 | Bitmap bmpScaled = Bitmap.createScaledBitmap(bmpOrg, w, h, true); 111 | Drawable newThumb = new BitmapDrawable(res, bmpScaled); 112 | newThumb.setBounds(0, 0, newThumb.getIntrinsicWidth(), newThumb.getIntrinsicHeight()); 113 | seekBar.setThumb(newThumb); 114 | seekBar.getViewTreeObserver().removeOnPreDrawListener(this); 115 | } 116 | return true; 117 | } 118 | }); 119 | } 120 | 121 | public DWRulerSeekbar setDWRulerSeekbarListener(OnDWSeekBarListener listener) { 122 | this.listener = listener; 123 | return this; 124 | } 125 | 126 | public DWRulerSeekbar setMinMaxValue(int seekbarMinValue, int seekbarMaxValue) { 127 | this.seekbarMinValue = seekbarMinValue; 128 | this.seekbarMaxValue = seekbarMaxValue; 129 | addCompoenet(); 130 | return this; 131 | } 132 | 133 | @Override 134 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 135 | if (listener != null) { 136 | listener.onStopSeekbarValue(seekbarMinValue + progress); 137 | } 138 | } 139 | 140 | @Override 141 | public void onStartTrackingTouch(SeekBar seekBar) { 142 | 143 | } 144 | 145 | @Override 146 | public void onStopTrackingTouch(SeekBar seekBar) { 147 | 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /dwrulerviewlibrary/src/main/java/com/tistory/dwfox/dwrulerviewlibrary/view/LineRulerView.java: -------------------------------------------------------------------------------- 1 | package com.tistory.dwfox.dwrulerviewlibrary.view; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.Context; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.DashPathEffect; 8 | import android.graphics.Paint; 9 | import android.graphics.Path; 10 | import android.os.Build; 11 | import android.util.AttributeSet; 12 | import android.util.Log; 13 | import android.view.View; 14 | 15 | import com.tistory.dwfox.dwrulerviewlibrary.utils.DWUtils; 16 | 17 | /** 18 | * Created by DWFOX on 2016-08-31. 19 | */ 20 | 21 | public class LineRulerView extends View { 22 | 23 | private Paint paint; 24 | private Paint textPaint; 25 | private DashPathEffect dashPathEffect; 26 | private Path backGroundPath; 27 | 28 | private float bigUnitLineHeight = 0f; 29 | private float samllUnitLineHeight = 0f; 30 | 31 | private float MAX_DATA = 100; 32 | private float MIN_DATA = 0; 33 | 34 | private int viewHeight = 0; 35 | private int viewWidth = 0; 36 | 37 | private int showRangeValue = 5; 38 | 39 | private int valueMultiple = 1; 40 | 41 | // 1 5개마다 ( Default) 42 | // 2 특정 배수 마다 43 | private int displayNumberType = 1; 44 | 45 | public static final int DISPLAY_NUMBER_TYPE_SPACIAL_COUNT = 1; 46 | public static final int DISPLAY_NUMBER_TYPE_MULTIPLE = 2; 47 | private int valueTypeMultiple = 5; 48 | 49 | private int longHeightRatio = 10; 50 | private int shortHeightRatio = 5; 51 | private int baseHeightRatio = 3; 52 | 53 | 54 | public LineRulerView(Context context) { 55 | super(context); 56 | init(context); 57 | } 58 | 59 | public LineRulerView(Context context, AttributeSet attrs) { 60 | super(context, attrs); 61 | init(context); 62 | } 63 | 64 | public LineRulerView(Context context, AttributeSet attrs, int defStyleAttr) { 65 | super(context, attrs, defStyleAttr); 66 | init(context); 67 | } 68 | 69 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 70 | public LineRulerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 71 | super(context, attrs, defStyleAttr, defStyleRes); 72 | init(context); 73 | } 74 | 75 | private void init(Context context) { 76 | paint = new Paint(); 77 | paint.setColor(Color.parseColor("#ffffff")); 78 | paint.setStrokeWidth(5f); 79 | paint.isAntiAlias(); 80 | paint.setStyle(Paint.Style.STROKE); 81 | 82 | textPaint = new Paint(); 83 | textPaint.setColor(0xFFFFFFFF); 84 | textPaint.isAntiAlias(); 85 | textPaint.setTextSize(DWUtils.sp2px(context, 14)); 86 | textPaint.setTextAlign(Paint.Align.CENTER); 87 | 88 | invalidate(); 89 | } 90 | 91 | public LineRulerView setMaxValue(float maxValue) { 92 | this.MAX_DATA = maxValue; 93 | return this; 94 | } 95 | 96 | public LineRulerView setMinValue(float minValue) { 97 | this.MIN_DATA = minValue; 98 | return this; 99 | } 100 | 101 | public LineRulerView setMinMaxValue(float minValue, float maxValue) { 102 | this.MIN_DATA = minValue; 103 | this.MAX_DATA = maxValue; 104 | return this; 105 | } 106 | 107 | public LineRulerView setValueMultiple(int valueMultiple) { 108 | this.valueMultiple = valueMultiple; 109 | return this; 110 | } 111 | 112 | public void setMultipleTypeValue(int valueTypeMultiple) { 113 | this.displayNumberType = DISPLAY_NUMBER_TYPE_MULTIPLE; 114 | this.valueTypeMultiple = valueTypeMultiple; 115 | } 116 | 117 | 118 | @Override 119 | protected void onDraw(Canvas canvas) { 120 | viewHeight = getMeasuredHeight(); 121 | viewWidth = getMeasuredWidth(); 122 | 123 | float viewInterval = (float) viewWidth / (MAX_DATA - MIN_DATA); 124 | canvas.drawLine(0, 0, 0, viewHeight / longHeightRatio * baseHeightRatio, paint); 125 | 126 | for (int i = 1; i < (MAX_DATA - MIN_DATA); i++) { 127 | if (displayNumberType == DISPLAY_NUMBER_TYPE_MULTIPLE) { 128 | 129 | if (((int) (i + MIN_DATA) * valueMultiple) % valueTypeMultiple == 0) { 130 | canvas.drawLine(viewInterval * i, 0, viewInterval * i, viewHeight / shortHeightRatio * baseHeightRatio, paint); 131 | canvas.drawText("" + ((int) (i + MIN_DATA) * valueMultiple), viewInterval * i, viewHeight / shortHeightRatio * baseHeightRatio + DWUtils.sp2px(getContext(), 14), textPaint); 132 | } else { 133 | canvas.drawLine(viewInterval * i, 0, viewInterval * i, viewHeight / longHeightRatio * baseHeightRatio, paint); 134 | } 135 | 136 | } else { 137 | if (i % 5 == 0) { 138 | canvas.drawLine(viewInterval * i, 0, viewInterval * i, viewHeight / shortHeightRatio * baseHeightRatio, paint); 139 | canvas.drawText("" + ((int) (i + MIN_DATA) * valueMultiple), viewInterval * i, viewHeight / shortHeightRatio * baseHeightRatio + DWUtils.sp2px(getContext(), 14), textPaint); 140 | } else { 141 | canvas.drawLine(viewInterval * i, 0, viewInterval * i, viewHeight / longHeightRatio * baseHeightRatio, paint); 142 | } 143 | } 144 | } 145 | canvas.drawLine(viewWidth, 0, viewWidth, viewHeight / longHeightRatio * baseHeightRatio, paint); 146 | 147 | super.onDraw(canvas); 148 | } 149 | } 150 | 151 | -------------------------------------------------------------------------------- /dwrulerviewlibrary/src/main/java/com/tistory/dwfox/dwrulerviewlibrary/view/ObservableHorizontalScrollView.java: -------------------------------------------------------------------------------- 1 | package com.tistory.dwfox.dwrulerviewlibrary.view; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.Context; 5 | import android.os.Build; 6 | import android.util.AttributeSet; 7 | import android.widget.HorizontalScrollView; 8 | 9 | /** 10 | * Created by DWFOX on 2016-09-01. 11 | */ 12 | public class ObservableHorizontalScrollView extends HorizontalScrollView { 13 | 14 | private Runnable scrollerTask; 15 | private int initialPosition; 16 | 17 | private int newCheck = 100; 18 | 19 | private float initValue = 0f; 20 | 21 | public interface OnScrollChangedListener { 22 | void onScrollChanged(ObservableHorizontalScrollView view, int l, int t); 23 | 24 | void onScrollStopped(int l, int t); 25 | } 26 | 27 | 28 | private OnScrollChangedListener mOnScrollChangedListener; 29 | 30 | public ObservableHorizontalScrollView(Context context) { 31 | super(context); 32 | init(); 33 | } 34 | 35 | public ObservableHorizontalScrollView(Context context, AttributeSet attrs) { 36 | super(context, attrs); 37 | init(); 38 | } 39 | 40 | public ObservableHorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr) { 41 | super(context, attrs, defStyleAttr); 42 | init(); 43 | } 44 | 45 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 46 | public ObservableHorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 47 | super(context, attrs, defStyleAttr, defStyleRes); 48 | init(); 49 | } 50 | 51 | 52 | public void setOnScrollChangedListener(OnScrollChangedListener l) { 53 | mOnScrollChangedListener = l; 54 | } 55 | 56 | 57 | private void init() { 58 | scrollerTask = new Runnable() { 59 | public void run() { 60 | 61 | int newPosition = getScrollX(); 62 | if (initialPosition - newPosition == 0) {//has stopped 63 | 64 | if (mOnScrollChangedListener != null) { 65 | mOnScrollChangedListener.onScrollStopped(getScrollX(), getScrollY()); 66 | } 67 | } else { 68 | initialPosition = getScrollX(); 69 | ObservableHorizontalScrollView.this.postDelayed(scrollerTask, newCheck); 70 | } 71 | } 72 | }; 73 | } 74 | 75 | 76 | @Override 77 | protected void onScrollChanged(int l, int t, int oldl, int oldt) { 78 | super.onScrollChanged(l, t, oldl, oldt); 79 | if (mOnScrollChangedListener != null) { 80 | mOnScrollChangedListener.onScrollChanged(this, l, t); 81 | } 82 | } 83 | 84 | public void startScrollerTask() { 85 | 86 | initialPosition = getScrollY(); 87 | ObservableHorizontalScrollView.this.postDelayed(scrollerTask, newCheck); 88 | } 89 | } 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /dwrulerviewlibrary/src/main/java/com/tistory/dwfox/dwrulerviewlibrary/view/ScrollingValuePicker.java: -------------------------------------------------------------------------------- 1 | package com.tistory.dwfox.dwrulerviewlibrary.view; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.Context; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.graphics.Path; 9 | import android.os.Build; 10 | import android.util.AttributeSet; 11 | import android.util.Log; 12 | import android.view.View; 13 | import android.view.ViewGroup; 14 | import android.view.ViewTreeObserver; 15 | import android.widget.FrameLayout; 16 | import android.widget.LinearLayout; 17 | 18 | import com.tistory.dwfox.dwrulerviewlibrary.utils.DWUtils; 19 | 20 | 21 | /** 22 | * Created by DWFOX on 2016-09-01. 23 | */ 24 | public class ScrollingValuePicker extends FrameLayout { 25 | 26 | private View mLeftSpacer; 27 | private View mRightSpacer; 28 | private LineRulerView lineRulerView; 29 | private ObservableHorizontalScrollView mScrollView; 30 | private float viewMultipleSize = 3f; 31 | 32 | private float maxValue = 0; 33 | private float minValue = 0; 34 | 35 | private float initValue = 0f; 36 | 37 | private int valueMultiple = 1; 38 | 39 | private int valueTypeMultiple = 5; 40 | 41 | public ScrollingValuePicker(Context context) { 42 | super(context); 43 | init(context); 44 | } 45 | 46 | public ScrollingValuePicker(Context context, AttributeSet attrs) { 47 | super(context, attrs); 48 | init(context); 49 | } 50 | 51 | public ScrollingValuePicker(Context context, AttributeSet attrs, int defStyleAttr) { 52 | super(context, attrs, defStyleAttr); 53 | init(context); 54 | } 55 | 56 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 57 | public ScrollingValuePicker(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 58 | super(context, attrs, defStyleAttr, defStyleRes); 59 | init(context); 60 | } 61 | 62 | public void setOnScrollChangedListener(final ObservableHorizontalScrollView.OnScrollChangedListener onScrollChangedListener) { 63 | mScrollView.setOnScrollChangedListener(onScrollChangedListener); 64 | } 65 | 66 | public void setMaxValue(float minValue, float maxValue) { 67 | setMaxValue(minValue, maxValue, 1); 68 | } 69 | 70 | public void setMaxValue(float minValue, float maxValue, int valueMultiple) { 71 | this.minValue = minValue; 72 | this.maxValue = maxValue; 73 | this.valueMultiple = valueMultiple; 74 | lineRulerView.setMaxValue(this.maxValue); 75 | lineRulerView.setMinValue(this.minValue); 76 | lineRulerView.setValueMultiple(this.valueMultiple); 77 | } 78 | 79 | public void setValueTypeMultiple(int valueTypeMultiple) { 80 | this.valueMultiple = valueTypeMultiple; 81 | lineRulerView.setMultipleTypeValue(valueTypeMultiple); 82 | } 83 | 84 | public void setViewMultipleSize(float size) { 85 | this.viewMultipleSize = size; 86 | } 87 | 88 | public void setInitValue(float initValue) { 89 | this.initValue = initValue; 90 | } 91 | 92 | public float getViewMultipleSize() { 93 | return this.viewMultipleSize; 94 | } 95 | 96 | 97 | private void init(Context context) { 98 | mScrollView = new ObservableHorizontalScrollView(context); 99 | mScrollView.setHorizontalScrollBarEnabled(false); 100 | addView(mScrollView); 101 | 102 | final LinearLayout container = new LinearLayout(context); 103 | mScrollView.addView(container); 104 | 105 | mLeftSpacer = new View(context); 106 | mRightSpacer = new View(context); 107 | 108 | lineRulerView = new LineRulerView(context); 109 | container.addView(lineRulerView); 110 | container.addView(mLeftSpacer, 0); 111 | container.addView(mRightSpacer); 112 | 113 | 114 | getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 115 | @Override 116 | public void onGlobalLayout() { 117 | if (getWidth() != 0) { 118 | DWUtils.scrollToValue(getScrollView(), initValue, maxValue, minValue, viewMultipleSize); 119 | getViewTreeObserver().removeOnGlobalLayoutListener(this); 120 | } 121 | } 122 | }); 123 | 124 | } 125 | 126 | public ObservableHorizontalScrollView getScrollView() { 127 | return mScrollView; 128 | } 129 | 130 | @Override 131 | protected void onDraw(Canvas canvas) { 132 | 133 | Paint paint = new Paint(); 134 | paint.setColor(Color.parseColor("#ffffff")); 135 | paint.setStrokeWidth(5f); 136 | paint.setStyle(Paint.Style.FILL_AND_STROKE); 137 | 138 | Path path = new Path(); 139 | path.moveTo(getWidth() / 2 - 30, 0); 140 | path.lineTo(getWidth() / 2, 40); 141 | path.lineTo(getWidth() / 2 + 30, 0); 142 | canvas.drawPath(path, paint); 143 | super.onDraw(canvas); 144 | } 145 | 146 | @Override 147 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 148 | super.onLayout(changed, left, top, right, bottom); 149 | 150 | if (changed) { 151 | 152 | final int width = getWidth(); 153 | 154 | final ViewGroup.LayoutParams leftParams = mLeftSpacer.getLayoutParams(); 155 | leftParams.width = width / 2; 156 | mLeftSpacer.setLayoutParams(leftParams); 157 | 158 | final ViewGroup.LayoutParams rulerViewParams = lineRulerView.getLayoutParams(); 159 | rulerViewParams.width = (int) (width * viewMultipleSize); // set RulerView Width 160 | lineRulerView.setLayoutParams(rulerViewParams); 161 | lineRulerView.invalidate(); 162 | 163 | 164 | final ViewGroup.LayoutParams rightParams = mRightSpacer.getLayoutParams(); 165 | rightParams.width = width / 2; 166 | mRightSpacer.setLayoutParams(rightParams); 167 | 168 | invalidate(); 169 | 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /dwrulerviewlibrary/src/main/res/drawable/indicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwfox/DWRulerView/4de51a1c112e9cf0cac13b3d1dc873f2e0d5c1e0/dwrulerviewlibrary/src/main/res/drawable/indicator.png -------------------------------------------------------------------------------- /dwrulerviewlibrary/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | DWRulerViewLibrary 3 | 4 | -------------------------------------------------------------------------------- /dwrulerviewlibrary/src/test/java/com/tistory/dwfox/dwrulerviewlibrary/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.tistory.dwfox.dwrulerviewlibrary; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwfox/DWRulerView/4de51a1c112e9cf0cac13b3d1dc873f2e0d5c1e0/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Sep 05 14:34:01 KST 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 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /screenshot/dwrulerview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwfox/DWRulerView/4de51a1c112e9cf0cac13b3d1dc873f2e0d5c1e0/screenshot/dwrulerview.gif -------------------------------------------------------------------------------- /screenshot/dwrulerview_s.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwfox/DWRulerView/4de51a1c112e9cf0cac13b3d1dc873f2e0d5c1e0/screenshot/dwrulerview_s.gif -------------------------------------------------------------------------------- /screenshot/dwseekbar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwfox/DWRulerView/4de51a1c112e9cf0cac13b3d1dc873f2e0d5c1e0/screenshot/dwseekbar.gif -------------------------------------------------------------------------------- /screenshot/youtube_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwfox/DWRulerView/4de51a1c112e9cf0cac13b3d1dc873f2e0d5c1e0/screenshot/youtube_image.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':dwrulerviewlibrary' 2 | --------------------------------------------------------------------------------