├── .gitignore
├── .idea
└── vcs.xml
├── README.MD
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── xk
│ │ └── sanjay
│ │ └── rulerview
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── xk
│ │ │ └── sanjay
│ │ │ └── rulerview
│ │ │ └── MainActivity.java
│ └── res
│ │ ├── layout
│ │ └── activity_main.xml
│ │ ├── menu
│ │ └── menu_main.xml
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── icon_arrow.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── values-v21
│ │ └── styles.xml
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── arrays.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── xk
│ └── sanjay
│ └── rulerview
│ └── ExampleUnitTest.java
├── art
├── demo.png
├── demo3.png
└── demo_up_half.png
├── build.gradle
├── gradle.properties
├── gradlew
├── gradlew.bat
├── rulberview
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── xk
│ │ └── sanjay
│ │ └── rulberview
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── xk
│ │ │ └── sanjay
│ │ │ └── rulberview
│ │ │ ├── RulerWheel.java
│ │ │ └── WheelHorizontalScroller.java
│ └── res
│ │ ├── drawable-xxhdpi
│ │ ├── ruler_mid_arraw.png
│ │ └── ruler_mid_arraw_down.png
│ │ └── values
│ │ ├── arrays.xml
│ │ ├── attrs_ruler.xml
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── xk
│ └── sanjay
│ └── rulberview
│ └── ExampleUnitTest.java
└── 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/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.MD:
--------------------------------------------------------------------------------
1 |
2 | # 介绍
3 |
4 |
5 | 这是一个水平的尺子滚轮插件
6 |
7 | ##上对齐+显示效果
8 |
9 | 
10 |
11 | ##上对齐+折半显示效果
12 |
13 | 
14 |
15 | ## 渐显效果
16 |
17 | 
18 |
19 | #特性
20 |
21 | 1. 支持定义字体的大小和颜色和是否显示刻度值
22 | 2. 支持定义各个刻度的颜色和大小,目前有大,中,小三者,如图片所示,有最大的是黑色,中等的为绿色,最小的是蓝色。同时刻度间隔和刻度的大小可以调节。
23 | 3. 支持自定义中间的指标器。
24 | 4. 可以有上和下,两种对齐的方式。
25 | 5. 支持指定默认值。
26 | 6. 支持设置最大和最小值。
27 | 7. 两种刻度格式SCALE和HALF,前者为有10格刻度,后者为只有0.5一格小的刻度。参考图片
28 | 8. 刻度尺的渐显效果
29 | 9. 支持显示自定义的数据!
30 | 10. 刻度值支持渐现的效果
31 | 11. 加入代码控制选中数据部分内容。
32 |
33 |
34 | # 考虑加入的新特性
35 |
36 | 1. 支持修改文字和刻度的间距定制
37 |
38 |
39 | # 使用方法
40 |
41 | ## XML 默认方式
42 |
43 |
44 |
73 |
74 |
75 | ## Activity
76 |
77 | rulerView = (RulerWheel) findViewById(R.id.ruler_view);
78 | rulerView.setScrollingListener(new RulerWheel.OnWheelScrollListener() {
79 | @Override
80 | public void onChanged(RulerWheel wheel, int oldValue, int newValue) {
81 | Log.e(TAG, "curValue=" + newValue);
82 | }
83 |
84 | @Override
85 | public void onScrollingStarted(RulerWheel wheel) {
86 |
87 | }
88 |
89 | @Override
90 | public void onScrollingFinished(RulerWheel wheel) {
91 |
92 | }
93 | });
94 |
95 | # 鸣谢
96 | 特别感谢[獨行Zz](http://blog.csdn.net/dashu8193058/article/details/45846189),这个项目是在他基础上改的。
97 |
98 | 还有需要别的欢迎在这个基础自己定制
99 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.2"
6 |
7 | defaultConfig {
8 | applicationId "com.xk.sanjay.rulerview"
9 | minSdkVersion 15
10 | targetSdkVersion 23
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 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | testCompile 'junit:junit:4.12'
25 | compile 'com.android.support:appcompat-v7:23.1.1'
26 | compile 'com.android.support:design:23.1.1'
27 | compile project(path: ':rulberview')
28 | }
29 |
--------------------------------------------------------------------------------
/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 F:\devel\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/xk/sanjay/rulerview/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.xk.sanjay.rulerview;
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 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xk/sanjay/rulerview/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.xk.sanjay.rulerview;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.widget.TextView;
6 |
7 | import com.xk.sanjay.rulberview.RulerWheel;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | public class MainActivity extends AppCompatActivity {
13 |
14 |
15 | private RulerWheel rulerView;
16 | private RulerWheel rulerView2;
17 | private String TAG = this.getClass().getSimpleName();
18 |
19 | private TextView tvCurValue;
20 | private TextView tvCurValue2;
21 |
22 | @Override
23 | protected void onCreate(Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 | setContentView(R.layout.activity_main);
26 |
27 | List list = new ArrayList<>();
28 | for (int i = 30; i < 150; i += 1) {
29 | list.add(i + "");
30 | for (int j = 1; j < 10; j++) {
31 | list.add(i + "." + j);
32 | }
33 | }
34 |
35 | tvCurValue = (TextView) findViewById(R.id.curValue_tv);
36 | rulerView = (RulerWheel) findViewById(R.id.ruler_view);
37 | rulerView.setData(list);
38 | rulerView.setScrollingListener(new RulerWheel.OnWheelScrollListener() {
39 | @Override
40 | public void onChanged(RulerWheel wheel, String oldValue, String newValue) {
41 | tvCurValue.setText(newValue + "");
42 | }
43 |
44 | @Override
45 | public void onScrollingStarted(RulerWheel wheel) {
46 |
47 | }
48 |
49 | @Override
50 | public void onScrollingFinished(RulerWheel wheel) {
51 |
52 | }
53 | });
54 |
55 |
56 | List list2 = new ArrayList<>();
57 | for (int i = 1000; i < 50000; i += 500) {
58 | list2.add(i + "");
59 | }
60 | tvCurValue2 = (TextView) findViewById(R.id.curValue2_tv);
61 | rulerView2 = (RulerWheel) findViewById(R.id.ruler_view2);
62 | rulerView2.setData(list2);
63 | rulerView2.setDataModel(RulerWheel.DATA_SET);
64 | rulerView2.setSelectedValue("8000");
65 | //不默认数据的画可以加下面的方式设置
66 | // rulerView2.setData(list2);
67 | rulerView2.setScrollingListener(new RulerWheel.OnWheelScrollListener() {
68 | @Override
69 | public void onChanged(RulerWheel wheel, String oldValue, String newValue) {
70 | tvCurValue2.setText(newValue + "");
71 | }
72 |
73 | @Override
74 | public void onScrollingStarted(RulerWheel wheel) {
75 |
76 | }
77 |
78 | @Override
79 | public void onScrollingFinished(RulerWheel wheel) {
80 |
81 | }
82 | });
83 |
84 |
85 | }
86 |
87 |
88 | public static void main(String[] args) {
89 |
90 | List list = new ArrayList<>();
91 | for (int i = 10; i < 200; i += 1) {
92 | list.add(i + "");
93 | for (int j = 1; j < 10; j++) {
94 | list.add(i + "." + j);
95 | }
96 | }
97 | System.out.println(String.valueOf(list));
98 |
99 |
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
22 |
23 |
43 |
44 |
53 |
54 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sanjay-F/RulerView/fc45621c9664a542aaf099a9a40e10ba33f29911/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sanjay-F/RulerView/fc45621c9664a542aaf099a9a40e10ba33f29911/app/src/main/res/mipmap-xhdpi/icon_arrow.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sanjay-F/RulerView/fc45621c9664a542aaf099a9a40e10ba33f29911/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | - 1
7 | - 3
8 | - 5
9 | - 11
10 | - 13
11 | - 19
12 | - 30
13 | - 46
14 | - 90
15 | - 104
16 | - 247
17 | - 422
18 | - 500
19 |
20 |
21 |
--------------------------------------------------------------------------------
/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 | 16dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | RulerView
3 | Settings
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/test/java/com/xk/sanjay/rulerview/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.xk.sanjay.rulerview;
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 | }
--------------------------------------------------------------------------------
/art/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sanjay-F/RulerView/fc45621c9664a542aaf099a9a40e10ba33f29911/art/demo.png
--------------------------------------------------------------------------------
/art/demo3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sanjay-F/RulerView/fc45621c9664a542aaf099a9a40e10ba33f29911/art/demo3.png
--------------------------------------------------------------------------------
/art/demo_up_half.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sanjay-F/RulerView/fc45621c9664a542aaf099a9a40e10ba33f29911/art/demo_up_half.png
--------------------------------------------------------------------------------
/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 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.5.0'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/rulberview/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/rulberview/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.2"
6 |
7 | defaultConfig {
8 | minSdkVersion 15
9 | targetSdkVersion 23
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | compile fileTree(dir: 'libs', include: ['*.jar'])
23 | testCompile 'junit:junit:4.12'
24 | compile 'com.android.support:support-annotations:23.1.1'
25 | }
26 |
--------------------------------------------------------------------------------
/rulberview/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 F:\devel\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 |
--------------------------------------------------------------------------------
/rulberview/src/androidTest/java/com/xk/sanjay/rulberview/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.xk.sanjay.rulberview;
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 | }
--------------------------------------------------------------------------------
/rulberview/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/rulberview/src/main/java/com/xk/sanjay/rulberview/RulerWheel.java:
--------------------------------------------------------------------------------
1 | package com.xk.sanjay.rulberview;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Bitmap;
6 | import android.graphics.BitmapFactory;
7 | import android.graphics.Canvas;
8 | import android.graphics.Color;
9 | import android.graphics.Paint;
10 | import android.support.annotation.IntDef;
11 | import android.text.Layout;
12 | import android.text.TextPaint;
13 | import android.util.AttributeSet;
14 | import android.view.MotionEvent;
15 | import android.view.View;
16 |
17 | import java.lang.annotation.Retention;
18 | import java.lang.annotation.RetentionPolicy;
19 | import java.util.ArrayList;
20 | import java.util.List;
21 |
22 |
23 | public class RulerWheel extends View {
24 | private String TAG = this.getClass().getSimpleName();
25 | // 默认刻度模式
26 | public static final int MOD_TYPE_SCALE = 5;
27 | // 1/2模式
28 | public static final int MOD_TYPE_HALF = 2;
29 | //刻度的上对齐方式
30 | public static final int ALIGN_MOD_UP = 0;
31 | //刻度的下对齐方式
32 | public static final int ALIGN_MOD_DOWN = 1;
33 | public static final int DEFAULT_ALIGN_MOD = ALIGN_MOD_DOWN;
34 | private int alignMode = DEFAULT_ALIGN_MOD;
35 | // 字体大小
36 | private int mTextSize = 36;
37 | // 分隔线(大号)
38 | private int mLineHeighMax;
39 | //最大刻度的粗细
40 | private int mMaxBarWidth;
41 | private int mMidBarWidth;
42 | private int mMinBarWidth;
43 | private int mLineColorMax;
44 | private int mTextColor;
45 | // 分隔线(中号)
46 | private int mLineHeighMid;
47 | private int mLineColorMid;
48 | // 分隔线(小号)
49 | private int mLineHeighMin;
50 | private int mLineColorMin;
51 | // 当前值
52 | private int mCurrValue;
53 | // 显示最大值
54 | private int mMaxValue;
55 | //显示最小值
56 | private int mMinValue;
57 | private int DEFAULT_MINI_VALUE = 0;
58 | private int DEFAULT_MAX_VALUE = 100;
59 | private int DEFAULT_CUR_VALUE = 0;
60 | private int DEFAULT_TEXT_SIZE = 30;
61 | private int DEFAULT_LINE_SIZE = 4;
62 | private int DEFAULT_LINE_DIVID_SIZE = 0;
63 | // 分隔模式
64 | private int mModType = MOD_TYPE_SCALE;
65 | /**
66 | * 分隔线之间间隔
67 | */
68 | private int mLineDivder;
69 | // 滚动器
70 | private WheelHorizontalScroller scroller;
71 | // 是否执行滚动
72 | private boolean isScrollingPerformed;
73 | // 滚动偏移量
74 | private int scrollingOffset;
75 | // 中间标线
76 | private Bitmap midBitmap;
77 | // 显示刻度值
78 | private boolean isShowScaleValue;
79 |
80 | /**
81 | * 是否支持渐显效果
82 | */
83 | private boolean mIsGradinet = false;
84 | private boolean mIsScaleValueGradinet = false;
85 |
86 | private Paint linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
87 | private Paint markPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
88 | private TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
89 | private float mTpDesiredWidth;
90 |
91 | private int scaleWidth;
92 |
93 | //数据模型,有两种,一种是数据增长方式,另外一个中就是用户自定要显示的数据,要求实现tostring()函数
94 | private int mDataModel;
95 |
96 | @IntDef(flag = true,
97 | value = {
98 | DATA_INT,
99 | DATA_SET
100 | })
101 | @Retention(RetentionPolicy.SOURCE)
102 | public @interface DataModel {
103 | }
104 |
105 | public static final int DATA_INT = 0;
106 | public static final int DATA_SET = 1;
107 | private List dataList;
108 | private CharSequence[] dataSource;
109 |
110 | public RulerWheel(Context context) {
111 | this(context, null);
112 | }
113 |
114 | public RulerWheel(Context context, AttributeSet attrs) {
115 | this(context, attrs, 0);
116 | }
117 |
118 | public RulerWheel(Context context, AttributeSet attrs, int defStyle) {
119 | super(context, attrs, defStyle);
120 | init(context, attrs);
121 | }
122 |
123 |
124 | public void init(Context context, AttributeSet attrs) {
125 |
126 | scroller = new WheelHorizontalScroller(context, scrollingListener);
127 | // 获取自定义属性和默认值
128 | TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.RulerWheel);
129 |
130 |
131 | // 刻度宽度
132 | scaleWidth = mTypedArray.getDimensionPixelSize(R.styleable.RulerWheel_scaleWidth, DEFAULT_LINE_SIZE);
133 | linePaint.setStrokeWidth(scaleWidth);
134 |
135 | // 刻度颜色
136 | mLineColorMax = mTypedArray.getColor(R.styleable.RulerWheel_lineColorMax, Color.BLACK);
137 | mLineColorMid = mTypedArray.getColor(R.styleable.RulerWheel_lineColorMid, Color.BLACK);
138 | mLineColorMin = mTypedArray.getColor(R.styleable.RulerWheel_lineColorMin, Color.BLACK);
139 |
140 | mTextSize = mTypedArray.getInteger(R.styleable.RulerWheel_text_Size, DEFAULT_TEXT_SIZE);
141 | mCurrValue = mTypedArray.getInteger(R.styleable.RulerWheel_def_value, DEFAULT_CUR_VALUE);
142 | mMaxValue = mTypedArray.getInteger(R.styleable.RulerWheel_max_value, DEFAULT_MAX_VALUE);
143 | mMinValue = mTypedArray.getInteger(R.styleable.RulerWheel_min_value, DEFAULT_MINI_VALUE);
144 |
145 | if (mCurrValue < mMinValue) {
146 | mCurrValue = mMinValue;
147 | }
148 |
149 | // 刻度模式
150 | mModType = obtainMode(mTypedArray.getInteger(R.styleable.RulerWheel_mode, 0));
151 |
152 | // 刻度对齐模式
153 | alignMode = mTypedArray.getInteger(R.styleable.RulerWheel_alignMode, DEFAULT_ALIGN_MOD);
154 |
155 | int maskResId;
156 | if (alignMode == ALIGN_MOD_UP) {
157 | // mask,我们的箭头
158 | maskResId = mTypedArray.getResourceId(R.styleable.RulerWheel_mask_bg, R.drawable.ruler_mid_arraw);
159 | } else {
160 | maskResId = mTypedArray.getResourceId(R.styleable.RulerWheel_mask_bg, R.drawable.ruler_mid_arraw_down);
161 | }
162 | midBitmap = BitmapFactory.decodeResource(getResources(), maskResId);
163 |
164 | // 线条间距
165 | mLineDivder = obtainLineDivder(mTypedArray.getDimensionPixelSize(R.styleable.RulerWheel_line_divider, DEFAULT_LINE_DIVID_SIZE));
166 |
167 | // 显示刻度值
168 | isShowScaleValue = mTypedArray.getBoolean(R.styleable.RulerWheel_showScaleValue, true);
169 | textPaint.setTextSize(mTextSize);
170 | textPaint.setTextAlign(Paint.Align.CENTER);
171 | mTpDesiredWidth = Layout.getDesiredWidth("0", textPaint);
172 |
173 |
174 | //---1/14---新加的特性----
175 | mMaxBarWidth = mTypedArray.getDimensionPixelSize(R.styleable.RulerWheel_MaxBarSize, scaleWidth);
176 | mMidBarWidth = mTypedArray.getDimensionPixelSize(R.styleable.RulerWheel_MidBarSize, scaleWidth);
177 | mMinBarWidth = mTypedArray.getDimensionPixelSize(R.styleable.RulerWheel_MinBarSize, scaleWidth);
178 | //渐显显示刻度
179 | mIsGradinet = mTypedArray.getBoolean(R.styleable.RulerWheel_showGradient, false);
180 | mIsScaleValueGradinet = mTypedArray.getBoolean(R.styleable.RulerWheel_scaleValueGradient, false);
181 | mTextColor = mTypedArray.getColor(R.styleable.RulerWheel_text_color, Color.BLACK);
182 |
183 | mDataModel = mTypedArray.getInteger(R.styleable.RulerWheel_dataMode, DATA_INT);
184 | if (mDataModel == DATA_SET) {
185 |
186 | dataSource = mTypedArray.getTextArray(R.styleable.RulerWheel_dataSource);
187 |
188 | dataList = new ArrayList<>();
189 |
190 | if (dataSource != null) {
191 |
192 | for (int i = 0; i < dataSource.length; i++) {
193 | dataList.add(String.valueOf(dataSource[i]));
194 | }
195 |
196 | mMinValue = 0;
197 | mMaxValue = dataSource.length - 1;
198 | } else {
199 | for (int i = 0; i < 20; i++) {
200 | dataList.add(i * 2 + "");
201 | }
202 | mMinValue = 0;
203 | mMaxValue = 19;
204 | }
205 |
206 | }
207 | textPaint.setColor(mTextColor);
208 |
209 | mTypedArray.recycle();
210 | }
211 |
212 | private int obtainMode(int mode) {
213 | if (mode == 1) {
214 | return MOD_TYPE_HALF;
215 | }
216 | return MOD_TYPE_SCALE;
217 | }
218 |
219 | private int obtainLineDivder(int lineDivder) {
220 | if (0 == lineDivder) {
221 | if (mModType == MOD_TYPE_HALF) {
222 | mLineDivder = 80;
223 | } else {
224 | mLineDivder = 20;
225 | }
226 | return mLineDivder;
227 | }
228 |
229 | return lineDivder;
230 | }
231 |
232 | // Scrolling listener
233 | WheelHorizontalScroller.ScrollingListener scrollingListener = new WheelHorizontalScroller.ScrollingListener() {
234 | @Override
235 | public void onStarted() {
236 | isScrollingPerformed = true;
237 | notifyScrollingListenersAboutStart();
238 | }
239 |
240 | @Override
241 | public void onScroll(int distance) {
242 | doScroll(distance);
243 | }
244 |
245 | @Override
246 | public void onFinished() {
247 | if (thatExceed()) {
248 | return;
249 | }
250 | if (isScrollingPerformed) {
251 | notifyScrollingListenersAboutEnd();
252 | isScrollingPerformed = false;
253 | }
254 | scrollingOffset = 0;
255 | invalidate();
256 | }
257 |
258 | @Override
259 | public void onJustify() {
260 | if (thatExceed()) {
261 | return;
262 | }
263 | if (Math.abs(scrollingOffset) > WheelHorizontalScroller.MIN_DELTA_FOR_SCROLLING) {
264 | if (scrollingOffset < -mLineDivder / 2) {
265 | scroller.scroll(mLineDivder + scrollingOffset, 0);
266 | } else if (scrollingOffset > mLineDivder / 2) {
267 | scroller.scroll(scrollingOffset - mLineDivder, 0);
268 | } else {
269 | scroller.scroll(scrollingOffset, 0);
270 | }
271 | }
272 | }
273 | };
274 |
275 | private void doScroll(int delta) {
276 | scrollingOffset += delta;
277 | int offsetCount = scrollingOffset / mLineDivder;
278 | if (0 != offsetCount) {
279 | // 显示在范围内
280 | // int oldValue = Math.min(Math.max(mMinValue, mCurrValue), mMaxValue);
281 | int oldValueIndex = Math.min(Math.max(mMinValue, mCurrValue), mMaxValue);
282 |
283 |
284 | mCurrValue -= offsetCount;
285 | scrollingOffset -= offsetCount * mLineDivder;
286 | if (null != onWheelListener) {
287 | //回调通知最新的值
288 | int valueIndex = Math.min(Math.max(mMinValue, mCurrValue), mMaxValue);
289 | onWheelListener.onChanged(this, dataList.get(oldValueIndex) + "", dataList.get(valueIndex));
290 | }
291 | }
292 | invalidate();
293 | }
294 |
295 | /**
296 | * 越界回滚
297 | *
298 | * @return
299 | */
300 | private boolean thatExceed() {
301 | //这个是越界后需要回滚的大小值
302 | int outRange = 0;
303 | if (mCurrValue < mMinValue) {
304 | outRange = (mCurrValue - mMinValue) * mLineDivder;
305 | } else if (mCurrValue > mMaxValue) {
306 | outRange = (mCurrValue - mMaxValue) * mLineDivder;
307 | }
308 | if (0 != outRange) {
309 | scrollingOffset = 0;
310 | scroller.scroll(-outRange, 100);
311 | return true;
312 | }
313 | return false;
314 | }
315 |
316 | public void setValue(int current, int maxValue) {
317 | if (current < mMinValue) {
318 | current = mMinValue;
319 | }
320 |
321 | if (maxValue < 0) {
322 | maxValue = 100;
323 | }
324 |
325 | this.mCurrValue = current;
326 | this.mMaxValue = maxValue;
327 | invalidate();
328 | }
329 |
330 | /**
331 | * 获取当前值
332 | *
333 | * @return
334 | */
335 | public int getValue() {
336 | return Math.min(Math.max(mMinValue, mCurrValue), mMaxValue);
337 | }
338 |
339 | /***
340 | * 这里修改了View的高度是一个固定值!
341 | * 可根据需要修改
342 | *
343 | * @param widthMeasureSpec
344 | * @param heightMeasureSpec
345 | */
346 | @Override
347 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
348 | int widthSize = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
349 | int heightSize;
350 | //如果想修改view的大小请修改这里
351 |
352 | if (alignMode == ALIGN_MOD_DOWN) {
353 | if (midBitmap != null) {
354 | heightSize = (int) (midBitmap.getHeight() + getPaddingTop() + getPaddingBottom() + 2 * textPaint.getTextSize());
355 | } else {
356 | heightSize = getPaddingTop() + getPaddingBottom();
357 | }
358 | } else {
359 | if (midBitmap != null) {
360 | heightSize = (int) (midBitmap.getHeight() + getPaddingTop() + getPaddingBottom());
361 | } else {
362 | heightSize = getPaddingTop() + getPaddingBottom();
363 | }
364 | }
365 | setMeasuredDimension(widthSize, heightSize);
366 | }
367 |
368 | /***
369 | * 如果想改各个刻度的高度值可以修改这里面的三个参数的值
370 | *
371 | * @param w
372 | * @param h
373 | * @param oldw
374 | * @param oldh
375 | */
376 | @Override
377 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
378 | super.onSizeChanged(w, h, oldw, oldh);
379 | if (w == 0 || h == 0)
380 | return;
381 | int rHeight = h - getPaddingTop() - getPaddingBottom();
382 | mLineHeighMax = rHeight / 3;
383 | mLineHeighMid = rHeight / 4;
384 | mLineHeighMin = rHeight / 7;
385 | }
386 |
387 | @Override
388 | protected void onDraw(Canvas canvas) {
389 | super.onDraw(canvas);
390 | if (mLineHeighMin == 0) {
391 | return;
392 | }
393 | int rWidth = getWidth() - getPaddingLeft() - getPaddingRight();
394 | int rHeight = getHeight() - getPaddingTop() - getPaddingBottom();
395 |
396 | //画数据
397 | drawRulerLine(canvas, rWidth, rHeight);
398 | //画指示器
399 | drawMiddleUpArrowLine(canvas, rWidth, rHeight);
400 | }
401 |
402 | /**
403 | * 画中间的箭头指示的,当然也可以替代别的mask
404 | *
405 | * @param canvas
406 | * @param rWidth
407 | * @param rHeight
408 | */
409 | private void drawMiddleUpArrowLine(Canvas canvas, int rWidth, int rHeight) {
410 |
411 | int left;
412 | int top;
413 | if (alignMode == ALIGN_MOD_DOWN) {
414 | left = (rWidth - midBitmap.getWidth()) / 2;
415 | top = (int) (textPaint.getTextSize() / 2);
416 | } else {
417 | left = (rWidth - midBitmap.getWidth()) / 2;
418 | top = (int) ((rHeight - midBitmap.getHeight()) / 2);
419 | }
420 | canvas.drawBitmap(midBitmap, left, top, markPaint);
421 | }
422 |
423 | /**
424 | * @param canvas
425 | * @param rWidth 显示宽度
426 | * @param rHeight 显示高度
427 | */
428 | private void drawRulerLine(Canvas canvas, int rWidth, int rHeight) {
429 | // 根据间隔计算当前一半宽度的个数+偏移2个
430 | final int halfCount = (int) Math.ceil(rWidth / 2f / mLineDivder) + 2;
431 | final int distanceX = scrollingOffset;
432 | final int currValue = mCurrValue;
433 |
434 | if (alignMode == ALIGN_MOD_UP) {
435 | drawUpMode(canvas, halfCount, distanceX, currValue, rWidth, rHeight);
436 | } else {
437 | drawDownMode(canvas, halfCount, distanceX, currValue, rWidth, rHeight);
438 | }
439 |
440 | }
441 |
442 | //标刻的对齐方式是上对齐
443 | private void drawUpMode(Canvas canvas, int halfCount, int distanceX, int currValue, int rWidth, int rHeight) {
444 |
445 | int ry = (int) (getPaddingTop() + (rHeight - mLineHeighMax) / 2 + textPaint.getTextSize());
446 | int value;
447 | float xPosition;
448 | for (int i = 0; i < halfCount; i++) {
449 | // right
450 | xPosition = rWidth / 2f + i * mLineDivder + distanceX;
451 | value = currValue + i;
452 | if (xPosition <= rWidth && value >= mMinValue && value <= mMaxValue) {
453 | if (value % mModType == 0) {
454 | if (mModType == MOD_TYPE_HALF) {
455 | linePaint.setColor(mLineColorMax);
456 | linePaint.setStrokeWidth(mMaxBarWidth);
457 | linePaint.setAlpha(getAlpha(halfCount, i));
458 | canvas.drawLine(xPosition, ry, xPosition, ry + mLineHeighMax, linePaint);
459 | if (isShowScaleValue) {
460 | if (mIsScaleValueGradinet) {
461 | textPaint.setAlpha(getAlpha(halfCount, i));
462 | }
463 | if (mDataModel == DATA_INT) {
464 | canvas.drawText(String.valueOf(value / 2), xPosition, ry - mTpDesiredWidth, textPaint);
465 | } else {
466 | canvas.drawText(String.valueOf(dataList.get(value)), xPosition, rHeight - mTpDesiredWidth, textPaint);
467 | }
468 | }
469 | } else if (mModType == MOD_TYPE_SCALE) {
470 | if (value % (MOD_TYPE_SCALE * 2) == 0) {
471 | linePaint.setColor(mLineColorMax);
472 | linePaint.setStrokeWidth(mMaxBarWidth);
473 | linePaint.setAlpha(getAlpha(halfCount, i));
474 | canvas.drawLine(xPosition, ry, xPosition, ry + mLineHeighMax, linePaint);
475 | if (isShowScaleValue) {
476 | if (mIsScaleValueGradinet) {
477 | textPaint.setAlpha(getAlpha(halfCount, i));
478 | }
479 | if (mDataModel == DATA_INT) {
480 | canvas.drawText(String.valueOf(value), xPosition, ry - mTpDesiredWidth, textPaint);
481 | } else {
482 | canvas.drawText(String.valueOf(dataList.get(value)), xPosition, rHeight - mTpDesiredWidth, textPaint);
483 | }
484 |
485 | }
486 | } else {
487 | linePaint.setStrokeWidth(mMidBarWidth);
488 | linePaint.setColor(mLineColorMid);
489 | linePaint.setAlpha(getAlpha(halfCount, i));
490 | canvas.drawLine(xPosition, ry, xPosition, ry + mLineHeighMid, linePaint);
491 | }
492 | }
493 | } else {
494 | if (mModType == MOD_TYPE_HALF) {
495 | linePaint.setStrokeWidth(mMidBarWidth);
496 | linePaint.setColor(mLineColorMid);
497 | linePaint.setAlpha(getAlpha(halfCount, i));
498 | canvas.drawLine(xPosition, ry, xPosition, ry + mLineHeighMid, linePaint);
499 | } else {
500 | linePaint.setColor(mLineColorMin);
501 | linePaint.setStrokeWidth(mMinBarWidth);
502 | linePaint.setAlpha(getAlpha(halfCount, i));
503 | canvas.drawLine(xPosition, ry, xPosition, ry + mLineHeighMin, linePaint);
504 | }
505 | }
506 | }
507 |
508 | // left
509 | xPosition = rWidth / 2f - i * mLineDivder + distanceX;
510 | value = currValue - i;
511 | if (xPosition > getPaddingLeft() && value > mMinValue && value <= mMaxValue) {
512 | if (value % mModType == 0) {
513 | if (mModType == MOD_TYPE_HALF) {
514 | linePaint.setColor(mLineColorMax);
515 | linePaint.setStrokeWidth(mMaxBarWidth);
516 | linePaint.setAlpha(getAlpha(halfCount, i));
517 | canvas.drawLine(xPosition, ry, xPosition, ry + mLineHeighMax, linePaint);
518 | if (isShowScaleValue) {
519 | if (mIsScaleValueGradinet) {
520 | textPaint.setAlpha(getAlpha(halfCount, i));
521 | }
522 | if (mDataModel == DATA_INT) {
523 | canvas.drawText(String.valueOf(value / 2), xPosition, ry - mTpDesiredWidth, textPaint);
524 | } else {
525 | canvas.drawText(String.valueOf(dataList.get(value)), xPosition, rHeight - mTpDesiredWidth, textPaint);
526 | }
527 | }
528 | } else if (mModType == MOD_TYPE_SCALE) {
529 | if (value % (MOD_TYPE_SCALE * 2) == 0) {
530 | linePaint.setColor(mLineColorMax);
531 | linePaint.setStrokeWidth(mMaxBarWidth);
532 | linePaint.setAlpha(getAlpha(halfCount, i));
533 | canvas.drawLine(xPosition, ry, xPosition, ry + mLineHeighMax, linePaint);
534 | if (isShowScaleValue) {
535 | if (mIsScaleValueGradinet) {
536 | textPaint.setAlpha(getAlpha(halfCount, i));
537 | }
538 | if (mDataModel == DATA_INT) {
539 | canvas.drawText(String.valueOf(value), xPosition, ry - mTpDesiredWidth, textPaint);
540 | } else {
541 | canvas.drawText(String.valueOf(dataList.get(value)), xPosition, rHeight - mTpDesiredWidth, textPaint);
542 | }
543 | }
544 | } else {
545 | linePaint.setColor(mLineColorMid);
546 | linePaint.setStrokeWidth(mMidBarWidth);
547 | linePaint.setAlpha(getAlpha(halfCount, i));
548 | canvas.drawLine(xPosition, ry, xPosition, ry + mLineHeighMid, linePaint);
549 | }
550 | }
551 | } else {
552 | if (mModType == MOD_TYPE_HALF) {
553 | linePaint.setStrokeWidth(mMidBarWidth);
554 | linePaint.setColor(mLineColorMid);
555 | linePaint.setAlpha(getAlpha(halfCount, i));
556 | canvas.drawLine(xPosition, ry, xPosition, ry + mLineHeighMid, linePaint);
557 | } else {
558 | linePaint.setColor(mLineColorMin);
559 | linePaint.setStrokeWidth(mMinBarWidth);
560 | linePaint.setAlpha(getAlpha(halfCount, i));
561 | canvas.drawLine(xPosition, ry, xPosition, ry + mLineHeighMin, linePaint);
562 | }
563 | }
564 | }
565 | }
566 | }
567 |
568 | //标刻的对齐方式是下对齐
569 | private void drawDownMode(Canvas canvas, int halfCount, int distanceX, int currValue, int rWidth, int rHeight) {
570 | int value;
571 | float xPosition;
572 | //线y坐标
573 | int ry = (int) (rHeight - mTpDesiredWidth - textPaint.getTextSize()) - getPaddingBottom();
574 | for (int i = 0; i < halfCount; i++) {
575 | //画显示在屏幕上的右半部分数据---right part
576 | xPosition = rWidth / 2f + i * mLineDivder + distanceX;
577 | value = currValue + i;
578 | if (xPosition <= rWidth && value >= mMinValue && value <= mMaxValue) {
579 | // Log.e(TAG, "right value=" + value + " xPos=" + xPosition);
580 | if (value % mModType == 0) {
581 | if (mModType == MOD_TYPE_HALF) {
582 | linePaint.setColor(mLineColorMax);
583 | linePaint.setStrokeWidth(mMaxBarWidth);
584 | linePaint.setAlpha(getAlpha(halfCount, i));
585 | canvas.drawLine(xPosition, ry, xPosition, ry - mLineHeighMax, linePaint);
586 | if (isShowScaleValue) {
587 | if (mIsScaleValueGradinet) {
588 | textPaint.setAlpha(getAlpha(halfCount, i));
589 | }
590 | if (mDataModel == DATA_INT) {
591 | canvas.drawText(String.valueOf(value / 2), xPosition, rHeight - mTpDesiredWidth, textPaint);
592 | } else {
593 | canvas.drawText(String.valueOf(dataList.get(value)), xPosition, rHeight - mTpDesiredWidth, textPaint);
594 | }
595 | }
596 |
597 | } else if (mModType == MOD_TYPE_SCALE) {
598 | if (value % (MOD_TYPE_SCALE * 2) == 0) {
599 | linePaint.setColor(mLineColorMax);
600 | linePaint.setStrokeWidth(mMaxBarWidth);
601 | linePaint.setAlpha(getAlpha(halfCount, i));
602 | canvas.drawLine(xPosition, ry, xPosition, ry - mLineHeighMax, linePaint);
603 | if (isShowScaleValue) {
604 | if (mIsScaleValueGradinet) {
605 | textPaint.setAlpha(getAlpha(halfCount, i));
606 | }
607 | if (mDataModel == DATA_INT) {
608 | canvas.drawText(String.valueOf(value), xPosition, rHeight - mTpDesiredWidth, textPaint);
609 | } else {
610 | canvas.drawText(String.valueOf(dataList.get(value)), xPosition, rHeight - mTpDesiredWidth, textPaint);
611 | }
612 | }
613 | } else {
614 | linePaint.setStrokeWidth(mMidBarWidth);
615 | linePaint.setColor(mLineColorMid);
616 | linePaint.setAlpha(getAlpha(halfCount, i));
617 | canvas.drawLine(xPosition, ry, xPosition, ry - mLineHeighMid, linePaint);
618 | }
619 | }
620 | } else {
621 | if (mModType == MOD_TYPE_HALF) {
622 | linePaint.setStrokeWidth(mMidBarWidth);
623 | linePaint.setColor(mLineColorMid);
624 | linePaint.setAlpha(getAlpha(halfCount, i));
625 | canvas.drawLine(xPosition, ry, xPosition, ry - mLineHeighMid, linePaint);
626 | } else {
627 | linePaint.setColor(mLineColorMin);
628 | linePaint.setStrokeWidth(mMinBarWidth);
629 | linePaint.setAlpha(getAlpha(halfCount, i));
630 | canvas.drawLine(xPosition, ry, xPosition, ry - mLineHeighMin, linePaint);
631 | }
632 | }
633 | }
634 |
635 | //画显示在屏幕上的左半部分数据---left part
636 | xPosition = rWidth / 2f - i * mLineDivder + distanceX;
637 | value = currValue - i;
638 | if (xPosition > getPaddingLeft() && value >= mMinValue && value <= mMaxValue) {
639 | // Log.e(TAG, "left value=" + value);
640 | if (value % mModType == 0) {
641 | if (mModType == MOD_TYPE_HALF) {
642 | linePaint.setColor(mLineColorMax);
643 | linePaint.setStrokeWidth(mMaxBarWidth);
644 | linePaint.setAlpha(getAlpha(halfCount, i));
645 | canvas.drawLine(xPosition, ry, xPosition, ry - mLineHeighMax, linePaint);
646 | if (isShowScaleValue) {
647 | if (mDataModel == DATA_INT) {
648 | if (mIsScaleValueGradinet) {
649 | textPaint.setAlpha(getAlpha(halfCount, i));
650 | }
651 | canvas.drawText(String.valueOf(value / 2), xPosition, rHeight - mTpDesiredWidth, textPaint);
652 | } else {
653 | canvas.drawText(String.valueOf(dataList.get(value)), xPosition, rHeight - mTpDesiredWidth, textPaint);
654 | }
655 | }
656 | } else if (mModType == MOD_TYPE_SCALE) {
657 | if (value % (MOD_TYPE_SCALE * 2) == 0) {
658 | linePaint.setColor(mLineColorMax);
659 | linePaint.setStrokeWidth(mMaxBarWidth);
660 | linePaint.setAlpha(getAlpha(halfCount, i));
661 | canvas.drawLine(xPosition, ry, xPosition, ry - mLineHeighMax, linePaint);
662 | if (isShowScaleValue) {
663 | if (mIsScaleValueGradinet) {
664 | textPaint.setAlpha(getAlpha(halfCount, i));
665 | }
666 | if (mDataModel == DATA_INT) {
667 | canvas.drawText(String.valueOf(value), xPosition, rHeight - mTpDesiredWidth, textPaint);
668 | } else {
669 | canvas.drawText(String.valueOf(dataList.get(value)), xPosition, rHeight - mTpDesiredWidth, textPaint);
670 | }
671 | }
672 | } else {
673 | linePaint.setStrokeWidth(mMidBarWidth);
674 | linePaint.setColor(mLineColorMid);
675 | linePaint.setAlpha(getAlpha(halfCount, i));
676 | canvas.drawLine(xPosition, ry, xPosition, ry - mLineHeighMid, linePaint);
677 | }
678 | }
679 | } else {
680 | if (mModType == MOD_TYPE_HALF) {
681 | linePaint.setStrokeWidth(mMidBarWidth);
682 | linePaint.setColor(mLineColorMid);
683 | linePaint.setAlpha(getAlpha(halfCount, i));
684 | canvas.drawLine(xPosition, ry, xPosition, ry - mLineHeighMid, linePaint);
685 | } else {
686 | linePaint.setColor(mLineColorMin);
687 | linePaint.setStrokeWidth(mMinBarWidth);
688 | linePaint.setAlpha(getAlpha(halfCount, i));
689 | canvas.drawLine(xPosition, ry, xPosition, ry - mLineHeighMin, linePaint);
690 | }
691 | }
692 | }
693 | }
694 | }
695 |
696 | private int getAlpha(int halfCount, int index) {
697 |
698 | if (mIsGradinet) {
699 | int MAX_ALPHA_VALUE = 255;
700 | return MAX_ALPHA_VALUE / halfCount * (halfCount - index);
701 | } else {
702 | return 255;
703 | }
704 | }
705 |
706 | private float mDownFocusX;
707 | private float mDownFocusY;
708 | private boolean isDisallowIntercept;
709 |
710 | @Override
711 | public boolean onTouchEvent(MotionEvent event) {
712 | if (!isEnabled()) {
713 | return true;
714 | }
715 | switch (event.getAction()) {
716 | case MotionEvent.ACTION_DOWN:
717 | mDownFocusX = event.getX();
718 | mDownFocusY = event.getY();
719 | break;
720 | case MotionEvent.ACTION_MOVE:
721 | if (!isDisallowIntercept && Math.abs(event.getY() - mDownFocusY) < Math.abs(event.getX() - mDownFocusX)) {
722 | isDisallowIntercept = true;
723 | if (getParent() != null) {
724 | getParent().requestDisallowInterceptTouchEvent(true);
725 | }
726 | }
727 | break;
728 | case MotionEvent.ACTION_UP:
729 | case MotionEvent.ACTION_CANCEL:
730 | if (getParent() != null) {
731 | getParent().requestDisallowInterceptTouchEvent(false);
732 | }
733 | isDisallowIntercept = false;
734 | break;
735 | }
736 | return scroller.onTouchEvent(event);
737 | }
738 |
739 | public void setData(List dataList) {
740 | setDataModel(DATA_SET);
741 | mMinValue = 0;
742 | mMaxValue = dataList.size() - 1;
743 | this.dataList = dataList;
744 | invalidate();
745 | }
746 |
747 | /***
748 | * @param dataModel 只支持{@link RulerWheel#DATA_INT}和{@link RulerWheel#DATA_SET}
749 | */
750 | public void setDataModel(@DataModel int dataModel) {
751 | this.mDataModel = dataModel;
752 | }
753 |
754 | //---------------------
755 | //region 回调接口通知部分
756 |
757 | private OnWheelScrollListener onWheelListener;
758 |
759 | /**
760 | * Adds wheel changing listener
761 | *
762 | * @param listener the listener
763 | */
764 | public void setScrollingListener(OnWheelScrollListener listener) {
765 | onWheelListener = listener;
766 | }
767 |
768 | /**
769 | * Removes wheel changing listener
770 | */
771 | public void removeScrollingListener() {
772 | onWheelListener = null;
773 | }
774 |
775 | /**
776 | * Notifies changing listeners
777 | *
778 | * @param oldValue the old wheel value
779 | * @param newValue the new wheel value
780 | */
781 | protected void notifyScrollingListeners(int oldValue, int newValue) {
782 | onWheelListener.onChanged(this, oldValue, newValue);
783 | }
784 |
785 | private void notifyScrollingListenersAboutStart() {
786 | if (null != onWheelListener) {
787 | onWheelListener.onScrollingStarted(this);
788 | }
789 | }
790 |
791 | private void notifyScrollingListenersAboutEnd() {
792 | if (null != onWheelListener) {
793 | onWheelListener.onScrollingFinished(this);
794 | }
795 | }
796 |
797 |
798 | public interface OnWheelScrollListener {
799 | /**
800 | * Callback method to be invoked when current item changed
801 | *
802 | * @param wheel the wheel view whose state has changed
803 | * @param oldValue the old value of current item
804 | * @param newValue the new value of current item
805 | */
806 | void onChanged(RulerWheel wheel, T oldValue, T newValue);
807 |
808 | /**
809 | * Callback method to be invoked when scrolling started.
810 | *
811 | * @param wheel the wheel view whose state has changed.
812 | */
813 | void onScrollingStarted(RulerWheel wheel);
814 |
815 | /**
816 | * Callback method to be invoked when scrolling ended.
817 | *
818 | * @param wheel the wheel view whose state has changed.
819 | */
820 | void onScrollingFinished(RulerWheel wheel);
821 | }
822 | //endregion
823 |
824 |
825 | public void setSelectedValue(String selectedValue) {
826 | if (mDataModel == DATA_SET && dataList != null && selectedValue != null) {
827 | int index = dataList.indexOf(selectedValue);
828 | mCurrValue = index == -1 ? mMinValue : index;
829 | }
830 | }
831 | }
--------------------------------------------------------------------------------
/rulberview/src/main/java/com/xk/sanjay/rulberview/WheelHorizontalScroller.java:
--------------------------------------------------------------------------------
1 | package com.xk.sanjay.rulberview;
2 |
3 | import android.content.Context;
4 | import android.os.Handler;
5 | import android.os.Message;
6 | import android.view.GestureDetector;
7 | import android.view.MotionEvent;
8 | import android.view.animation.Interpolator;
9 | import android.widget.Scroller;
10 |
11 | public class WheelHorizontalScroller {
12 | /**
13 | * Scrolling listener interface
14 | */
15 | public interface ScrollingListener {
16 | /**
17 | * Scrolling callback called when scrolling is performed.
18 | *
19 | * @param distance the distance to scroll
20 | */
21 | void onScroll(int distance);
22 |
23 | /**
24 | * Starting callback called when scrolling is started
25 | */
26 | void onStarted();
27 |
28 | /**
29 | * Finishing callback called after justifying
30 | */
31 | void onFinished();
32 |
33 | /**
34 | * Justifying callback called to justify a view when scrolling is ended
35 | */
36 | void onJustify();
37 | }
38 |
39 | /**
40 | * Scrolling duration
41 | */
42 | public static final int SCROLLING_DURATION = 400;
43 |
44 | /**
45 | * Minimum delta for scrolling
46 | */
47 | public static final int MIN_DELTA_FOR_SCROLLING = 1;
48 |
49 | // Listener
50 | private ScrollingListener listener;
51 |
52 | // Context
53 | private Context context;
54 |
55 | // Scrolling
56 | private GestureDetector gestureDetector;
57 | private Scroller scroller;
58 | private int lastScrollX;
59 | private float lastTouchedX;
60 | private boolean isScrollingPerformed;
61 |
62 | /**
63 | * Constructor
64 | *
65 | * @param context the current context
66 | * @param listener the scrolling listener
67 | */
68 | public WheelHorizontalScroller(Context context, ScrollingListener listener) {
69 | gestureDetector = new GestureDetector(context, gestureListener);
70 | gestureDetector.setIsLongpressEnabled(false);
71 | scroller = new Scroller(context);
72 | scroller.setFriction(0.05f);
73 |
74 | this.listener = listener;
75 | this.context = context;
76 | }
77 |
78 | /**
79 | * Set the the specified scrolling interpolator
80 | *
81 | * @param interpolator the interpolator
82 | */
83 | public void setInterpolator(Interpolator interpolator) {
84 | scroller.forceFinished(true);
85 | scroller = new Scroller(context, interpolator);
86 | }
87 |
88 | /**
89 | * Scroll the wheel
90 | *
91 | * @param distance the scrolling distance
92 | * @param time the scrolling duration
93 | */
94 | public void scroll(int distance, int time) {
95 | scroller.forceFinished(true);
96 | lastScrollX = 0;
97 | scroller.startScroll(0, 0, distance, 0, time != 0 ? time : SCROLLING_DURATION);
98 | setNextMessage(MESSAGE_SCROLL);
99 | startScrolling();
100 | }
101 |
102 | /**
103 | * Stops scrolling
104 | */
105 | public void stopScrolling() {
106 | scroller.forceFinished(true);
107 | }
108 |
109 | // gesture listener
110 | private GestureDetector.SimpleOnGestureListener gestureListener = new GestureDetector.SimpleOnGestureListener() {
111 | public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
112 | // Do scrolling in onTouchEvent() since onScroll() are not call immediately
113 | // when user touch and move the wheel
114 | return true;
115 | }
116 |
117 | public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
118 | lastScrollX = 0;
119 | // final int maxX = 0x7FFFFFFF;
120 | // final int minX = -maxX;
121 | scroller.fling(0, lastScrollX, (int) -velocityX, 0, -0x7FFFFFFF, 0x7FFFFFFF, 0, 0);
122 | setNextMessage(MESSAGE_SCROLL);
123 | return true;
124 | }
125 | };
126 |
127 | /**
128 | * Handles Touch event
129 | *
130 | * @param event the motion event
131 | * @return
132 | */
133 | public boolean onTouchEvent(MotionEvent event) {
134 | switch (event.getAction()) {
135 | case MotionEvent.ACTION_DOWN:
136 | lastTouchedX = event.getX();
137 | scroller.forceFinished(true);
138 | clearMessages();
139 | break;
140 |
141 | case MotionEvent.ACTION_MOVE:
142 | // perform scrolling
143 | int distanceX = (int) (event.getX() - lastTouchedX);
144 | if (distanceX != 0) {
145 | startScrolling();
146 | listener.onScroll(distanceX);
147 | lastTouchedX = event.getX();
148 | }
149 | break;
150 | }
151 |
152 | if (!gestureDetector.onTouchEvent(event) && event.getAction() == MotionEvent.ACTION_UP) {
153 | justify();
154 | }
155 |
156 | return true;
157 | }
158 |
159 | // Messages
160 | private final int MESSAGE_SCROLL = 0;
161 | private final int MESSAGE_JUSTIFY = 1;
162 |
163 | /**
164 | * Set next message to queue. Clears queue before.
165 | *
166 | * @param message the message to set
167 | */
168 | private void setNextMessage(int message) {
169 | clearMessages();
170 | animationHandler.sendEmptyMessage(message);
171 | }
172 |
173 | /**
174 | * Clears messages from queue
175 | */
176 | private void clearMessages() {
177 | animationHandler.removeMessages(MESSAGE_SCROLL);
178 | animationHandler.removeMessages(MESSAGE_JUSTIFY);
179 | }
180 |
181 | // animation handler
182 | private Handler animationHandler = new Handler(new Handler.Callback() {
183 | @Override
184 | public boolean handleMessage(Message msg) {
185 | scroller.computeScrollOffset();
186 | int currX = scroller.getCurrX();
187 | int delta = lastScrollX - currX;
188 | lastScrollX = currX;
189 | if (delta != 0) {
190 | listener.onScroll(delta);
191 | }
192 |
193 | // scrolling is not finished when it comes to final Y
194 | // so, finish it manually
195 | if (Math.abs(currX - scroller.getFinalX()) < MIN_DELTA_FOR_SCROLLING) {
196 | lastScrollX = scroller.getFinalX();
197 | scroller.forceFinished(true);
198 | }
199 | if (!scroller.isFinished()) {
200 | animationHandler.sendEmptyMessage(msg.what);
201 | } else if (msg.what == MESSAGE_SCROLL) {
202 | justify();
203 | } else {
204 | finishScrolling();
205 | }
206 | return true;
207 | }
208 | });
209 |
210 | /**
211 | * Justifies wheel
212 | */
213 | private void justify() {
214 | listener.onJustify();
215 | setNextMessage(MESSAGE_JUSTIFY);
216 | }
217 |
218 | /**
219 | * Starts scrolling
220 | */
221 | private void startScrolling() {
222 | if (!isScrollingPerformed) {
223 | isScrollingPerformed = true;
224 | listener.onStarted();
225 | }
226 | }
227 |
228 | /**
229 | * Finishes scrolling
230 | */
231 | void finishScrolling() {
232 | if (isScrollingPerformed) {
233 | listener.onFinished();
234 | isScrollingPerformed = false;
235 | }
236 | }
237 | }
238 |
--------------------------------------------------------------------------------
/rulberview/src/main/res/drawable-xxhdpi/ruler_mid_arraw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sanjay-F/RulerView/fc45621c9664a542aaf099a9a40e10ba33f29911/rulberview/src/main/res/drawable-xxhdpi/ruler_mid_arraw.png
--------------------------------------------------------------------------------
/rulberview/src/main/res/drawable-xxhdpi/ruler_mid_arraw_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sanjay-F/RulerView/fc45621c9664a542aaf099a9a40e10ba33f29911/rulberview/src/main/res/drawable-xxhdpi/ruler_mid_arraw_down.png
--------------------------------------------------------------------------------
/rulberview/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | - 1
7 | - 3
8 | - 5
9 | - 11
10 | - 13
11 | - 19
12 | - 30
13 | - 46
14 | - 90
15 | - 104
16 | - 247
17 | - 422
18 |
19 |
20 |
--------------------------------------------------------------------------------
/rulberview/src/main/res/values/attrs_ruler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/rulberview/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | RulberView
3 |
4 |
--------------------------------------------------------------------------------
/rulberview/src/test/java/com/xk/sanjay/rulberview/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.xk.sanjay.rulberview;
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 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':rulberview'
2 |
--------------------------------------------------------------------------------