├── .gitignore
├── .idea
├── .name
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── gradle.xml
├── misc.xml
├── modules.xml
└── vcs.xml
├── Calendar.iml
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── images
├── 1.gif
└── 2.gif
├── library
├── .gitignore
├── build.gradle
├── library.iml
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── cn
│ │ └── zhangzhikai
│ │ └── calendarview
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── cn
│ │ │ └── zhikaizhang
│ │ │ └── calendarview
│ │ │ ├── CalendarView.java
│ │ │ ├── Constant.java
│ │ │ ├── ICalendarView.java
│ │ │ └── RenderUtil.java
│ └── res
│ │ └── values
│ │ ├── attrs.xml
│ │ └── strings.xml
│ └── test
│ └── java
│ └── cn
│ └── zhangzhikai
│ └── calendar_view_library
│ └── ExampleUnitTest.java
├── pickerview
├── .gitignore
├── build.gradle
├── pickerview.iml
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── bigkoo
│ │ └── pickerview
│ │ └── ApplicationTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── bigkoo
│ │ └── pickerview
│ │ ├── MyTimePickerView.java
│ │ ├── OptionsPickerView.java
│ │ ├── TimePickerView.java
│ │ ├── adapter
│ │ ├── ArrayWheelAdapter.java
│ │ ├── NumericWheelAdapter.java
│ │ └── WheelAdapter.java
│ │ ├── lib
│ │ ├── InertiaTimerTask.java
│ │ ├── LoopViewGestureListener.java
│ │ ├── MessageHandler.java
│ │ ├── OnItemSelectedRunnable.java
│ │ ├── SmoothScrollTimerTask.java
│ │ └── WheelView.java
│ │ ├── listener
│ │ ├── OnDismissListener.java
│ │ └── OnItemSelectedListener.java
│ │ ├── utils
│ │ └── PickerViewAnimateUtil.java
│ │ └── view
│ │ ├── BasePickerView.java
│ │ ├── WheelOptions.java
│ │ └── WheelTime.java
│ └── res
│ ├── anim
│ ├── slide_in_bottom.xml
│ └── slide_out_bottom.xml
│ ├── drawable
│ └── selector_pickerview_btn.xml
│ ├── layout
│ ├── include_pickerview_topbar.xml
│ ├── layout_basepickerview.xml
│ ├── my_time_picker_view.xml
│ ├── pickerview_options.xml
│ └── pickerview_time.xml
│ └── values
│ ├── attrs.xml
│ ├── bools.xml
│ ├── colors.xml
│ ├── dimens.xml
│ ├── integers.xml
│ └── strings.xml
├── sample
├── .gitignore
├── build.gradle
├── proguard-rules.pro
├── sample.iml
└── src
│ ├── androidTest
│ └── java
│ │ └── cn
│ │ └── zhangzhikai
│ │ └── demo
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── cn
│ │ │ └── zhikaizhang
│ │ │ └── calendarviewdemo
│ │ │ ├── Demo0.java
│ │ │ ├── Demo1.java
│ │ │ └── MainActivity.java
│ └── res
│ │ ├── drawable-hdpi
│ │ ├── down.png
│ │ └── right.png
│ │ ├── drawable
│ │ └── bg.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── mode0.xml
│ │ └── mode1.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── values-v21
│ │ └── styles.xml
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── cn
│ └── zhangzhikai
│ └── calendar
│ └── ExampleUnitTest.java
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 | /captures
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | Calendar
--------------------------------------------------------------------------------
/.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 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
20 |
21 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | 1.8
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Calendar.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Android-CalendarView
2 | ====================
3 | #### normal mode
4 | 
5 |
6 | #### record mode
7 | 
8 |
9 | Support `API LEVEL >= 7`.
10 |
11 | Including In Your Project
12 | -------------------------
13 |
14 | #### Gradle
15 | Add the following code in the build.gradle of your module.
16 | ```groovy
17 | dependencies {
18 | compile 'cn.zhikaizhang.calendar:library:1.0.1'
19 | }
20 | ```
21 | #### Download the source code
22 | You can also download the source code of the project and import the library module into your project as a module so that you can modify the source code.
23 |
24 | Usage
25 | -----
26 | *For a working implementation of this project see the `sample/` folder.*
27 |
28 | Step1. Include one of the widgets in your xml. You can set the mode 0 for the normal mode and 1 for the record mode. You can also specify the mode in your java code.
29 | ```xml
30 |
35 |
36 | ```
37 | Step2. Refresh the CalendarView. You will use refresh0() for the normal calendar mode and refresh1() for the record mode.
38 | ```java
39 | calendarView.setMode(0);
40 | //refresh the CalendarView with new values of year and month
41 | calendarView.refresh0(year, month);
42 |
43 | calendarView.setMode(1);
44 | //simulate to get data
45 | int days = calendarView.daysOfCurrentMonth();
46 | boolean data[] = new boolean[days+1];
47 | int today = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
48 | for(int i = 1; i <= days; i++){
49 | if(i <= today){
50 | data[i] = (Math.random() > 0.5);
51 | }else{
52 | data[i] = false;
53 | }
54 | }
55 | calendarView.refresh1(data);
56 | ```
57 | Step3. Set the appearance you like. You can set the language to English or Chinese. You can also modify the color and size of the text.
58 | ```java
59 | /**
60 | * modify the language of head of the calendar
61 | * legal values of style : 0 - 3
62 | * 0, 1, 2 : Chinese, 3 : English
63 | */
64 | calendarView.setWeekTextStyle(style);
65 |
66 | //set the text color of the head
67 | calendarView.setWeekTextColor(Color.BLACK);
68 |
69 | /**
70 | * set the scale of text size of the head
71 | * legal values : 0.0f - 1.0f
72 | */
73 | calendarView.setWeekTextSizeScale(0.5f);
74 |
75 | //set the text color of the calendar cell
76 | calendarView.setCalendarTextColor(Color.BLACK);
77 |
78 | /**
79 | * set the scale of text size of the calendar cell
80 | * legal values : 0.0f - 1.0f
81 | */
82 | calendarView.setTextSizeScale(0.5f);
83 |
84 | /**
85 | * set the color of the text of selected day
86 | */
87 | calendarView.setSelectedDayTextColor(Color.WHITE);
88 |
89 | /**
90 | * set the color of the background of selected day
91 | */
92 | calendarView.setSelectedDayBgColor(Color.rgb(124, 180, 246));
93 |
94 | /**
95 | * set the color of the background of today
96 | */
97 | calendarView.setTodayBgColor(Color.rgb(124, 180, 246));
98 | ```
99 | Step4. Implement the callback. Set the OnRefreshListener to do what you want after you refresh the calendar and set the OnItemClickListener to do what you want after you click a day.
100 | ```java
101 | calendarView.setOnRefreshListener(new ICalendarView.OnRefreshListener() {
102 | @Override
103 | public void onRefresh() {
104 | yearMonthTextView.setText(getYearMonthText(calendarView.getYear(), calendarView.getMonth()));
105 | }
106 | });
107 |
108 | calendarView.setOnItemClickListener(new ICalendarView.OnItemClickListener() {
109 | @Override
110 | public void onItemClick(int day) {
111 | int year = calendarView.getYear();
112 | int month = calendarView.getMonth();
113 | Toast.makeText(Demo0.this, year + "-" + month + "-" + day, Toast.LENGTH_SHORT).show();
114 | }
115 | });
116 | ```
117 |
118 | Author
119 | ======
120 |
121 | * ZhikaiZhang
122 | * Email
123 | * Blog
124 | * [android自定义控件之日历控件的实现](http://zhikaizhang.cn/2016/05/21/android%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8E%A7%E4%BB%B6%E4%B9%8B%E6%97%A5%E5%8E%86%E6%8E%A7%E4%BB%B6%E7%9A%84%E5%AE%9E%E7%8E%B0/)
125 |
126 | License
127 | =======
128 |
129 | Copyright 2016 ZhikaiZhang
130 |
131 | Licensed under the Apache License, Version 2.0 (the "License");
132 | you may not use this file except in compliance with the License.
133 | You may obtain a copy of the License at
134 |
135 | http://www.apache.org/licenses/LICENSE-2.0
136 |
137 | Unless required by applicable law or agreed to in writing, software
138 | distributed under the License is distributed on an "AS IS" BASIS,
139 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
140 | See the License for the specific language governing permissions and
141 | limitations under the License.
142 |
143 |
--------------------------------------------------------------------------------
/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.3.0'
9 | //classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3'
10 | //classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.0'
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 |
--------------------------------------------------------------------------------
/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/laserwave/calendar_view/d1bd8457868457fae4f9228ede552c63ba9e6f3a/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu May 19 19:24:43 CST 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.4-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/images/1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laserwave/calendar_view/d1bd8457868457fae4f9228ede552c63ba9e6f3a/images/1.gif
--------------------------------------------------------------------------------
/images/2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laserwave/calendar_view/d1bd8457868457fae4f9228ede552c63ba9e6f3a/images/2.gif
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | //apply plugin: 'com.github.dcendents.android-maven'
3 | //apply plugin: 'com.jfrog.bintray'
4 | version = "1.0.1"
5 |
6 | android {
7 | compileSdkVersion 23
8 | buildToolsVersion "23.0.2"
9 | resourcePrefix "calendarview__"
10 | defaultConfig {
11 | minSdkVersion 7
12 | targetSdkVersion 23
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 | }
23 |
24 | dependencies {
25 | compile fileTree(dir: 'libs', include: ['*.jar'])
26 | testCompile 'junit:junit:4.12'
27 | compile 'com.android.support:appcompat-v7:23.2.0'
28 | }
29 | /*
30 | def siteUrl = 'https://github.com/laserwave/Android-CalendarView'
31 | def gitUrl = 'https://github.com/laserwave/Android-CalendarView.git'
32 | group = "cn.zhikaizhang.calendar" // Maven Group ID for the artifact
33 | install {
34 | repositories.mavenInstaller {
35 | // This generates POM.xml with proper parameters
36 | pom {
37 | project {
38 | packaging 'aar'
39 | // Add your description here
40 | name 'Android-CalendarView' //项目描述
41 | url siteUrl
42 | // Set your license
43 | licenses {
44 | license {
45 | name 'The Apache Software License, Version 2.0'
46 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
47 | }
48 | }
49 | developers {
50 | developer {
51 | id 'zhikaizhang' //填写的一些基本信息
52 | name 'zhikaizhang'
53 | email 'zhikaizhang@seu.edu.cn'
54 | }
55 | }
56 | scm {
57 | connection gitUrl
58 | developerConnection gitUrl
59 | url siteUrl
60 | }
61 | }
62 | }
63 | }
64 | }
65 | task sourcesJar(type: Jar) {
66 | from android.sourceSets.main.java.srcDirs
67 | classifier = 'sources'
68 | }
69 | task javadoc(type: Javadoc) {
70 | source = android.sourceSets.main.java.srcDirs
71 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
72 | }
73 | task javadocJar(type: Jar, dependsOn: javadoc) {
74 | classifier = 'javadoc'
75 | from javadoc.destinationDir
76 | }
77 | artifacts {
78 | archives javadocJar
79 | archives sourcesJar
80 | }
81 | Properties properties = new Properties()
82 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
83 | bintray {
84 | user = properties.getProperty("bintray.user")
85 | key = properties.getProperty("bintray.apikey")
86 | configurations = ['archives']
87 | pkg {
88 | repo = "maven"
89 | name = "Android-CalendarView" //发布到JCenter上的项目名字
90 | websiteUrl = siteUrl
91 | vcsUrl = gitUrl
92 | licenses = ["Apache-2.0"]
93 | publish = true
94 | }
95 | }
96 | */
97 |
--------------------------------------------------------------------------------
/library/library.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | generateDebugAndroidTestSources
19 | generateDebugSources
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 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/library/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\AndroidStudio\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 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/cn/zhangzhikai/calendarview/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package cn.zhangzhikai.calendarview;
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 | }
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/library/src/main/java/cn/zhikaizhang/calendarview/CalendarView.java:
--------------------------------------------------------------------------------
1 | package cn.zhikaizhang.calendarview;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.Paint;
8 | import android.graphics.Typeface;
9 | import android.util.AttributeSet;
10 | import android.util.DisplayMetrics;
11 | import android.view.MotionEvent;
12 | import android.view.View;
13 | import android.view.WindowManager;
14 |
15 | import java.util.Calendar;
16 |
17 | import cn.zhikaizhang.library.R;
18 |
19 | public class CalendarView extends View implements View.OnTouchListener, ICalendarView {
20 |
21 | private int selectedYear;
22 |
23 | private int selectedMonth;
24 |
25 | /**
26 | * correspond to xxxx(year)-xx(month)-1(day)
27 | */
28 | private Calendar calendar;
29 |
30 | /**
31 | * the calendar needs a 6*7 matrix to store
32 | * date[i] represents the day of position i
33 | */
34 | private int[] date = new int[42];
35 |
36 | /**
37 | * the width of the telephone screen
38 | */
39 | private int screenWidth;
40 |
41 | /**
42 | * the index in date[] of the first day of current month
43 | */
44 | private int curStartIndex;
45 |
46 | /**
47 | * the index in date[] of the last day of current month
48 | */
49 | private int curEndIndex;
50 |
51 | /**
52 | * the index in date[] of today
53 | */
54 | private int todayIndex = -1;
55 |
56 | /**
57 | * [only used for MODE_SHOW_DATA_OF_THIS_MONTH]
58 | * data[i] indicates whether completing the plan on the ith day of current month (such as running in JOY RUN)
59 | */
60 | private boolean[] data = new boolean[32];
61 |
62 | /**
63 | * record the index in date[] of the last ACTION_DOWN event
64 | */
65 | private int actionDownIndex = -1;
66 |
67 | /**
68 | * record the selected index in date[]
69 | */
70 | private int selectedIndex = -1;
71 |
72 | private OnItemClickListener onItemClickListener;
73 |
74 | private OnRefreshListener onRefreshListener;
75 |
76 | /**
77 | * two legal values:
78 | * MODE_CALENDAR (0) : normal calendar
79 | * MODE_SHOW_DATA_OF_THIS_MONTH (1) : record the completion of the task in the month
80 | */
81 | private int mode;
82 |
83 |
84 | /**
85 | * following are some parameters for rendering the widget
86 | */
87 | private float cellWidth;
88 | private float cellHeight;
89 | private String[] weekText;
90 | private int textColor = Constant.TEXT_COLOR;
91 | private int backgroundColor = Constant.BACKGROUND_COLOR;
92 | private Paint textPaint;
93 | private Paint weekTextPaint;
94 | private Paint grayPaint;
95 | private Paint whitePaint;
96 | private Paint bluePaint;
97 | private Paint blackPaint;
98 | private Paint todayBgPaint;
99 | private Paint selectedDayBgPaint;
100 | private Paint selectedDayTextPaint;
101 |
102 |
103 | public CalendarView(Context context, AttributeSet attrs, int defStyle) {
104 |
105 | super(context, attrs, defStyle);
106 |
107 | /**
108 | * read the attribute in the layout xml
109 | */
110 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CalendarView);
111 | mode = typedArray.getInt(R.styleable.CalendarView_mode, Constant.MODE_SHOW_DATA_OF_THIS_MONTH);
112 |
113 | /**
114 | * default choose the current month of real life
115 | */
116 | calendar = Calendar.getInstance();
117 | selectedYear = calendar.get(Calendar.YEAR);
118 | selectedMonth = calendar.get(Calendar.MONTH) + 1;
119 | calendar.set(Calendar.DAY_OF_MONTH, 1);
120 |
121 | /**
122 | * get the width of the screen of the phone
123 | */
124 | WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
125 | DisplayMetrics dm = new DisplayMetrics();
126 | wm.getDefaultDisplay().getMetrics(dm);
127 | screenWidth = dm.widthPixels;
128 |
129 | /**
130 | * set the width and height of a cell of the calendar
131 | */
132 | cellWidth = screenWidth / 7f;
133 | cellHeight = cellWidth * 0.7f;
134 |
135 | setBackgroundColor(backgroundColor);
136 |
137 | weekText = getResources().getStringArray(Constant.WEEK_TEXT[0]);
138 |
139 | setOnTouchListener(this);
140 |
141 | textPaint = RenderUtil.getPaint(textColor);
142 | textPaint.setTextSize(cellHeight * 0.4f);
143 |
144 | /**
145 | * paint for head of the calendar
146 | */
147 | weekTextPaint = RenderUtil.getPaint(textColor);
148 | weekTextPaint.setTextSize(cellHeight * 0.4f);
149 | weekTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
150 |
151 | whitePaint = RenderUtil.getPaint(Color.WHITE);
152 |
153 | blackPaint = RenderUtil.getPaint(Color.BLACK);
154 |
155 | bluePaint = RenderUtil.getPaint(Color.rgb(92, 158, 237));
156 |
157 | grayPaint = RenderUtil.getPaint(Color.rgb(200, 200, 200));
158 |
159 | todayBgPaint = RenderUtil.getPaint(Color.rgb(124, 180, 246));
160 | todayBgPaint.setStrokeWidth(3);
161 | todayBgPaint.setStyle(Paint.Style.STROKE);
162 |
163 | selectedDayBgPaint = RenderUtil.getPaint(Color.rgb(124, 180, 246));
164 |
165 | selectedDayTextPaint = RenderUtil.getPaint(Color.WHITE);
166 | selectedDayTextPaint.setTextSize(cellHeight * 0.4f);
167 |
168 | initial();
169 |
170 | }
171 |
172 | public CalendarView(Context context, AttributeSet attrs) {
173 | this(context, attrs, 0);
174 | }
175 |
176 | public CalendarView(Context context) {
177 | this(context, null);
178 | }
179 |
180 | @Override
181 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
182 | widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(screenWidth, View.MeasureSpec.EXACTLY);
183 | heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(measureHeight(), View.MeasureSpec.EXACTLY);
184 | setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
185 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
186 | }
187 |
188 | /**
189 | * calculate the total height of the widget
190 | */
191 | private int measureHeight(){
192 | /**
193 | * the weekday of the first day of the month, Sunday's result is 1 and Monday 2 and Saturday 7, etc.
194 | */
195 | int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
196 | /**
197 | * the number of days of current month
198 | */
199 | int daysOfMonth = daysOfCurrentMonth();
200 | /**
201 | * calculate the total lines, which equals to 1 (head of the calendar) + 1 (the first line) + n/7 + (n%7==0?0:1)
202 | * and n means number of days except first line of the calendar
203 | */
204 | int n = -1;
205 | if(dayOfWeek >= 2 && dayOfWeek <= 7){
206 | n = daysOfMonth - (8 - dayOfWeek + 1);
207 | }else if(dayOfWeek == 1){
208 | n = daysOfMonth - 1;
209 | }
210 | int lines = 2 + n / 7 + (n % 7 == 0 ? 0 : 1);
211 | return (int) (cellHeight * lines);
212 | }
213 |
214 | /**
215 | * calculate the values of date[] and the legal range of index of date[]
216 | */
217 | private void initial() {
218 | int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
219 | int monthStart = -1;
220 | if(dayOfWeek >= 2 && dayOfWeek <= 7){
221 | monthStart = dayOfWeek - 2;
222 | }else if(dayOfWeek == 1){
223 | monthStart = 6;
224 | }
225 | curStartIndex = monthStart;
226 | date[monthStart] = 1;
227 | int daysOfMonth = daysOfCurrentMonth();
228 | for (int i = 1; i < daysOfMonth; i++) {
229 | date[monthStart + i] = i + 1;
230 | }
231 | curEndIndex = monthStart + daysOfMonth;
232 | if(mode == Constant.MODE_SHOW_DATA_OF_THIS_MONTH){
233 | todayIndex = Calendar.getInstance().get(Calendar.DAY_OF_MONTH) + monthStart - 1;
234 | }else if(mode == Constant.MODE_CALENDAR){
235 | //the year and month selected is the current year and month
236 | if(calendar.get(Calendar.YEAR) == Calendar.getInstance().get(Calendar.YEAR)
237 | && calendar.get(Calendar.MONTH) == Calendar.getInstance().get(Calendar.MONTH)){
238 | todayIndex = Calendar.getInstance().get(Calendar.DAY_OF_MONTH) + monthStart - 1;
239 | }else{
240 | todayIndex = -1;
241 | }
242 | }
243 | }
244 |
245 | /**
246 | * y is bigger than the head of the calendar, meaning that the coordination may represent a day
247 | * of the calendar
248 | */
249 | private boolean coordIsCalendarCell(float y){
250 | return y > cellHeight;
251 | }
252 |
253 | /**
254 | * calculate the index of date[] according to the coordination
255 | */
256 | private int getIndexByCoordinate(float x, float y){
257 | int m = (int) (Math.floor(x / cellWidth) + 1);
258 | int n = (int) (Math.floor((y - cellHeight) / cellHeight) + 1);
259 | return (n - 1) * 7 + m - 1;
260 | }
261 |
262 | /**
263 | * whether the index is legal
264 | * @param i the index in date[]
265 | * @return
266 | */
267 | private boolean isLegalIndex(int i){
268 | return !isIllegalIndex(i);
269 | }
270 |
271 | /**
272 | * whether the index is illegal
273 | * @param i the index in date[]
274 | * @return
275 | */
276 | private boolean isIllegalIndex(int i){
277 | return i < curStartIndex || i >= curEndIndex;
278 | }
279 |
280 | /**
281 | * calculate the x position according to the index in date[]
282 | * @param i the index in date[]
283 | * @return
284 | */
285 | private int getXByIndex(int i) {
286 | return i % 7 + 1;
287 | }
288 |
289 | /**
290 | * calculate the y position according to the index in date[]
291 | * @param i the index in date[]
292 | * @return
293 | */
294 | private int getYByIndex(int i) {
295 | return i / 7 + 1;
296 | }
297 |
298 |
299 | /**
300 | * render
301 | */
302 | @Override
303 | protected void onDraw(Canvas canvas) {
304 |
305 | super.onDraw(canvas);
306 |
307 | /**
308 | * render the head
309 | */
310 | float baseline = RenderUtil.getBaseline(0, cellHeight, weekTextPaint);
311 | for (int i = 0; i < 7; i++) {
312 | float weekTextX = RenderUtil.getStartX(cellWidth * i + cellWidth * 0.5f, weekTextPaint, weekText[i]);
313 | canvas.drawText(weekText[i], weekTextX, baseline, weekTextPaint);
314 | }
315 |
316 | if(mode == Constant.MODE_CALENDAR){
317 | for (int i = curStartIndex; i < curEndIndex; i++) {
318 | if(i == todayIndex && i == selectedIndex){
319 | drawCircle(canvas, i, selectedDayBgPaint, cellHeight * 0.48f);
320 | drawText(canvas, i, selectedDayTextPaint, "" + date[i]);
321 | }else if(i == todayIndex){
322 | drawCircle(canvas, i, todayBgPaint, cellHeight * 0.48f);
323 | drawText(canvas, i, textPaint, "" + date[i]);
324 | }else if(i == selectedIndex){
325 | drawCircle(canvas, i, selectedDayBgPaint, cellHeight * 0.48f);
326 | drawText(canvas, i, selectedDayTextPaint, "" + date[i]);
327 | }else{
328 | drawText(canvas, i, textPaint, "" + date[i]);
329 | }
330 |
331 | }
332 | }else if(mode == Constant.MODE_SHOW_DATA_OF_THIS_MONTH){
333 | for (int i = curStartIndex; i < curEndIndex; i++) {
334 | if(i < todayIndex){
335 | if(data[date[i]]){
336 | drawCircle(canvas, i, bluePaint, cellHeight * 0.37f);
337 | drawCircle(canvas, i, whitePaint, cellHeight * 0.31f);
338 | drawCircle(canvas, i, blackPaint, cellHeight * 0.1f);
339 | }else{
340 | drawCircle(canvas, i, grayPaint, cellHeight * 0.1f);
341 | }
342 | }else if(i == todayIndex){
343 | if(data[date[i]]){
344 | drawCircle(canvas, i, bluePaint, cellHeight * 0.37f);
345 | drawCircle(canvas, i, whitePaint, cellHeight * 0.31f);
346 | drawCircle(canvas, i, blackPaint, cellHeight * 0.1f);
347 | }else{
348 | drawCircle(canvas, i, grayPaint, cellHeight * 0.37f);
349 | drawCircle(canvas, i, whitePaint, cellHeight * 0.31f);
350 | drawCircle(canvas, i, blackPaint, cellHeight * 0.1f);
351 | }
352 | }else{
353 | drawText(canvas, i, textPaint, "" + date[i]);
354 | }
355 | }
356 | }
357 |
358 | }
359 |
360 | /**
361 | * draw text, around the middle of the cell decided by the index
362 | */
363 | private void drawText(Canvas canvas, int index, Paint paint, String text) {
364 | if(isIllegalIndex(index)){
365 | return;
366 | }
367 | int x = getXByIndex(index);
368 | int y = getYByIndex(index);
369 | float top = cellHeight + (y - 1) * cellHeight;
370 | float bottom = top + cellHeight;
371 | float baseline = RenderUtil.getBaseline(top, bottom, paint);
372 | float startX = RenderUtil.getStartX(cellWidth * (x - 1) + cellWidth * 0.5f, paint, text);
373 | canvas.drawText(text, startX, baseline, paint);
374 | }
375 |
376 | /**
377 | * draw circle, around the middle of the cell decided by the index
378 | */
379 | private void drawCircle(Canvas canvas, int index, Paint paint, float radius){
380 | if(isIllegalIndex(index)){
381 | return;
382 | }
383 | int x = getXByIndex(index);
384 | int y = getYByIndex(index);
385 | float centreY = cellHeight + (y - 1) * cellHeight + cellHeight * 0.5f;
386 | float centreX = cellWidth * (x - 1) + cellWidth * 0.5f;
387 | canvas.drawCircle(centreX, centreY, radius, paint);
388 | }
389 |
390 | @Override
391 | public boolean onTouch(View v, MotionEvent event) {
392 | float x = event.getX();
393 | float y = event.getY();
394 | switch (event.getAction()) {
395 | case MotionEvent.ACTION_DOWN:
396 | if(coordIsCalendarCell(y)){
397 | int index = getIndexByCoordinate(x, y);
398 | if(isLegalIndex(index)) {
399 | actionDownIndex = index;
400 | selectedIndex = -1;
401 | }
402 | }
403 | break;
404 | case MotionEvent.ACTION_UP:
405 | if(coordIsCalendarCell(y)){
406 | int actionUpIndex = getIndexByCoordinate(x, y);
407 | if(isLegalIndex(actionUpIndex)){
408 | if(actionDownIndex == actionUpIndex){
409 | selectedIndex = actionUpIndex;
410 | actionDownIndex = -1;
411 | int day = date[actionUpIndex];
412 | if(onItemClickListener != null){
413 | onItemClickListener.onItemClick(day);
414 | }
415 | invalidate();
416 | }
417 | }
418 | }
419 | break;
420 | }
421 | return true;
422 | }
423 |
424 | private static int leap(int year){
425 | return (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)?1:0;
426 | }
427 |
428 | @Override
429 | public int daysOfCurrentMonth(){
430 | return Constant.DAYS_OF_MONTH[leap(selectedYear)][selectedMonth];
431 | }
432 |
433 | @Override
434 | public int getYear(){
435 | return selectedYear;
436 | }
437 |
438 | /**
439 | * legal values : 1-12
440 | */
441 | @Override
442 | public int getMonth(){
443 | return selectedMonth;
444 | }
445 |
446 | @Override
447 | public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
448 | this.onItemClickListener = onItemClickListener;
449 | }
450 |
451 | /**
452 | * used for MODE_CALENDAR
453 | * legal values of month: 1-12
454 | */
455 | @Override
456 | public void refresh0(int year, int month) {
457 | if(mode == Constant.MODE_CALENDAR){
458 | selectedYear = year;
459 | selectedMonth = month;
460 | selectedIndex = -1;
461 | calendar.set(Calendar.YEAR, selectedYear);
462 | calendar.set(Calendar.MONTH, selectedMonth - 1);
463 | calendar.set(Calendar.DAY_OF_MONTH, 1);
464 | initial();
465 | invalidate();
466 | if(onRefreshListener != null){
467 | onRefreshListener.onRefresh();
468 | }
469 | }
470 | }
471 |
472 | /**
473 | * used for MODE_SHOW_DATA_OF_THIS_MONTH
474 | * the index 1 to 31(big month), 1 to 30(small month), 1 - 28(Feb of normal year), 1 - 29(Feb of leap year)
475 | * is better to be accessible in the parameter data, illegal indexes will be ignored with default false value
476 | */
477 | @Override
478 | public void refresh1(boolean[] data) {
479 | /**
480 | * the month and year may change (eg. Jan 31st becomes Feb 1st after refreshing)
481 | */
482 | if(mode == Constant.MODE_SHOW_DATA_OF_THIS_MONTH){
483 | calendar = Calendar.getInstance();
484 | selectedYear = calendar.get(Calendar.YEAR);
485 | selectedMonth = calendar.get(Calendar.MONTH) + 1;
486 | calendar.set(Calendar.DAY_OF_MONTH, 1);
487 | for(int i = 1; i <= daysOfCurrentMonth(); i++){
488 | if(i < data.length){
489 | this.data[i] = data[i];
490 | }else{
491 | this.data[i] = false;
492 | }
493 | }
494 | initial();
495 | invalidate();
496 | if(onRefreshListener != null){
497 | onRefreshListener.onRefresh();
498 | }
499 | }
500 | }
501 |
502 | @Override
503 | public void setMode(int mode) {
504 | if(mode == Constant.MODE_SHOW_DATA_OF_THIS_MONTH || mode == Constant.MODE_CALENDAR){
505 | this.mode = mode;
506 | }
507 | }
508 |
509 | /**
510 | * legal values : 0-3
511 | */
512 | @Override
513 | public void setWeekTextStyle(int style) {
514 | if(style >= 0 && style <= 3){
515 | weekText = getResources().getStringArray(Constant.WEEK_TEXT[style]);
516 | }
517 | }
518 |
519 | @Override
520 | public void setWeekTextColor(int color) {
521 | weekTextPaint.setColor(color);
522 | }
523 |
524 | @Override
525 | public void setCalendarTextColor(int color) {
526 | textPaint.setColor(color);
527 | }
528 |
529 | /**
530 | * legal values : 0-1
531 | */
532 | @Override
533 | public void setWeekTextSizeScale(float scale) {
534 | if(scale >= 0 && scale <= 1){
535 | weekTextPaint.setTextSize(cellHeight * 0.5f * scale);
536 | }
537 | }
538 |
539 | /**
540 | * legal values : 0-1
541 | */
542 | @Override
543 | public void setTextSizeScale(float scale) {
544 | if(scale >= 0 && scale <= 1) {
545 | textPaint.setTextSize(cellHeight * 0.5f * scale);
546 | selectedDayTextPaint.setTextSize(cellHeight * 0.5f * scale);
547 | }
548 | }
549 |
550 |
551 | @Override
552 | public void setSelectedDayTextColor(int color) {
553 | selectedDayTextPaint.setColor(color);
554 | }
555 |
556 | @Override
557 | public void setSelectedDayBgColor(int color) {
558 | selectedDayBgPaint.setColor(color);
559 | }
560 |
561 | @Override
562 | public void setTodayBgColor(int color) {
563 | todayBgPaint.setColor(color);
564 | }
565 |
566 | @Override
567 | public Calendar getCalendar() {
568 | return calendar;
569 | }
570 |
571 |
572 | @Override
573 | public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
574 | this.onRefreshListener = onRefreshListener;
575 | }
576 |
577 | /**
578 | * used for MODE_SHOW_DATA_OF_THIS_MONTH
579 | */
580 | @Override
581 | public int daysCompleteTheTask() {
582 | int k = 0;
583 | for(int i = 1; i <= daysOfCurrentMonth(); i++){
584 | k += data[i]?1:0;
585 | }
586 | return k;
587 | }
588 | }
589 |
--------------------------------------------------------------------------------
/library/src/main/java/cn/zhikaizhang/calendarview/Constant.java:
--------------------------------------------------------------------------------
1 | package cn.zhikaizhang.calendarview;
2 |
3 | import android.graphics.Color;
4 |
5 | import cn.zhikaizhang.library.R;
6 |
7 | public class Constant {
8 |
9 |
10 | public static final int[] WEEK_TEXT = {R.array.calendarview__weektext_0, R.array.calendarview__weektext_1, R.array.calendarview__weektext_2, R.array.calendarview__weektext_3};
11 |
12 | public static final int TEXT_COLOR = Color.BLACK;
13 |
14 | public static final int BACKGROUND_COLOR = Color.WHITE;
15 |
16 | public static final int DAYS_OF_MONTH[][] = new int[][]{{-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {-1, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
17 |
18 | public static final int MODE_CALENDAR = 0;
19 |
20 | public static final int MODE_SHOW_DATA_OF_THIS_MONTH = 1;
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/library/src/main/java/cn/zhikaizhang/calendarview/ICalendarView.java:
--------------------------------------------------------------------------------
1 | package cn.zhikaizhang.calendarview;
2 |
3 | import java.util.Calendar;
4 |
5 | public interface ICalendarView {
6 |
7 | /**
8 | * only used for MODE_CALENDAR
9 | */
10 | void refresh0(int year, int month);
11 |
12 | void setSelectedDayTextColor(int color);
13 |
14 | void setSelectedDayBgColor(int color);
15 |
16 | void setTodayBgColor(int color);
17 |
18 | /**
19 | * only used for MODE_SHOW_DATA_OF_THIS_MONTH
20 | */
21 | void refresh1(boolean data[]);
22 |
23 | int daysCompleteTheTask();
24 |
25 | /**
26 | * used for both
27 | */
28 | void setWeekTextStyle(int style);
29 |
30 | void setWeekTextColor(int color);
31 |
32 | void setCalendarTextColor(int color);
33 |
34 | void setWeekTextSizeScale(float scale);
35 |
36 | void setTextSizeScale(float scale);
37 |
38 | void setMode(int mode);
39 |
40 | int getYear();
41 |
42 | int getMonth();
43 |
44 | int daysOfCurrentMonth();
45 |
46 | Calendar getCalendar();
47 |
48 | void setOnItemClickListener(OnItemClickListener onItemClickListener);
49 |
50 | void setOnRefreshListener(OnRefreshListener onRefreshListener);
51 |
52 | interface OnItemClickListener{
53 | void onItemClick(int day);
54 | }
55 |
56 | interface OnRefreshListener{
57 | void onRefresh();
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/library/src/main/java/cn/zhikaizhang/calendarview/RenderUtil.java:
--------------------------------------------------------------------------------
1 | package cn.zhikaizhang.calendarview;
2 |
3 | import android.graphics.Paint;
4 |
5 | public class RenderUtil {
6 |
7 | /**
8 | * get the baseline to draw between top and bottom in the middle
9 | */
10 | public static float getBaseline(float top, float bottom, Paint paint){
11 | Paint.FontMetrics fontMetrics = paint.getFontMetrics();
12 | return (top + bottom - fontMetrics.bottom - fontMetrics.top) / 2;
13 | }
14 |
15 | /**
16 | * get the x position to draw around the middle
17 | */
18 | public static float getStartX(float middle, Paint paint, String text){
19 | return middle - paint.measureText(text) * 0.5f;
20 | }
21 |
22 | public static Paint getPaint(int color){
23 | Paint paint = new Paint();
24 | paint.setColor(color);
25 | paint.setAntiAlias(true);
26 | return paint;
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/library/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/library/src/main/res/values/strings.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 | - Mon
33 | - Tus
34 | - Wed
35 | - Thu
36 | - Fri
37 | - Sat
38 | - Sun
39 |
40 |
41 |
--------------------------------------------------------------------------------
/library/src/test/java/cn/zhangzhikai/calendar_view_library/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package cn.zhangzhikai.calendarview;
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 | }
--------------------------------------------------------------------------------
/pickerview/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/pickerview/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | version = "2.0.8"
4 |
5 | android {
6 | compileSdkVersion 23
7 | buildToolsVersion "23.0.2"
8 |
9 | defaultConfig {
10 | minSdkVersion 7
11 | targetSdkVersion 23
12 | versionCode 1
13 | versionName "1.0"
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | }
22 |
23 | dependencies {
24 | compile fileTree(dir: 'libs', include: ['*.jar'])
25 | }
26 |
27 | //def siteUrl = 'https://github.com/saiwu-bigkoo/Android-PickerView' // #CONFIG# // project homepage
28 | //def gitUrl = 'https://github.com/saiwu-bigkoo/Android-PickerView.git' // #CONFIG# // project git
29 | //group = "com.bigkoo"
30 |
31 | //install {
32 | // repositories.mavenInstaller {
33 | // // This generates POM.xml with proper parameters
34 | // pom {
35 | // project {
36 | // packaging 'aar'
37 | // name 'PickerView For Android' // #CONFIG# // project title
38 | // url siteUrl
39 | // // Set your license
40 | // licenses {
41 | // license {
42 | // name 'The Apache Software License, Version 2.0'
43 | // url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
44 | // }
45 | // }
46 | // developers {
47 | // developer {
48 | // id 'sai' // #CONFIG# // your user id (you can write your nickname)
49 | // name 'sai.wu' // #CONFIG# // your user name
50 | // email 'sai.wu@bigkoo.com' // #CONFIG# // your email
51 | // }
52 | // }
53 | // scm {
54 | // connection gitUrl
55 | // developerConnection gitUrl
56 | // url siteUrl
57 | // }
58 | // }
59 | // }
60 | // }
61 | //}
62 |
63 | task sourcesJar(type: Jar) {
64 | from android.sourceSets.main.java.srcDirs
65 | classifier = 'sources'
66 | }
67 |
68 | task javadoc(type: Javadoc) {
69 | source = android.sourceSets.main.java.srcDirs
70 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
71 | }
72 |
73 | task javadocJar(type: Jar, dependsOn: javadoc) {
74 | classifier = 'javadoc'
75 | from javadoc.destinationDir
76 | }
77 |
78 | artifacts {
79 | archives javadocJar
80 | archives sourcesJar
81 | }
82 |
83 | Properties properties = new Properties()
84 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
85 | //bintray {
86 | // user = properties.getProperty("bintray.user")
87 | // key = properties.getProperty("bintray.apikey")
88 | // configurations = ['archives']
89 | // pkg {
90 | // repo = "maven"
91 | // name = "PickerView" // #CONFIG# project name in jcenter
92 | // websiteUrl = siteUrl
93 | // vcsUrl = gitUrl
94 | // licenses = ["Apache-2.0"]
95 | // publish = true
96 | // }
97 | //}
--------------------------------------------------------------------------------
/pickerview/pickerview.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | generateDebugAndroidTestSources
19 | generateDebugSources
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 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/pickerview/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 /Users/Sai/Documents/software/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 |
--------------------------------------------------------------------------------
/pickerview/src/androidTest/java/com/bigkoo/pickerview/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.bigkoo.pickerview;
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 | }
--------------------------------------------------------------------------------
/pickerview/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/pickerview/src/main/java/com/bigkoo/pickerview/MyTimePickerView.java:
--------------------------------------------------------------------------------
1 | package com.bigkoo.pickerview;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 |
6 | import com.bigkoo.pickerview.view.WheelTime;
7 |
8 | import java.util.Calendar;
9 |
10 | public class MyTimePickerView extends TimePickerView {
11 |
12 |
13 | public MyTimePickerView(Context context) {
14 | super(context, Type.YEAR_MONTH);
15 | }
16 |
17 | @Override
18 | public int getContentViewId() {
19 | return R.layout.my_time_picker_view;
20 | }
21 |
22 | @Override
23 | public void initialWheelTime() {
24 | final View timepickerview = findViewById(R.id.timepicker);
25 | wheelTime = new WheelTime(timepickerview, type);
26 | Calendar calendar = Calendar.getInstance();
27 | calendar.setTimeInMillis(System.currentTimeMillis());
28 | int year = calendar.get(Calendar.YEAR);
29 | int month = calendar.get(Calendar.MONTH);
30 | setRange(1, year + 1000);
31 | wheelTime.setEndMonthDay(month + 1, 0);
32 | wheelTime.setPicker(year, month, 0);
33 | }
34 |
35 |
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/pickerview/src/main/java/com/bigkoo/pickerview/OptionsPickerView.java:
--------------------------------------------------------------------------------
1 | package com.bigkoo.pickerview;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.widget.TextView;
7 |
8 | import com.bigkoo.pickerview.view.BasePickerView;
9 | import com.bigkoo.pickerview.view.WheelOptions;
10 |
11 | import java.util.ArrayList;
12 |
13 | /**
14 | * Created by Sai on 15/11/22.
15 | */
16 | public class OptionsPickerView extends BasePickerView implements View.OnClickListener {
17 | WheelOptions wheelOptions;
18 | private View btnSubmit, btnCancel;
19 | private TextView tvTitle;
20 | private OnOptionsSelectListener optionsSelectListener;
21 | private static final String TAG_SUBMIT = "submit";
22 | private static final String TAG_CANCEL = "cancel";
23 | public OptionsPickerView(Context context) {
24 | super(context);
25 | LayoutInflater.from(context).inflate(getLayoutId(), contentContainer);
26 | // -----确定和取消按钮
27 | btnSubmit = findViewById(R.id.btnSubmit);
28 | btnSubmit.setTag(TAG_SUBMIT);
29 | btnCancel = findViewById(R.id.btnCancel);
30 | btnCancel.setTag(TAG_CANCEL);
31 | btnSubmit.setOnClickListener(this);
32 | btnCancel.setOnClickListener(this);
33 | //顶部标题
34 | tvTitle = (TextView) findViewById(R.id.tvTitle);
35 | // ----转轮
36 | final View optionspicker = findViewById(R.id.optionspicker);
37 | wheelOptions = new WheelOptions(optionspicker);
38 | }
39 |
40 | public int getLayoutId(){
41 | return R.layout.pickerview_options;
42 | }
43 |
44 | public void setPicker(ArrayList optionsItems) {
45 | wheelOptions.setPicker(optionsItems, null, null, false);
46 | }
47 |
48 | public void setPicker(ArrayList options1Items,
49 | ArrayList> options2Items, boolean linkage) {
50 | wheelOptions.setPicker(options1Items, options2Items, null, linkage);
51 | }
52 |
53 | public void setPicker(ArrayList options1Items,
54 | ArrayList> options2Items,
55 | ArrayList>> options3Items,
56 | boolean linkage) {
57 | wheelOptions.setPicker(options1Items, options2Items, options3Items,
58 | linkage);
59 | }
60 | /**
61 | * 设置选中的item位置
62 | * @param option1
63 | */
64 | public void setSelectOptions(int option1){
65 | wheelOptions.setCurrentItems(option1, 0, 0);
66 | }
67 | /**
68 | * 设置选中的item位置
69 | * @param option1
70 | * @param option2
71 | */
72 | public void setSelectOptions(int option1, int option2){
73 | wheelOptions.setCurrentItems(option1, option2, 0);
74 | }
75 | /**
76 | * 设置选中的item位置
77 | * @param option1
78 | * @param option2
79 | * @param option3
80 | */
81 | public void setSelectOptions(int option1, int option2, int option3){
82 | wheelOptions.setCurrentItems(option1, option2, option3);
83 | }
84 | /**
85 | * 设置选项的单位
86 | * @param label1
87 | */
88 | public void setLabels(String label1){
89 | wheelOptions.setLabels(label1, null, null);
90 | }
91 | /**
92 | * 设置选项的单位
93 | * @param label1
94 | * @param label2
95 | */
96 | public void setLabels(String label1,String label2){
97 | wheelOptions.setLabels(label1, label2, null);
98 | }
99 | /**
100 | * 设置选项的单位
101 | * @param label1
102 | * @param label2
103 | * @param label3
104 | */
105 | public void setLabels(String label1,String label2,String label3){
106 | wheelOptions.setLabels(label1, label2, label3);
107 | }
108 | /**
109 | * 设置是否循环滚动
110 | * @param cyclic
111 | */
112 | public void setCyclic(boolean cyclic){
113 | wheelOptions.setCyclic(cyclic);
114 | }
115 | public void setCyclic(boolean cyclic1,boolean cyclic2,boolean cyclic3) {
116 | wheelOptions.setCyclic(cyclic1,cyclic2,cyclic3);
117 | }
118 |
119 |
120 | @Override
121 | public void onClick(View v)
122 | {
123 | String tag=(String) v.getTag();
124 | if(tag.equals(TAG_CANCEL))
125 | {
126 | dismiss();
127 | return;
128 | }
129 | else
130 | {
131 | if(optionsSelectListener!=null)
132 | {
133 | int[] optionsCurrentItems=wheelOptions.getCurrentItems();
134 | optionsSelectListener.onOptionsSelect(optionsCurrentItems[0], optionsCurrentItems[1], optionsCurrentItems[2]);
135 | }
136 | dismiss();
137 | return;
138 | }
139 | }
140 |
141 | public interface OnOptionsSelectListener {
142 | public void onOptionsSelect(int options1, int option2, int options3);
143 | }
144 |
145 | public void setOnoptionsSelectListener(
146 | OnOptionsSelectListener optionsSelectListener) {
147 | this.optionsSelectListener = optionsSelectListener;
148 | }
149 |
150 | public void setTitle(String title){
151 | tvTitle.setText(title);
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/pickerview/src/main/java/com/bigkoo/pickerview/TimePickerView.java:
--------------------------------------------------------------------------------
1 | package com.bigkoo.pickerview;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.widget.TextView;
7 |
8 | import com.bigkoo.pickerview.view.BasePickerView;
9 | import com.bigkoo.pickerview.view.WheelTime;
10 |
11 | import java.text.ParseException;
12 | import java.util.Calendar;
13 | import java.util.Date;
14 |
15 | /**
16 | * Created by Sai on 15/11/22.
17 | */
18 | public class TimePickerView extends BasePickerView implements View.OnClickListener {
19 | public enum Type {
20 | ALL, YEAR_MONTH_DAY, HOURS_MINS, MONTH_DAY_HOUR_MIN , YEAR_MONTH
21 | }// 四种选择模式,年月日时分,年月日,时分,月日时分
22 |
23 | WheelTime wheelTime;
24 | private View btnSubmit, btnCancel;
25 | private TextView tvTitle;
26 | private static final String TAG_SUBMIT = "submit";
27 | protected static final String TAG_CANCEL = "cancel";
28 | protected static final String TAG_NOTHING = "donothing";
29 | protected OnTimeSelectListener timeSelectListener;
30 | Type type;
31 |
32 | public TimePickerView(Context context, Type type) {
33 | super(context);
34 |
35 | LayoutInflater.from(context).inflate(getContentViewId(), contentContainer);
36 | // -----确定和取消按钮
37 | btnSubmit = findViewById(R.id.btnSubmit);
38 | btnSubmit.setTag(TAG_SUBMIT);
39 | btnCancel = findViewById(R.id.btnCancel);
40 | btnCancel.setTag(TAG_CANCEL);
41 | btnSubmit.setOnClickListener(this);
42 | btnCancel.setOnClickListener(this);
43 | //顶部标题
44 | tvTitle = (TextView) findViewById(R.id.tvTitle);
45 | this.type = type;
46 |
47 | initialWheelTime();
48 |
49 |
50 | }
51 |
52 | public int getContentViewId(){
53 | return R.layout.pickerview_time;
54 | }
55 |
56 | /**
57 | * 设置可以选择的时间范围
58 | *
59 | * @param startYear
60 | * @param endYear
61 | */
62 | public void setRange(int startYear, int endYear) {
63 | wheelTime.setStartYear(startYear);
64 | wheelTime.setEndYear(endYear);
65 | }
66 |
67 | /**
68 | * 设置选中时间
69 | * @param date
70 | */
71 | public void setTime(Date date) {
72 | Calendar calendar = Calendar.getInstance();
73 | if (date == null)
74 | calendar.setTimeInMillis(System.currentTimeMillis());
75 | else
76 | calendar.setTime(date);
77 | int year = calendar.get(Calendar.YEAR);
78 | int month = calendar.get(Calendar.MONTH);
79 | int day = calendar.get(Calendar.DAY_OF_MONTH);
80 | int hours = calendar.get(Calendar.HOUR_OF_DAY);
81 | int minute = calendar.get(Calendar.MINUTE);
82 | wheelTime.setPicker(year, month, day, hours, minute);
83 | }
84 |
85 | /**
86 | * 设置是否循环滚动
87 | *
88 | * @param cyclic
89 | */
90 | public void setCyclic(boolean cyclic) {
91 | wheelTime.setCyclic(cyclic);
92 | }
93 |
94 | @Override
95 | public void onClick(View v) {
96 | String tag = (String) v.getTag();
97 | if (tag.equals(TAG_CANCEL)) {
98 | dismiss();
99 | return;
100 | } else if(tag.equals(TAG_NOTHING)){
101 | }
102 | else {
103 | if (timeSelectListener != null) {
104 | try {
105 | Date date = WheelTime.dateFormat.parse(wheelTime.getTime());
106 | timeSelectListener.onTimeSelect(date);
107 | } catch (ParseException e) {
108 | e.printStackTrace();
109 | }
110 | }
111 | dismiss();
112 | return;
113 | }
114 | }
115 |
116 | public interface OnTimeSelectListener {
117 | public void onTimeSelect(Date date);
118 | }
119 |
120 | public void setOnTimeSelectListener(OnTimeSelectListener timeSelectListener) {
121 | this.timeSelectListener = timeSelectListener;
122 | }
123 |
124 | public void setTitle(String title){
125 | tvTitle.setText(title);
126 | }
127 |
128 | public void initialWheelTime(){
129 | // ----时间转轮
130 | final View timepickerview = findViewById(R.id.timepicker);
131 | wheelTime = new WheelTime(timepickerview, type);
132 |
133 | //默认选中当前时间
134 | Calendar calendar = Calendar.getInstance();
135 | calendar.setTimeInMillis(System.currentTimeMillis());
136 | int year = calendar.get(Calendar.YEAR);
137 | int month = calendar.get(Calendar.MONTH);
138 | int day = calendar.get(Calendar.DAY_OF_MONTH);
139 | int hours = calendar.get(Calendar.HOUR_OF_DAY);
140 | int minute = calendar.get(Calendar.MINUTE);
141 | wheelTime.setPicker(year, month, day, hours, minute);
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/pickerview/src/main/java/com/bigkoo/pickerview/adapter/ArrayWheelAdapter.java:
--------------------------------------------------------------------------------
1 | package com.bigkoo.pickerview.adapter;
2 |
3 | import java.util.ArrayList;
4 |
5 | /**
6 | * The simple Array wheel adapter
7 | * @param the element type
8 | */
9 | public class ArrayWheelAdapter implements WheelAdapter {
10 |
11 | /** The default items length */
12 | public static final int DEFAULT_LENGTH = 4;
13 |
14 | // items
15 | private ArrayList items;
16 | // length
17 | private int length;
18 |
19 | /**
20 | * Constructor
21 | * @param items the items
22 | * @param length the max items length
23 | */
24 | public ArrayWheelAdapter(ArrayList items, int length) {
25 | this.items = items;
26 | this.length = length;
27 | }
28 |
29 | /**
30 | * Contructor
31 | * @param items the items
32 | */
33 | public ArrayWheelAdapter(ArrayList items) {
34 | this(items, DEFAULT_LENGTH);
35 | }
36 |
37 | @Override
38 | public Object getItem(int index) {
39 | if (index >= 0 && index < items.size()) {
40 | return items.get(index);
41 | }
42 | return "";
43 | }
44 |
45 | @Override
46 | public int getItemsCount() {
47 | return items.size();
48 | }
49 |
50 | @Override
51 | public int indexOf(Object o){
52 | return items.indexOf(o);
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/pickerview/src/main/java/com/bigkoo/pickerview/adapter/NumericWheelAdapter.java:
--------------------------------------------------------------------------------
1 | package com.bigkoo.pickerview.adapter;
2 |
3 |
4 | /**
5 | * Numeric Wheel adapter.
6 | */
7 | public class NumericWheelAdapter implements WheelAdapter {
8 |
9 | /** The default min value */
10 | public static final int DEFAULT_MAX_VALUE = 9;
11 |
12 | /** The default max value */
13 | private static final int DEFAULT_MIN_VALUE = 0;
14 |
15 | // Values
16 | private int minValue;
17 | private int maxValue;
18 |
19 | /**
20 | * Default constructor
21 | */
22 | public NumericWheelAdapter() {
23 | this(DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE);
24 | }
25 |
26 | /**
27 | * Constructor
28 | * @param minValue the wheel min value
29 | * @param maxValue the wheel max value
30 | */
31 | public NumericWheelAdapter(int minValue, int maxValue) {
32 | this.minValue = minValue;
33 | this.maxValue = maxValue;
34 | }
35 |
36 | @Override
37 | public Object getItem(int index) {
38 | if (index >= 0 && index < getItemsCount()) {
39 | int value = minValue + index;
40 | return value;
41 | }
42 | return 0;
43 | }
44 |
45 | @Override
46 | public int getItemsCount() {
47 | return maxValue - minValue + 1;
48 | }
49 |
50 | @Override
51 | public int indexOf(Object o){
52 | return (int)o - minValue;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/pickerview/src/main/java/com/bigkoo/pickerview/adapter/WheelAdapter.java:
--------------------------------------------------------------------------------
1 | package com.bigkoo.pickerview.adapter;
2 |
3 | public interface WheelAdapter {
4 | /**
5 | * Gets items count
6 | * @return the count of wheel items
7 | */
8 | public int getItemsCount();
9 |
10 | /**
11 | * Gets a wheel item by index.
12 | *
13 | * @param index the item index
14 | * @return the wheel item text or null
15 | */
16 | public T getItem(int index);
17 |
18 | /**
19 | * Gets maximum item length. It is used to determine the wheel width.
20 | * If -1 is returned there will be used the default wheel width.
21 | *
22 | * @return the maximum item length or -1
23 | */
24 | public int indexOf(T o);
25 | }
26 |
--------------------------------------------------------------------------------
/pickerview/src/main/java/com/bigkoo/pickerview/lib/InertiaTimerTask.java:
--------------------------------------------------------------------------------
1 | package com.bigkoo.pickerview.lib;
2 |
3 | import java.util.TimerTask;
4 |
5 | final class InertiaTimerTask extends TimerTask {
6 |
7 | float a;
8 | final float velocityY;
9 | final WheelView loopView;
10 |
11 | InertiaTimerTask(WheelView loopview, float velocityY) {
12 | super();
13 | loopView = loopview;
14 | this.velocityY = velocityY;
15 | a = Integer.MAX_VALUE;
16 | }
17 |
18 | @Override
19 | public final void run() {
20 | if (a == Integer.MAX_VALUE) {
21 | if (Math.abs(velocityY) > 2000F) {
22 | if (velocityY > 0.0F) {
23 | a = 2000F;
24 | } else {
25 | a = -2000F;
26 | }
27 | } else {
28 | a = velocityY;
29 | }
30 | }
31 | if (Math.abs(a) >= 0.0F && Math.abs(a) <= 20F) {
32 | loopView.cancelFuture();
33 | loopView.handler.sendEmptyMessage(MessageHandler.WHAT_SMOOTH_SCROLL);
34 | return;
35 | }
36 | int i = (int) ((a * 10F) / 1000F);
37 | loopView.totalScrollY = loopView.totalScrollY - i;
38 | if (!loopView.isLoop) {
39 | float itemHeight = loopView.itemHeight;
40 | float top = (-loopView.initPosition) * itemHeight;
41 | float bottom = (loopView.getItemsCount() - 1 - loopView.initPosition) * itemHeight;
42 | if(loopView.totalScrollY - itemHeight*0.3 < top){
43 | top = loopView.totalScrollY + i;
44 | }
45 | else if(loopView.totalScrollY + itemHeight*0.3 > bottom){
46 | bottom = loopView.totalScrollY + i;
47 | }
48 |
49 | if (loopView.totalScrollY <= top){
50 | a = 40F;
51 | loopView.totalScrollY = (int)top;
52 | } else if (loopView.totalScrollY >= bottom) {
53 | loopView.totalScrollY = (int)bottom;
54 | a = -40F;
55 | }
56 | }
57 | if (a < 0.0F) {
58 | a = a + 20F;
59 | } else {
60 | a = a - 20F;
61 | }
62 | loopView.handler.sendEmptyMessage(MessageHandler.WHAT_INVALIDATE_LOOP_VIEW);
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/pickerview/src/main/java/com/bigkoo/pickerview/lib/LoopViewGestureListener.java:
--------------------------------------------------------------------------------
1 | package com.bigkoo.pickerview.lib;
2 |
3 | import android.view.MotionEvent;
4 |
5 | final class LoopViewGestureListener extends android.view.GestureDetector.SimpleOnGestureListener {
6 |
7 | final WheelView loopView;
8 |
9 | LoopViewGestureListener(WheelView loopview) {
10 | loopView = loopview;
11 | }
12 |
13 | @Override
14 | public final boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
15 | loopView.scrollBy(velocityY);
16 | return true;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/pickerview/src/main/java/com/bigkoo/pickerview/lib/MessageHandler.java:
--------------------------------------------------------------------------------
1 | package com.bigkoo.pickerview.lib;
2 |
3 | import android.os.Handler;
4 | import android.os.Message;
5 |
6 | final class MessageHandler extends Handler {
7 | public static final int WHAT_INVALIDATE_LOOP_VIEW = 1000;
8 | public static final int WHAT_SMOOTH_SCROLL = 2000;
9 | public static final int WHAT_ITEM_SELECTED = 3000;
10 |
11 | final WheelView loopview;
12 |
13 | MessageHandler(WheelView loopview) {
14 | this.loopview = loopview;
15 | }
16 |
17 | @Override
18 | public final void handleMessage(Message msg) {
19 | switch (msg.what) {
20 | case WHAT_INVALIDATE_LOOP_VIEW:
21 | loopview.invalidate();
22 | break;
23 |
24 | case WHAT_SMOOTH_SCROLL:
25 | loopview.smoothScroll(WheelView.ACTION.FLING);
26 | break;
27 |
28 | case WHAT_ITEM_SELECTED:
29 | loopview.onItemSelected();
30 | break;
31 | }
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/pickerview/src/main/java/com/bigkoo/pickerview/lib/OnItemSelectedRunnable.java:
--------------------------------------------------------------------------------
1 | package com.bigkoo.pickerview.lib;
2 |
3 | final class OnItemSelectedRunnable implements Runnable {
4 | final WheelView loopView;
5 |
6 | OnItemSelectedRunnable(WheelView loopview) {
7 | loopView = loopview;
8 | }
9 |
10 | @Override
11 | public final void run() {
12 | loopView.onItemSelectedListener.onItemSelected(loopView.getCurrentItem());
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/pickerview/src/main/java/com/bigkoo/pickerview/lib/SmoothScrollTimerTask.java:
--------------------------------------------------------------------------------
1 | package com.bigkoo.pickerview.lib;
2 |
3 | import java.util.TimerTask;
4 |
5 | final class SmoothScrollTimerTask extends TimerTask {
6 |
7 | int realTotalOffset;
8 | int realOffset;
9 | int offset;
10 | final WheelView loopView;
11 |
12 | SmoothScrollTimerTask(WheelView loopview, int offset) {
13 | this.loopView = loopview;
14 | this.offset = offset;
15 | realTotalOffset = Integer.MAX_VALUE;
16 | realOffset = 0;
17 | }
18 |
19 | @Override
20 | public final void run() {
21 | if (realTotalOffset == Integer.MAX_VALUE) {
22 | realTotalOffset = offset;
23 | }
24 | //把要滚动的范围细分成十小份,按是小份单位来重绘
25 | realOffset = (int) ((float) realTotalOffset * 0.1F);
26 |
27 | if (realOffset == 0) {
28 | if (realTotalOffset < 0) {
29 | realOffset = -1;
30 | } else {
31 | realOffset = 1;
32 | }
33 | }
34 |
35 | if (Math.abs(realTotalOffset) <= 1) {
36 | loopView.cancelFuture();
37 | loopView.handler.sendEmptyMessage(MessageHandler.WHAT_ITEM_SELECTED);
38 | } else {
39 | loopView.totalScrollY = loopView.totalScrollY + realOffset;
40 |
41 | //这里如果不是循环模式,则点击空白位置需要回滚,不然就会出现选到-1 item的 情况
42 | if (!loopView.isLoop) {
43 | float itemHeight = loopView.itemHeight;
44 | float top = (float) (-loopView.initPosition) * itemHeight;
45 | float bottom = (float) (loopView.getItemsCount() - 1 - loopView.initPosition) * itemHeight;
46 | if (loopView.totalScrollY <= top||loopView.totalScrollY >= bottom) {
47 | loopView.totalScrollY = loopView.totalScrollY - realOffset;
48 | loopView.cancelFuture();
49 | loopView.handler.sendEmptyMessage(MessageHandler.WHAT_ITEM_SELECTED);
50 | return;
51 | }
52 | }
53 | loopView.handler.sendEmptyMessage(MessageHandler.WHAT_INVALIDATE_LOOP_VIEW);
54 | realTotalOffset = realTotalOffset - realOffset;
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/pickerview/src/main/java/com/bigkoo/pickerview/lib/WheelView.java:
--------------------------------------------------------------------------------
1 | package com.bigkoo.pickerview.lib;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.graphics.Paint;
7 | import android.graphics.Rect;
8 | import android.graphics.Typeface;
9 | import android.os.Handler;
10 | import android.util.AttributeSet;
11 | import android.view.GestureDetector;
12 | import android.view.Gravity;
13 | import android.view.MotionEvent;
14 | import android.view.View;
15 |
16 | import com.bigkoo.pickerview.R;
17 | import com.bigkoo.pickerview.adapter.WheelAdapter;
18 | import com.bigkoo.pickerview.listener.OnItemSelectedListener;
19 |
20 | import java.lang.reflect.InvocationTargetException;
21 | import java.lang.reflect.Method;
22 | import java.util.concurrent.Executors;
23 | import java.util.concurrent.ScheduledExecutorService;
24 | import java.util.concurrent.ScheduledFuture;
25 | import java.util.concurrent.TimeUnit;
26 |
27 | /**
28 | * 3d滚轮控件
29 | */
30 | public class WheelView extends View {
31 |
32 | public enum ACTION {
33 | // 点击,滑翔(滑到尽头),拖拽事件
34 | CLICK, FLING, DAGGLE
35 | }
36 | Context context;
37 |
38 | Handler handler;
39 | private GestureDetector gestureDetector;
40 | OnItemSelectedListener onItemSelectedListener;
41 |
42 | // Timer mTimer;
43 | ScheduledExecutorService mExecutor = Executors.newSingleThreadScheduledExecutor();
44 | private ScheduledFuture> mFuture;
45 |
46 | Paint paintOuterText;
47 | Paint paintCenterText;
48 | Paint paintIndicator;
49 |
50 | WheelAdapter adapter;
51 |
52 | private String label;//附加单位
53 | int textSize;//选项的文字大小
54 | boolean customTextSize;//自定义文字大小,为true则用于使setTextSize函数无效,只能通过xml修改
55 | int maxTextWidth;
56 | int maxTextHeight;
57 | float itemHeight;//每行高度
58 |
59 | int textColorOut;
60 | int textColorCenter;
61 | int dividerColor;
62 |
63 | // 条目间距倍数
64 | static final float lineSpacingMultiplier = 1.4F;
65 | boolean isLoop;
66 |
67 | // 第一条线Y坐标值
68 | float firstLineY;
69 | //第二条线Y坐标
70 | float secondLineY;
71 | //中间Y坐标
72 | float centerY;
73 |
74 | //滚动总高度y值
75 | int totalScrollY;
76 | //初始化默认选中第几个
77 | int initPosition;
78 | //选中的Item是第几个
79 | private int selectedItem;
80 | int preCurrentIndex;
81 | //滚动偏移值,用于记录滚动了多少个item
82 | int change;
83 |
84 | // 显示几个条目
85 | int itemsVisible = 11;
86 |
87 | int measuredHeight;
88 | int measuredWidth;
89 |
90 | // 半圆周长
91 | int halfCircumference;
92 | // 半径
93 | int radius;
94 |
95 | private int mOffset = 0;
96 | private float previousY = 0;
97 | long startTime = 0;
98 |
99 | // 修改这个值可以改变滑行速度
100 | private static final int VELOCITYFLING = 5;
101 | int widthMeasureSpec;
102 |
103 | private int mGravity = Gravity.CENTER;
104 | private int drawCenterContentStart = 0;//中间选中文字开始绘制位置
105 | private int drawOutContentStart = 0;//非中间文字开始绘制位置
106 | private static final float SCALECONTENT = 0.8F;//非中间文字则用此控制高度,压扁形成3d错觉
107 | private static final float CENTERCONTENTOFFSET = 6;//中间文字文字居中需要此偏移值
108 | private static final String GETPICKERVIEWTEXT = "getPickerViewText";//反射的方法名
109 |
110 | public WheelView(Context context) {
111 | this(context, null);
112 | }
113 |
114 | public WheelView(Context context, AttributeSet attrs) {
115 | super(context, attrs);
116 | textColorOut = getResources().getColor(R.color.pickerview_wheelview_textcolor_out);
117 | textColorCenter = getResources().getColor(R.color.pickerview_wheelview_textcolor_center);
118 | dividerColor = getResources().getColor(R.color.pickerview_wheelview_textcolor_divider);
119 | //配合customTextSize使用,customTextSize为true才会发挥效果
120 | textSize = getResources().getDimensionPixelSize(R.dimen.pickerview_textsize);
121 | customTextSize = getResources().getBoolean(R.bool.pickerview_customTextSize);
122 | if(attrs != null) {
123 | TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.wheelview,0,0);
124 | mGravity = a.getInt(R.styleable.wheelview_gravity, Gravity.CENTER);
125 | textColorOut = a.getColor(R.styleable.wheelview_textColorOut, textColorOut);
126 | textColorCenter = a.getColor(R.styleable.wheelview_textColorCenter,textColorCenter);
127 | dividerColor = a.getColor(R.styleable.wheelview_dividerColor,dividerColor);
128 | textSize = a.getDimensionPixelOffset(R.styleable.wheelview_textSize,textSize);
129 | }
130 | initLoopView(context);
131 | }
132 |
133 | private void initLoopView(Context context) {
134 | this.context = context;
135 | handler = new MessageHandler(this);
136 | gestureDetector = new GestureDetector(context, new LoopViewGestureListener(this));
137 | gestureDetector.setIsLongpressEnabled(false);
138 |
139 | isLoop = true;
140 |
141 | totalScrollY = 0;
142 | initPosition = -1;
143 |
144 | initPaints();
145 |
146 | }
147 |
148 | private void initPaints() {
149 | paintOuterText = new Paint();
150 | paintOuterText.setColor(textColorOut);
151 | paintOuterText.setAntiAlias(true);
152 | paintOuterText.setTypeface(Typeface.MONOSPACE);
153 | paintOuterText.setTextSize(textSize);
154 |
155 | paintCenterText = new Paint();
156 | paintCenterText.setColor(textColorCenter);
157 | paintCenterText.setAntiAlias(true);
158 | paintCenterText.setTextScaleX(1.1F);
159 | paintCenterText.setTypeface(Typeface.MONOSPACE);
160 | paintCenterText.setTextSize(textSize);
161 |
162 | paintIndicator = new Paint();
163 | paintIndicator.setColor(dividerColor);
164 | paintIndicator.setAntiAlias(true);
165 |
166 | if (android.os.Build.VERSION.SDK_INT >= 11) {
167 | setLayerType(LAYER_TYPE_SOFTWARE, null);
168 | }
169 | }
170 |
171 | private void remeasure() {
172 | if (adapter == null) {
173 | return;
174 | }
175 |
176 | measureTextWidthHeight();
177 |
178 | //最大Text的高度乘间距倍数得到 可见文字实际的总高度,半圆的周长
179 | halfCircumference = (int) (itemHeight * (itemsVisible - 1)) ;
180 | //整个圆的周长除以PI得到直径,这个直径用作控件的总高度
181 | measuredHeight = (int) ((halfCircumference * 2) / Math.PI);
182 | //求出半径
183 | radius = (int) (halfCircumference / Math.PI);
184 | //控件宽度,这里支持weight
185 | measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
186 | //计算两条横线和控件中间点的Y位置
187 | firstLineY = (measuredHeight - itemHeight) / 2.0F;
188 | secondLineY = (measuredHeight + itemHeight) / 2.0F;
189 | centerY = (measuredHeight + maxTextHeight) / 2.0F - CENTERCONTENTOFFSET;
190 | //初始化显示的item的position,根据是否loop
191 | if (initPosition == -1) {
192 | if (isLoop) {
193 | initPosition = (adapter.getItemsCount() + 1) / 2;
194 | } else {
195 | initPosition = 0;
196 | }
197 | }
198 |
199 | preCurrentIndex = initPosition;
200 | }
201 |
202 | /**
203 | * 计算最大len的Text的宽高度
204 | */
205 | private void measureTextWidthHeight() {
206 | Rect rect = new Rect();
207 | for (int i = 0; i < adapter.getItemsCount(); i++) {
208 | String s1 = getContentText(adapter.getItem(i));
209 | paintCenterText.getTextBounds(s1, 0, s1.length(), rect);
210 | int textWidth = rect.width();
211 | if (textWidth > maxTextWidth) {
212 | maxTextWidth = textWidth;
213 | }
214 | paintCenterText.getTextBounds("\u661F\u671F", 0, 2, rect); // 星期
215 | int textHeight = rect.height();
216 | if (textHeight > maxTextHeight) {
217 | maxTextHeight = textHeight;
218 | }
219 | }
220 | itemHeight = lineSpacingMultiplier * maxTextHeight;
221 | }
222 |
223 | void smoothScroll(ACTION action) {
224 | cancelFuture();
225 | if (action== ACTION.FLING||action== ACTION.DAGGLE) {
226 | mOffset = (int) ((totalScrollY%itemHeight + itemHeight) % itemHeight);
227 | if ((float) mOffset > itemHeight / 2.0F) {
228 | mOffset = (int) (itemHeight - (float) mOffset);
229 | } else {
230 | mOffset = -mOffset;
231 | }
232 | }
233 | //停止的时候,位置有偏移,不是全部都能正确停止到中间位置的,这里把文字位置挪回中间去
234 | mFuture = mExecutor.scheduleWithFixedDelay(new SmoothScrollTimerTask(this, mOffset), 0, 10, TimeUnit.MILLISECONDS);
235 | }
236 |
237 | protected final void scrollBy(float velocityY) {
238 | cancelFuture();
239 |
240 | mFuture = mExecutor.scheduleWithFixedDelay(new InertiaTimerTask(this, velocityY), 0, VELOCITYFLING, TimeUnit.MILLISECONDS);
241 | }
242 |
243 | public void cancelFuture() {
244 | if (mFuture!=null&&!mFuture.isCancelled()) {
245 | mFuture.cancel(true);
246 | mFuture = null;
247 | }
248 | }
249 |
250 | /**
251 | * 设置是否循环滚动
252 | * @param cyclic
253 | */
254 | public final void setCyclic(boolean cyclic) {
255 | isLoop = cyclic;
256 | }
257 |
258 | public final void setTextSize(float size) {
259 | if (size > 0.0F&&!customTextSize) {
260 | textSize = (int) (context.getResources().getDisplayMetrics().density * size);
261 | paintOuterText.setTextSize(textSize);
262 | paintCenterText.setTextSize(textSize);
263 | }
264 | }
265 |
266 | public final void setCurrentItem(int currentItem) {
267 | this.initPosition = currentItem;
268 | totalScrollY = 0;//回归顶部,不然重设setCurrentItem的话位置会偏移的,就会显示出不对位置的数据
269 | invalidate();
270 | }
271 |
272 | public final void setOnItemSelectedListener(OnItemSelectedListener OnItemSelectedListener) {
273 | this.onItemSelectedListener = OnItemSelectedListener;
274 | }
275 |
276 | public final void setAdapter(WheelAdapter adapter) {
277 | this.adapter = adapter;
278 | remeasure();
279 | invalidate();
280 | }
281 |
282 | public final WheelAdapter getAdapter(){
283 | return adapter;
284 | }
285 |
286 | public final int getCurrentItem() {
287 | return selectedItem;
288 | }
289 |
290 | protected final void onItemSelected() {
291 | if (onItemSelectedListener != null) {
292 | postDelayed(new OnItemSelectedRunnable(this), 200L);
293 | }
294 | }
295 |
296 | @Override
297 | protected void onDraw(Canvas canvas) {
298 | if (adapter == null) {
299 | return;
300 | }
301 | //可见的item数组
302 | Object visibles[] = new Object[itemsVisible];
303 | //滚动的Y值高度除去每行Item的高度,得到滚动了多少个item,即change数
304 | change = (int) (totalScrollY / itemHeight);
305 | try {
306 | //滚动中实际的预选中的item(即经过了中间位置的item) = 滑动前的位置 + 滑动相对位置
307 | preCurrentIndex = initPosition + change % adapter.getItemsCount();
308 | }catch (ArithmeticException e){
309 | System.out.println("出错了!adapter.getItemsCount() == 0,联动数据不匹配");
310 | }
311 | if (!isLoop) {//不循环的情况
312 | if (preCurrentIndex < 0) {
313 | preCurrentIndex = 0;
314 | }
315 | if (preCurrentIndex > adapter.getItemsCount() - 1) {
316 | preCurrentIndex = adapter.getItemsCount() - 1;
317 | }
318 | } else {//循环
319 | if (preCurrentIndex < 0) {//举个例子:如果总数是5,preCurrentIndex = -1,那么preCurrentIndex按循环来说,其实是0的上面,也就是4的位置
320 | preCurrentIndex = adapter.getItemsCount() + preCurrentIndex;
321 | }
322 | if (preCurrentIndex > adapter.getItemsCount() - 1) {//同理上面,自己脑补一下
323 | preCurrentIndex = preCurrentIndex - adapter.getItemsCount();
324 | }
325 | }
326 |
327 | //跟滚动流畅度有关,总滑动距离与每个item高度取余,即并不是一格格的滚动,每个item不一定滚到对应Rect里的,这个item对应格子的偏移值
328 | int itemHeightOffset = (int) (totalScrollY % itemHeight);
329 | // 设置数组中每个元素的值
330 | int counter = 0;
331 | while (counter < itemsVisible) {
332 | int index = preCurrentIndex - (itemsVisible / 2 - counter);//索引值,即当前在控件中间的item看作数据源的中间,计算出相对源数据源的index值
333 |
334 | //判断是否循环,如果是循环数据源也使用相对循环的position获取对应的item值,如果不是循环则超出数据源范围使用""空白字符串填充,在界面上形成空白无数据的item项
335 | if (isLoop) {
336 | index = getLoopMappingIndex(index);
337 | visibles[counter] = adapter.getItem(index);
338 | } else if (index < 0) {
339 | visibles[counter] = "";
340 | } else if (index > adapter.getItemsCount() - 1) {
341 | visibles[counter] = "";
342 | } else {
343 | visibles[counter] = adapter.getItem(index);
344 | }
345 |
346 | counter++;
347 |
348 | }
349 |
350 | //中间两条横线
351 | canvas.drawLine(0.0F, firstLineY, measuredWidth, firstLineY, paintIndicator);
352 | canvas.drawLine(0.0F, secondLineY, measuredWidth, secondLineY, paintIndicator);
353 | //单位的Label
354 | if(label != null) {
355 | int drawRightContentStart = measuredWidth - getTextWidth(paintCenterText,label);
356 | //靠右并留出空隙
357 | canvas.drawText(label, drawRightContentStart - CENTERCONTENTOFFSET, centerY, paintCenterText);
358 | }
359 | counter = 0;
360 | while (counter < itemsVisible) {
361 | canvas.save();
362 | // L(弧长)=α(弧度)* r(半径) (弧度制)
363 | // 求弧度--> (L * π ) / (π * r) (弧长X派/半圆周长)
364 | float itemHeight = maxTextHeight * lineSpacingMultiplier;
365 | double radian = ((itemHeight * counter - itemHeightOffset) * Math.PI) / halfCircumference;
366 | // 弧度转换成角度(把半圆以Y轴为轴心向右转90度,使其处于第一象限及第四象限
367 | float angle = (float) (90D - (radian / Math.PI) * 180D);
368 | // 九十度以上的不绘制
369 | if (angle >= 90F || angle <= -90F) {
370 | canvas.restore();
371 | } else {
372 | String contentText = getContentText(visibles[counter]);
373 |
374 | //计算开始绘制的位置
375 | measuredCenterContentStart(contentText);
376 | measuredOutContentStart(contentText);
377 | float translateY = (float) (radius - Math.cos(radian) * radius - (Math.sin(radian) * maxTextHeight) / 2D);
378 | //根据Math.sin(radian)来更改canvas坐标系原点,然后缩放画布,使得文字高度进行缩放,形成弧形3d视觉差
379 | canvas.translate(0.0F, translateY);
380 | canvas.scale(1.0F, (float) Math.sin(radian));
381 | if (translateY <= firstLineY && maxTextHeight + translateY >= firstLineY) {
382 | // 条目经过第一条线
383 | canvas.save();
384 | canvas.clipRect(0, 0, measuredWidth, firstLineY - translateY);
385 | canvas.scale(1.0F, (float) Math.sin(radian) * SCALECONTENT);
386 | canvas.drawText(contentText, drawOutContentStart, maxTextHeight, paintOuterText);
387 | canvas.restore();
388 | canvas.save();
389 | canvas.clipRect(0, firstLineY - translateY, measuredWidth, (int) (itemHeight));
390 | canvas.scale(1.0F, (float) Math.sin(radian) * 1F);
391 | canvas.drawText(contentText, drawCenterContentStart, maxTextHeight - CENTERCONTENTOFFSET, paintCenterText);
392 | canvas.restore();
393 | } else if (translateY <= secondLineY && maxTextHeight + translateY >= secondLineY) {
394 | // 条目经过第二条线
395 | canvas.save();
396 | canvas.clipRect(0, 0, measuredWidth, secondLineY - translateY);
397 | canvas.scale(1.0F, (float) Math.sin(radian) * 1.0F);
398 | canvas.drawText(contentText, drawCenterContentStart, maxTextHeight - CENTERCONTENTOFFSET, paintCenterText);
399 | canvas.restore();
400 | canvas.save();
401 | canvas.clipRect(0, secondLineY - translateY, measuredWidth, (int) (itemHeight));
402 | canvas.scale(1.0F, (float) Math.sin(radian) * SCALECONTENT);
403 | canvas.drawText(contentText, drawOutContentStart, maxTextHeight, paintOuterText);
404 | canvas.restore();
405 | } else if (translateY >= firstLineY && maxTextHeight + translateY <= secondLineY) {
406 | // 中间条目
407 | canvas.clipRect(0, 0, measuredWidth, (int) (itemHeight));
408 | canvas.drawText(contentText, drawCenterContentStart, maxTextHeight - CENTERCONTENTOFFSET, paintCenterText);
409 | int preSelectedItem = adapter.indexOf(visibles[counter]);
410 | if(preSelectedItem != -1){
411 | selectedItem = preSelectedItem;
412 | }
413 | } else {
414 | // 其他条目
415 | canvas.save();
416 | canvas.clipRect(0, 0, measuredWidth, (int) (itemHeight));
417 | canvas.scale(1.0F, (float) Math.sin(radian) * SCALECONTENT);
418 | canvas.drawText(contentText, drawOutContentStart, maxTextHeight, paintOuterText);
419 | canvas.restore();
420 | }
421 | canvas.restore();
422 | }
423 | counter++;
424 | }
425 | }
426 |
427 | //递归计算出对应的index
428 | private int getLoopMappingIndex(int index){
429 | if(index < 0){
430 | index = index + adapter.getItemsCount();
431 | index = getLoopMappingIndex(index);
432 | }
433 | else if (index > adapter.getItemsCount() - 1) {
434 | index = index - adapter.getItemsCount();
435 | index = getLoopMappingIndex(index);
436 | }
437 | return index;
438 | }
439 |
440 | /**
441 | * 根据传进来的对象反射出getPickerViewText()方法,来获取需要显示的值
442 | * @param item
443 | * @return
444 | */
445 | private String getContentText(Object item) {
446 | String contentText = item.toString();
447 | try {
448 | Class> clz = item.getClass();
449 | Method m = clz.getMethod(GETPICKERVIEWTEXT);
450 | contentText = m.invoke(item, new Object[0]).toString();
451 | } catch (NoSuchMethodException e) {
452 | } catch (InvocationTargetException e) {
453 | } catch (IllegalAccessException e) {
454 | } catch (Exception e){
455 | }
456 | return contentText;
457 | }
458 |
459 | private void measuredCenterContentStart(String content) {
460 | Rect rect = new Rect();
461 | paintCenterText.getTextBounds(content, 0, content.length(), rect);
462 | switch (mGravity){
463 | case Gravity.CENTER:
464 | drawCenterContentStart = (int)((measuredWidth - rect.width()) * 0.5);
465 | break;
466 | case Gravity.LEFT:
467 | drawCenterContentStart = 0;
468 | break;
469 | case Gravity.RIGHT:
470 | drawCenterContentStart = measuredWidth - rect.width();
471 | break;
472 | }
473 | }
474 | private void measuredOutContentStart(String content) {
475 | Rect rect = new Rect();
476 | paintOuterText.getTextBounds(content, 0, content.length(), rect);
477 | switch (mGravity){
478 | case Gravity.CENTER:
479 | drawOutContentStart = (int)((measuredWidth - rect.width()) * 0.5);
480 | break;
481 | case Gravity.LEFT:
482 | drawOutContentStart = 0;
483 | break;
484 | case Gravity.RIGHT:
485 | drawOutContentStart = measuredWidth - rect.width();
486 | break;
487 | }
488 | }
489 |
490 | @Override
491 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
492 | this.widthMeasureSpec = widthMeasureSpec;
493 | remeasure();
494 | setMeasuredDimension(measuredWidth, measuredHeight);
495 | }
496 |
497 | @Override
498 | public boolean onTouchEvent(MotionEvent event) {
499 | boolean eventConsumed = gestureDetector.onTouchEvent(event);
500 | switch (event.getAction()) {
501 | case MotionEvent.ACTION_DOWN:
502 | startTime = System.currentTimeMillis();
503 | cancelFuture();
504 | previousY = event.getRawY();
505 | break;
506 |
507 | case MotionEvent.ACTION_MOVE:
508 | float dy = previousY - event.getRawY();
509 | previousY = event.getRawY();
510 | totalScrollY = (int) (totalScrollY + dy);
511 |
512 | // 边界处理。
513 | if (!isLoop) {
514 | float top = -initPosition * itemHeight;
515 | float bottom = (adapter.getItemsCount() - 1 - initPosition) * itemHeight;
516 | if(totalScrollY - itemHeight*0.3 < top){
517 | top = totalScrollY - dy;
518 | }
519 | else if(totalScrollY + itemHeight*0.3 > bottom){
520 | bottom = totalScrollY - dy;
521 | }
522 |
523 | if (totalScrollY < top) {
524 | totalScrollY = (int) top;
525 | } else if (totalScrollY > bottom) {
526 | totalScrollY = (int) bottom;
527 | }
528 | }
529 | break;
530 |
531 | case MotionEvent.ACTION_UP:
532 | default:
533 | if (!eventConsumed) {
534 | float y = event.getY();
535 | double l = Math.acos((radius - y) / radius) * radius;
536 | int circlePosition = (int) ((l + itemHeight / 2) / itemHeight);
537 |
538 | float extraOffset = (totalScrollY % itemHeight + itemHeight) % itemHeight;
539 | mOffset = (int) ((circlePosition - itemsVisible / 2) * itemHeight - extraOffset);
540 |
541 | if ((System.currentTimeMillis() - startTime) > 120) {
542 | // 处理拖拽事件
543 | smoothScroll(ACTION.DAGGLE);
544 | } else {
545 | // 处理条目点击事件
546 | smoothScroll(ACTION.CLICK);
547 | }
548 | }
549 | break;
550 | }
551 | invalidate();
552 |
553 | return true;
554 | }
555 |
556 | /**
557 | * 获取Item个数
558 | * @return
559 | */
560 | public int getItemsCount() {
561 | return adapter != null ? adapter.getItemsCount() : 0;
562 | }
563 |
564 | /**
565 | * 附加在右边的单位字符串
566 | * @param label
567 | */
568 | public void setLabel(String label){
569 | this.label = label;
570 | }
571 |
572 | public void setGravity(int gravity) {
573 | this.mGravity = gravity;
574 | }
575 |
576 | public int getTextWidth(Paint paint, String str) {
577 | int iRet = 0;
578 | if (str != null && str.length() > 0) {
579 | int len = str.length();
580 | float[] widths = new float[len];
581 | paint.getTextWidths(str, widths);
582 | for (int j = 0; j < len; j++) {
583 | iRet += (int) Math.ceil(widths[j]);
584 | }
585 | }
586 | return iRet;
587 | }
588 | }
--------------------------------------------------------------------------------
/pickerview/src/main/java/com/bigkoo/pickerview/listener/OnDismissListener.java:
--------------------------------------------------------------------------------
1 | package com.bigkoo.pickerview.listener;
2 |
3 | /**
4 | * Created by Sai on 15/8/9.
5 | */
6 | public interface OnDismissListener {
7 | public void onDismiss(Object o);
8 | }
9 |
--------------------------------------------------------------------------------
/pickerview/src/main/java/com/bigkoo/pickerview/listener/OnItemSelectedListener.java:
--------------------------------------------------------------------------------
1 | package com.bigkoo.pickerview.listener;
2 |
3 |
4 | public interface OnItemSelectedListener {
5 | void onItemSelected(int index);
6 | }
7 |
--------------------------------------------------------------------------------
/pickerview/src/main/java/com/bigkoo/pickerview/utils/PickerViewAnimateUtil.java:
--------------------------------------------------------------------------------
1 | package com.bigkoo.pickerview.utils;
2 |
3 | import android.view.Gravity;
4 |
5 | import com.bigkoo.pickerview.R;
6 |
7 | /**
8 | * Created by Sai on 15/8/9.
9 | */
10 | public class PickerViewAnimateUtil {
11 | private static final int INVALID = -1;
12 | /**
13 | * Get default animation resource when not defined by the user
14 | *
15 | * @param gravity the gravity of the dialog
16 | * @param isInAnimation determine if is in or out animation. true when is is
17 | * @return the id of the animation resource
18 | */
19 | public static int getAnimationResource(int gravity, boolean isInAnimation) {
20 | switch (gravity) {
21 | case Gravity.BOTTOM:
22 | return isInAnimation ? R.anim.slide_in_bottom : R.anim.slide_out_bottom;
23 | }
24 | return INVALID;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/pickerview/src/main/java/com/bigkoo/pickerview/view/BasePickerView.java:
--------------------------------------------------------------------------------
1 | package com.bigkoo.pickerview.view;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.view.Gravity;
6 | import android.view.LayoutInflater;
7 | import android.view.MotionEvent;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.view.animation.Animation;
11 | import android.view.animation.AnimationUtils;
12 | import android.widget.FrameLayout;
13 |
14 | import com.bigkoo.pickerview.utils.PickerViewAnimateUtil;
15 | import com.bigkoo.pickerview.R;
16 | import com.bigkoo.pickerview.listener.OnDismissListener;
17 |
18 | /**
19 | * Created by Sai on 15/11/22.
20 | * 精仿iOSPickerViewController控件
21 | */
22 | public class BasePickerView {
23 | private final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
24 | ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM
25 | );
26 |
27 | protected Context context;
28 | protected ViewGroup contentContainer;
29 | private ViewGroup decorView;//activity的根View
30 | private ViewGroup rootView;//附加View 的 根View
31 |
32 | private OnDismissListener onDismissListener;
33 | private boolean isDismissing;
34 |
35 | private Animation outAnim;
36 | private Animation inAnim;
37 | private int gravity = Gravity.BOTTOM;
38 |
39 | public BasePickerView(Context context){
40 | this.context = context;
41 |
42 | initViews();
43 | init();
44 | initEvents();
45 | }
46 |
47 | protected void initViews(){
48 | LayoutInflater layoutInflater = LayoutInflater.from(context);
49 | decorView = (ViewGroup) ((Activity)context).getWindow().getDecorView().findViewById(android.R.id.content);
50 | rootView = (ViewGroup) layoutInflater.inflate(R.layout.layout_basepickerview, decorView, false);
51 | rootView.setLayoutParams(new FrameLayout.LayoutParams(
52 | ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
53 | ));
54 | contentContainer = (ViewGroup) rootView.findViewById(R.id.content_container);
55 | contentContainer.setLayoutParams(params);
56 | }
57 |
58 | protected void init() {
59 | inAnim = getInAnimation();
60 | outAnim = getOutAnimation();
61 | }
62 | protected void initEvents() {
63 | }
64 | /**
65 | * show的时候调用
66 | *
67 | * @param view 这个View
68 | */
69 | private void onAttached(View view) {
70 | decorView.addView(view);
71 | contentContainer.startAnimation(inAnim);
72 | }
73 | /**
74 | * 添加这个View到Activity的根视图
75 | */
76 | public void show() {
77 | if (isShowing()) {
78 | return;
79 | }
80 | onAttached(rootView);
81 | }
82 | /**
83 | * 检测该View是不是已经添加到根视图
84 | *
85 | * @return 如果视图已经存在该View返回true
86 | */
87 | public boolean isShowing() {
88 | View view = decorView.findViewById(R.id.outmost_container);
89 | return view != null;
90 | }
91 | public void dismiss() {
92 | if (isDismissing) {
93 | return;
94 | }
95 |
96 | //消失动画
97 | outAnim.setAnimationListener(new Animation.AnimationListener() {
98 | @Override
99 | public void onAnimationStart(Animation animation) {
100 |
101 | }
102 |
103 | @Override
104 | public void onAnimationEnd(Animation animation) {
105 | decorView.post(new Runnable() {
106 | @Override
107 | public void run() {
108 | //从activity根视图移除
109 | decorView.removeView(rootView);
110 | isDismissing = false;
111 | if (onDismissListener != null) {
112 | onDismissListener.onDismiss(BasePickerView.this);
113 | }
114 | }
115 | });
116 | }
117 |
118 | @Override
119 | public void onAnimationRepeat(Animation animation) {
120 |
121 | }
122 | });
123 | contentContainer.startAnimation(outAnim);
124 | isDismissing = true;
125 | }
126 | public Animation getInAnimation() {
127 | int res = PickerViewAnimateUtil.getAnimationResource(this.gravity, true);
128 | return AnimationUtils.loadAnimation(context, res);
129 | }
130 |
131 | public Animation getOutAnimation() {
132 | int res = PickerViewAnimateUtil.getAnimationResource(this.gravity, false);
133 | return AnimationUtils.loadAnimation(context, res);
134 | }
135 |
136 | public BasePickerView setOnDismissListener(OnDismissListener onDismissListener) {
137 | this.onDismissListener = onDismissListener;
138 | return this;
139 | }
140 |
141 | public BasePickerView setCancelable(boolean isCancelable) {
142 | View view = rootView.findViewById(R.id.outmost_container);
143 |
144 | if (isCancelable) {
145 | view.setOnTouchListener(onCancelableTouchListener);
146 | }
147 | else{
148 | view.setOnTouchListener(null);
149 | }
150 | return this;
151 | }
152 | /**
153 | * Called when the user touch on black overlay in order to dismiss the dialog
154 | */
155 | private final View.OnTouchListener onCancelableTouchListener = new View.OnTouchListener() {
156 | @Override
157 | public boolean onTouch(View v, MotionEvent event) {
158 | if (event.getAction() == MotionEvent.ACTION_DOWN) {
159 | dismiss();
160 | }
161 | return false;
162 | }
163 | };
164 |
165 | public View findViewById(int id){
166 | return contentContainer.findViewById(id);
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/pickerview/src/main/java/com/bigkoo/pickerview/view/WheelOptions.java:
--------------------------------------------------------------------------------
1 | package com.bigkoo.pickerview.view;
2 |
3 | import java.util.ArrayList;
4 | import android.view.View;
5 |
6 | import com.bigkoo.pickerview.R;
7 | import com.bigkoo.pickerview.adapter.ArrayWheelAdapter;
8 | import com.bigkoo.pickerview.lib.WheelView;
9 | import com.bigkoo.pickerview.listener.OnItemSelectedListener;
10 |
11 | public class WheelOptions {
12 | private View view;
13 | private WheelView wv_option1;
14 | private WheelView wv_option2;
15 | private WheelView wv_option3;
16 |
17 | private ArrayList mOptions1Items;
18 | private ArrayList> mOptions2Items;
19 | private ArrayList>> mOptions3Items;
20 |
21 | private boolean linkage = false;
22 | private OnItemSelectedListener wheelListener_option1;
23 | private OnItemSelectedListener wheelListener_option2;
24 |
25 | public View getView() {
26 | return view;
27 | }
28 |
29 | public void setView(View view) {
30 | this.view = view;
31 | }
32 |
33 | public WheelOptions(View view) {
34 | super();
35 | this.view = view;
36 | setView(view);
37 | }
38 |
39 | public void setPicker(ArrayList optionsItems) {
40 | setPicker(optionsItems, null, null, false);
41 | }
42 |
43 | public void setPicker(ArrayList options1Items,
44 | ArrayList> options2Items, boolean linkage) {
45 | setPicker(options1Items, options2Items, null, linkage);
46 | }
47 |
48 | public void setPicker(ArrayList options1Items,
49 | ArrayList> options2Items,
50 | ArrayList>> options3Items,
51 | boolean linkage) {
52 | this.linkage = linkage;
53 | this.mOptions1Items = options1Items;
54 | this.mOptions2Items = options2Items;
55 | this.mOptions3Items = options3Items;
56 | int len = ArrayWheelAdapter.DEFAULT_LENGTH;
57 | if (this.mOptions3Items == null)
58 | len = 8;
59 | if (this.mOptions2Items == null)
60 | len = 12;
61 | // 选项1
62 | wv_option1 = (WheelView) view.findViewById(R.id.options1);
63 | wv_option1.setAdapter(new ArrayWheelAdapter(mOptions1Items, len));// 设置显示数据
64 | wv_option1.setCurrentItem(0);// 初始化时显示的数据
65 | // 选项2
66 | wv_option2 = (WheelView) view.findViewById(R.id.options2);
67 | if (mOptions2Items != null)
68 | wv_option2.setAdapter(new ArrayWheelAdapter(mOptions2Items.get(0)));// 设置显示数据
69 | wv_option2.setCurrentItem(wv_option1.getCurrentItem());// 初始化时显示的数据
70 | // 选项3
71 | wv_option3 = (WheelView) view.findViewById(R.id.options3);
72 | if (mOptions3Items != null)
73 | wv_option3.setAdapter(new ArrayWheelAdapter(mOptions3Items.get(0)
74 | .get(0)));// 设置显示数据
75 | wv_option3.setCurrentItem(wv_option3.getCurrentItem());// 初始化时显示的数据
76 |
77 | int textSize = 25;
78 |
79 | wv_option1.setTextSize(textSize);
80 | wv_option2.setTextSize(textSize);
81 | wv_option3.setTextSize(textSize);
82 |
83 | if (this.mOptions2Items == null)
84 | wv_option2.setVisibility(View.GONE);
85 | if (this.mOptions3Items == null)
86 | wv_option3.setVisibility(View.GONE);
87 |
88 | // 联动监听器
89 | wheelListener_option1 = new OnItemSelectedListener() {
90 |
91 | @Override
92 | public void onItemSelected(int index) {
93 | int opt2Select = 0;
94 | if (mOptions2Items != null) {
95 | opt2Select = wv_option2.getCurrentItem();//上一个opt2的选中位置
96 | //新opt2的位置,判断如果旧位置没有超过数据范围,则沿用旧位置,否则选中最后一项
97 | opt2Select = opt2Select >= mOptions2Items.get(index).size() - 1 ? mOptions2Items.get(index).size() - 1 : opt2Select;
98 |
99 | wv_option2.setAdapter(new ArrayWheelAdapter(mOptions2Items
100 | .get(index)));
101 | wv_option2.setCurrentItem(opt2Select);
102 | }
103 | if (mOptions3Items != null) {
104 | wheelListener_option2.onItemSelected(opt2Select);
105 | }
106 | }
107 | };
108 | wheelListener_option2 = new OnItemSelectedListener() {
109 |
110 | @Override
111 | public void onItemSelected(int index) {
112 | if (mOptions3Items != null) {
113 | int opt1Select = wv_option1.getCurrentItem();
114 | opt1Select = opt1Select >= mOptions3Items.size() - 1 ? mOptions3Items.size() - 1 : opt1Select;
115 | index = index >= mOptions2Items.get(opt1Select).size() - 1 ? mOptions2Items.get(opt1Select).size() - 1 : index;
116 | int opt3 = wv_option3.getCurrentItem();//上一个opt3的选中位置
117 | //新opt3的位置,判断如果旧位置没有超过数据范围,则沿用旧位置,否则选中最后一项
118 | opt3 = opt3 >= mOptions3Items.get(opt1Select).get(index).size() - 1 ? mOptions3Items.get(opt1Select).get(index).size() - 1 : opt3;
119 |
120 | wv_option3.setAdapter(new ArrayWheelAdapter(mOptions3Items
121 | .get(wv_option1.getCurrentItem()).get(
122 | index)));
123 | wv_option3.setCurrentItem(opt3);
124 |
125 | }
126 | }
127 | };
128 |
129 | // // 添加联动监听
130 | if (options2Items != null && linkage)
131 | wv_option1.setOnItemSelectedListener(wheelListener_option1);
132 | if (options3Items != null && linkage)
133 | wv_option2.setOnItemSelectedListener(wheelListener_option2);
134 | }
135 |
136 | /**
137 | * 设置选项的单位
138 | *
139 | * @param label1
140 | * @param label2
141 | * @param label3
142 | */
143 | public void setLabels(String label1, String label2, String label3) {
144 | if (label1 != null)
145 | wv_option1.setLabel(label1);
146 | if (label2 != null)
147 | wv_option2.setLabel(label2);
148 | if (label3 != null)
149 | wv_option3.setLabel(label3);
150 | }
151 |
152 | /**
153 | * 设置是否循环滚动
154 | *
155 | * @param cyclic
156 | */
157 | public void setCyclic(boolean cyclic) {
158 | wv_option1.setCyclic(cyclic);
159 | wv_option2.setCyclic(cyclic);
160 | wv_option3.setCyclic(cyclic);
161 | }
162 |
163 | /**
164 | * 分别设置第一二三级是否循环滚动
165 | *
166 | * @param cyclic1,cyclic2,cyclic3
167 | */
168 | public void setCyclic(boolean cyclic1,boolean cyclic2,boolean cyclic3) {
169 | wv_option1.setCyclic(cyclic1);
170 | wv_option2.setCyclic(cyclic2);
171 | wv_option3.setCyclic(cyclic3);
172 | }
173 | /**
174 | * 设置第二级是否循环滚动
175 | *
176 | * @param cyclic
177 | */
178 | public void setOption2Cyclic(boolean cyclic) {
179 | wv_option2.setCyclic(cyclic);
180 | }
181 | /**
182 | * 设置第三级是否循环滚动
183 | *
184 | * @param cyclic
185 | */
186 | public void setOption3Cyclic(boolean cyclic) {
187 | wv_option3.setCyclic(cyclic);
188 | }
189 |
190 | /**
191 | * 返回当前选中的结果对应的位置数组 因为支持三级联动效果,分三个级别索引,0,1,2
192 | *
193 | * @return
194 | */
195 | public int[] getCurrentItems() {
196 | int[] currentItems = new int[3];
197 | currentItems[0] = wv_option1.getCurrentItem();
198 | currentItems[1] = wv_option2.getCurrentItem();
199 | currentItems[2] = wv_option3.getCurrentItem();
200 | return currentItems;
201 | }
202 |
203 | public void setCurrentItems(int option1, int option2, int option3) {
204 | if(linkage){
205 | itemSelected(option1, option2, option3);
206 | }
207 | wv_option1.setCurrentItem(option1);
208 | wv_option2.setCurrentItem(option2);
209 | wv_option3.setCurrentItem(option3);
210 | }
211 |
212 | private void itemSelected(int opt1Select, int opt2Select, int opt3Select) {
213 | if (mOptions2Items != null) {
214 | wv_option2.setAdapter(new ArrayWheelAdapter(mOptions2Items
215 | .get(opt1Select)));
216 | wv_option2.setCurrentItem(opt2Select);
217 | }
218 | if (mOptions3Items != null) {
219 | wv_option3.setAdapter(new ArrayWheelAdapter(mOptions3Items
220 | .get(opt1Select).get(
221 | opt2Select)));
222 | wv_option3.setCurrentItem(opt3Select);
223 | }
224 | }
225 |
226 |
227 | }
228 |
--------------------------------------------------------------------------------
/pickerview/src/main/java/com/bigkoo/pickerview/view/WheelTime.java:
--------------------------------------------------------------------------------
1 | package com.bigkoo.pickerview.view;
2 |
3 | import java.text.DateFormat;
4 | import java.text.SimpleDateFormat;
5 | import java.util.Arrays;
6 | import java.util.List;
7 |
8 | import com.bigkoo.pickerview.R;
9 | import com.bigkoo.pickerview.TimePickerView.Type;
10 | import com.bigkoo.pickerview.adapter.NumericWheelAdapter;
11 | import com.bigkoo.pickerview.lib.WheelView;
12 | import com.bigkoo.pickerview.listener.OnItemSelectedListener;
13 |
14 | import android.content.Context;
15 | import android.view.View;
16 |
17 |
18 | public class WheelTime {
19 | public static DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
20 | private View view;
21 | private WheelView wv_year;
22 | private WheelView wv_month;
23 | private WheelView wv_day;
24 | private WheelView wv_hours;
25 | private WheelView wv_mins;
26 |
27 | private Type type;
28 | public static final int DEFULT_START_YEAR = 1990;
29 | public static final int DEFULT_END_YEAR = 2100;
30 | private int startYear = DEFULT_START_YEAR;
31 | private int endYear = DEFULT_END_YEAR;
32 |
33 | private int endMonth = 12;
34 | private int endDay = 31;
35 |
36 |
37 | // private OnItemChangeListener onItemChangeListener = new OnItemChangeListener() {
38 | // @Override
39 | // public void onItemChange(int year, int month, int day) {
40 | // }
41 | // };
42 |
43 | public WheelTime(View view) {
44 | this(view, Type.ALL);
45 | }
46 | public WheelTime(View view,Type type) {
47 | super();
48 | this.view = view;
49 | this.type = type;
50 | setView(view);
51 | }
52 | public void setPicker(int year ,int month,int day){
53 | this.setPicker(year, month, day, 0, 0);
54 | }
55 |
56 | /**
57 | *
58 | * @param year 真实年
59 | * @param month 真实月 - 1
60 | * @param day 真实日
61 | */
62 | public void setPicker(int year ,int month ,int day,int h,int m) {
63 | // 添加大小月月份并将其转换为list,方便之后的判断
64 | String[] months_big = { "1", "3", "5", "7", "8", "10", "12" };
65 | String[] months_little = { "4", "6", "9", "11" };
66 |
67 | final List list_big = Arrays.asList(months_big);
68 | final List list_little = Arrays.asList(months_little);
69 |
70 | Context context = view.getContext();
71 | // 年
72 | wv_year = (WheelView) view.findViewById(R.id.year);
73 | wv_year.setAdapter(new NumericWheelAdapter(startYear, endYear));// 设置"年"的显示数据
74 | wv_year.setLabel(context.getString(R.string.pickerview_year));// 添加文字
75 | wv_year.setCurrentItem(year - startYear);// 初始化时显示的数据
76 |
77 | // 月
78 | wv_month = (WheelView) view.findViewById(R.id.month);
79 | if(year == endYear){
80 | wv_month.setAdapter(new NumericWheelAdapter(1, endMonth));
81 | }else {
82 | wv_month.setAdapter(new NumericWheelAdapter(1, 12));
83 | }
84 | wv_month.setLabel(context.getString(R.string.pickerview_month));
85 | wv_month.setCurrentItem(month);
86 |
87 | // 日
88 | wv_day = (WheelView) view.findViewById(R.id.day);
89 | // 判断大小月及是否闰年,用来确定"日"的数据
90 | if(year == endYear && month + 1 == endMonth){
91 | wv_day.setAdapter(new NumericWheelAdapter(1, endDay));
92 | }else{
93 | if (list_big.contains(String.valueOf(month + 1))) {
94 | wv_day.setAdapter(new NumericWheelAdapter(1, 31));
95 | } else if (list_little.contains(String.valueOf(month + 1))) {
96 | wv_day.setAdapter(new NumericWheelAdapter(1, 30));
97 | } else {
98 | // 闰年
99 | if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0){
100 | wv_day.setAdapter(new NumericWheelAdapter(1, 29));
101 | }
102 | else{
103 | wv_day.setAdapter(new NumericWheelAdapter(1, 28));
104 | }
105 | }
106 | }
107 | wv_day.setLabel(context.getString(R.string.pickerview_day));
108 | wv_day.setCurrentItem(day - 1);
109 |
110 | wv_hours = (WheelView)view.findViewById(R.id.hour);
111 | wv_hours.setAdapter(new NumericWheelAdapter(0, 23));
112 | wv_hours.setLabel(context.getString(R.string.pickerview_hours));// 添加文字
113 | wv_hours.setCurrentItem(h);
114 |
115 | wv_mins = (WheelView)view.findViewById(R.id.min);
116 | wv_mins.setAdapter(new NumericWheelAdapter(0, 59));
117 | wv_mins.setLabel(context.getString(R.string.pickerview_minutes));// 添加文字
118 | wv_mins.setCurrentItem(m);
119 |
120 | // 添加"年"监听
121 | OnItemSelectedListener wheelListener_year = new OnItemSelectedListener() {
122 | @Override
123 | public void onItemSelected(int index) {
124 |
125 | int year_num = index + startYear;
126 |
127 | if(year_num == endYear){
128 | wv_month.setAdapter(new NumericWheelAdapter(1, endMonth));
129 | if(wv_month.getCurrentItem() + 1 > endMonth){
130 | wv_month.setCurrentItem(endMonth - 1);
131 | wv_day.setAdapter(new NumericWheelAdapter(1, endDay));
132 | wv_day.setCurrentItem(endDay - 1);
133 | }
134 | }else{
135 | wv_month.setAdapter(new NumericWheelAdapter(1, 12));
136 |
137 | // 判断大小月及是否闰年,用来确定"日"的数据
138 | int maxItem = 30;
139 | if (list_big.contains(String.valueOf(wv_month.getCurrentItem() + 1))) {
140 | wv_day.setAdapter(new NumericWheelAdapter(1, 31));
141 | maxItem = 31;
142 | } else if (list_little.contains(String.valueOf(wv_month.getCurrentItem() + 1))) {
143 | wv_day.setAdapter(new NumericWheelAdapter(1, 30));
144 | maxItem = 30;
145 | } else {
146 | if ((year_num % 4 == 0 && year_num % 100 != 0)|| year_num % 400 == 0){
147 | wv_day.setAdapter(new NumericWheelAdapter(1, 29));
148 | maxItem = 29;
149 | }
150 | else{
151 | wv_day.setAdapter(new NumericWheelAdapter(1, 28));
152 | maxItem = 28;
153 | }
154 | }
155 | if (wv_day.getCurrentItem() > maxItem - 1) {
156 | wv_day.setCurrentItem(maxItem - 1);
157 | }
158 | // onItemChangeListener.onItemChange(wv_year.getCurrentItem() + startYear, wv_month.getCurrentItem() + 1, wv_day.getCurrentItem() + 1);
159 | }
160 |
161 |
162 | }
163 | };
164 | // 添加"月"监听
165 | OnItemSelectedListener wheelListener_month = new OnItemSelectedListener() {
166 | @Override
167 | public void onItemSelected(int index) {
168 | int year_num = wv_year.getCurrentItem() + startYear;
169 | int month_num = index + 1;
170 | int maxItem = 30;
171 |
172 | if(year_num == endYear && month_num == endMonth){
173 | wv_day.setAdapter(new NumericWheelAdapter(1, endDay));
174 | if(wv_day.getCurrentItem() + 1 > endDay){
175 | wv_day.setCurrentItem(endDay - 1);
176 | }
177 | // onItemChangeListener.onItemChange(wv_year.getCurrentItem() + startYear, wv_month.getCurrentItem() + 1, wv_day.getCurrentItem() + 1);
178 | }else{
179 | // 判断大小月及是否闰年,用来确定"日"的数据
180 | if (list_big.contains(String.valueOf(month_num))) {
181 | wv_day.setAdapter(new NumericWheelAdapter(1, 31));
182 | maxItem = 31;
183 | } else if (list_little.contains(String.valueOf(month_num))) {
184 | wv_day.setAdapter(new NumericWheelAdapter(1, 30));
185 | maxItem = 30;
186 | } else {
187 | if ((year_num % 4 == 0 && year_num % 100 != 0)
188 | || year_num % 400 == 0){
189 | wv_day.setAdapter(new NumericWheelAdapter(1, 29));
190 | maxItem = 29;
191 | }
192 | else{
193 | wv_day.setAdapter(new NumericWheelAdapter(1, 28));
194 | maxItem = 28;
195 | }
196 | }
197 | if (wv_day.getCurrentItem() > maxItem - 1) {
198 | wv_day.setCurrentItem(maxItem - 1);
199 | }
200 | // onItemChangeListener.onItemChange(wv_year.getCurrentItem() + startYear, wv_month.getCurrentItem() + 1, wv_day.getCurrentItem() + 1);
201 | }
202 |
203 |
204 | }
205 | };
206 | wv_year.setOnItemSelectedListener(wheelListener_year);
207 | wv_month.setOnItemSelectedListener(wheelListener_month);
208 |
209 | // wv_day.setOnItemSelectedListener(new OnItemSelectedListener() {
210 | // @Override
211 | // public void onItemSelected(int index) {
212 | // onItemChangeListener.onItemChange(wv_year.getCurrentItem() + startYear, wv_month.getCurrentItem() + 1, wv_day.getCurrentItem() + 1);
213 | // }
214 | // });
215 |
216 | // 根据屏幕密度来指定选择器字体的大小(不同屏幕可能不同)
217 | int textSize = 6;
218 | switch(type){
219 | case ALL:
220 | textSize = textSize * 3;
221 | break;
222 | case YEAR_MONTH_DAY:
223 | textSize = textSize * 4;
224 | wv_hours.setVisibility(View.GONE);
225 | wv_mins.setVisibility(View.GONE);
226 | break;
227 | case HOURS_MINS:
228 | textSize = textSize * 4;
229 | wv_year.setVisibility(View.GONE);
230 | wv_month.setVisibility(View.GONE);
231 | wv_day.setVisibility(View.GONE);
232 | break;
233 | case MONTH_DAY_HOUR_MIN:
234 | textSize = textSize * 3;
235 | wv_year.setVisibility(View.GONE);
236 | break;
237 | case YEAR_MONTH:
238 | textSize = textSize * 4;
239 | wv_day.setVisibility(View.GONE);
240 | wv_hours.setVisibility(View.GONE);
241 | wv_mins.setVisibility(View.GONE);
242 | }
243 | wv_day.setTextSize(textSize);
244 | wv_month.setTextSize(textSize);
245 | wv_year.setTextSize(textSize);
246 | wv_hours.setTextSize(textSize);
247 | wv_mins.setTextSize(textSize);
248 |
249 | }
250 |
251 | /**
252 | * 设置是否循环滚动
253 | * @param cyclic
254 | */
255 | public void setCyclic(boolean cyclic){
256 | wv_year.setCyclic(cyclic);
257 | wv_month.setCyclic(cyclic);
258 | wv_day.setCyclic(cyclic);
259 | wv_hours.setCyclic(cyclic);
260 | wv_mins.setCyclic(cyclic);
261 | }
262 | public String getTime() {
263 | StringBuffer sb = new StringBuffer();
264 | sb.append((wv_year.getCurrentItem() + startYear)).append("-")
265 | .append((wv_month.getCurrentItem() + 1)).append("-")
266 | .append((wv_day.getCurrentItem() + 1)).append(" ")
267 | .append(wv_hours.getCurrentItem()).append(":")
268 | .append(wv_mins.getCurrentItem());
269 | return sb.toString();
270 | }
271 |
272 | public View getView() {
273 | return view;
274 | }
275 |
276 | public void setView(View view) {
277 | this.view = view;
278 | }
279 |
280 | public int getStartYear() {
281 | return startYear;
282 | }
283 |
284 | public void setStartYear(int startYear) {
285 | this.startYear = startYear;
286 | }
287 |
288 | public int getEndYear() {
289 | return endYear;
290 | }
291 |
292 | public void setEndYear(int endYear) {
293 | this.endYear = endYear;
294 | }
295 |
296 | public void setEndMonthDay(int endMonth, int endDay){
297 | this.endMonth = endMonth;
298 | this.endDay = endDay;
299 | }
300 |
301 | // public interface OnItemChangeListener{
302 | // void onItemChange(int year, int month, int day);
303 | // }
304 |
305 | // public void setOnItemChangeListener(OnItemChangeListener onItemChangeListener){
306 | // this.onItemChangeListener = onItemChangeListener;
307 | // }
308 | }
309 |
--------------------------------------------------------------------------------
/pickerview/src/main/res/anim/slide_in_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
--------------------------------------------------------------------------------
/pickerview/src/main/res/anim/slide_out_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
--------------------------------------------------------------------------------
/pickerview/src/main/res/drawable/selector_pickerview_btn.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/pickerview/src/main/res/layout/include_pickerview_topbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
18 |
19 |
29 |
30 |
42 |
43 |
--------------------------------------------------------------------------------
/pickerview/src/main/res/layout/layout_basepickerview.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/pickerview/src/main/res/layout/my_time_picker_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
13 |
14 |
20 |
21 |
26 |
27 |
32 |
33 |
38 |
39 |
44 |
45 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/pickerview/src/main/res/layout/pickerview_options.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
18 |
19 |
25 |
26 |
31 |
32 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/pickerview/src/main/res/layout/pickerview_time.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
18 |
19 |
24 |
25 |
30 |
31 |
36 |
37 |
42 |
43 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/pickerview/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/pickerview/src/main/res/values/bools.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | true
5 |
--------------------------------------------------------------------------------
/pickerview/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #057dff
4 | #c2daf5
5 | #f5f5f5
6 | #000000
7 | #a8a8a8
8 | #2a2a2a
9 | #d5d5d5
10 |
11 | #60000000
12 |
13 |
14 |
--------------------------------------------------------------------------------
/pickerview/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 44dp
4 |
5 |
6 | 10dp
7 |
8 |
9 | 30dp
10 |
11 |
12 | 18sp
13 | 19sp
14 |
15 |
16 |
17 | 20sp
18 |
19 |
20 |
--------------------------------------------------------------------------------
/pickerview/src/main/res/values/integers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 300
5 |
--------------------------------------------------------------------------------
/pickerview/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | cancel
4 | ok
5 |
6 |
7 | 日
8 | 时
9 | 分
10 | 秒
11 |
12 |
--------------------------------------------------------------------------------
/sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.2"
6 |
7 | defaultConfig {
8 | applicationId "cn.zhikaizhang.calendar"
9 | minSdkVersion 7
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 project(':library')
26 | compile project(':pickerview')
27 | compile 'com.android.support:appcompat-v7:23.2.0'
28 | compile 'com.android.support:design:23.2.0'
29 | }
30 |
--------------------------------------------------------------------------------
/sample/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\AndroidStudio\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 |
--------------------------------------------------------------------------------
/sample/sample.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | generateDebugAndroidTestSources
19 | generateDebugSources
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 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/sample/src/androidTest/java/cn/zhangzhikai/demo/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package cn.zhangzhikai.demo;
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 | }
--------------------------------------------------------------------------------
/sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
24 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/sample/src/main/java/cn/zhikaizhang/calendarviewdemo/Demo0.java:
--------------------------------------------------------------------------------
1 | package cn.zhikaizhang.calendarviewdemo;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import android.widget.Button;
7 | import android.widget.TextView;
8 | import android.widget.Toast;
9 |
10 | import com.bigkoo.pickerview.MyTimePickerView;
11 | import com.bigkoo.pickerview.TimePickerView;
12 |
13 | import java.util.Calendar;
14 | import java.util.Date;
15 |
16 | import cn.zhangzhikai.demo.R;
17 | import cn.zhikaizhang.calendarview.CalendarView;
18 | import cn.zhikaizhang.calendarview.ICalendarView;
19 |
20 |
21 | public class Demo0 extends Activity{
22 |
23 | private CalendarView calendarView;
24 | private MyTimePickerView timePickerView;
25 | private TextView yearMonthTextView;
26 | private Button prevButton;
27 | private Button nextButton;
28 |
29 | private static String[] MONTH_NAME = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"};
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | setContentView(R.layout.mode0);
35 | calendarView = (CalendarView)findViewById(R.id.calendarView);
36 | yearMonthTextView = (TextView)findViewById(R.id.year_month_textview);
37 | prevButton = (Button)findViewById(R.id.prev);
38 | nextButton = (Button)findViewById(R.id.next);
39 |
40 | timePickerView = new MyTimePickerView(Demo0.this);
41 | timePickerView.setTitle("Select Year/Month");
42 | timePickerView.setCyclic(false);
43 | timePickerView.setCancelable(false);
44 | timePickerView.setOnTimeSelectListener(new TimePickerView.OnTimeSelectListener() {
45 | @Override
46 | public void onTimeSelect(Date date) {
47 | Calendar c = Calendar.getInstance();
48 | c.setTime(date);
49 | int year = c.get(Calendar.YEAR);
50 | int month = c.get(Calendar.MONTH) + 1;
51 | calendarView.refresh0(year, month);
52 | }
53 | });
54 |
55 | yearMonthTextView.setText(getYearMonthText(calendarView.getYear(), calendarView.getMonth()));
56 | yearMonthTextView.setOnClickListener(new View.OnClickListener() {
57 | @Override
58 | public void onClick(View v) {
59 | timePickerView.setTime(calendarView.getCalendar().getTime());
60 | timePickerView.show();
61 | }
62 | });
63 |
64 | prevButton.setOnClickListener(new View.OnClickListener() {
65 | @Override
66 | public void onClick(View v) {
67 | Calendar c = calendarView.getCalendar();
68 | c.set(Calendar.MONTH, c.get(Calendar.MONTH) - 1);
69 | calendarView.refresh0(c.get(Calendar.YEAR), c.get(Calendar.MONTH) + 1);
70 | }
71 | });
72 |
73 | nextButton.setOnClickListener(new View.OnClickListener() {
74 | @Override
75 | public void onClick(View v) {
76 | Calendar c = calendarView.getCalendar();
77 | c.set(Calendar.MONTH, c.get(Calendar.MONTH) + 1);
78 | calendarView.refresh0(c.get(Calendar.YEAR), c.get(Calendar.MONTH) + 1);
79 | }
80 | });
81 |
82 |
83 | calendarView.setWeekTextStyle(3);
84 |
85 | calendarView.setOnRefreshListener(new ICalendarView.OnRefreshListener() {
86 | @Override
87 | public void onRefresh() {
88 | yearMonthTextView.setText(getYearMonthText(calendarView.getYear(), calendarView.getMonth()));
89 | }
90 | });
91 |
92 | calendarView.setOnItemClickListener(new ICalendarView.OnItemClickListener() {
93 | @Override
94 | public void onItemClick(int day) {
95 | int year = calendarView.getYear();
96 | int month = calendarView.getMonth();
97 | Toast.makeText(Demo0.this, year + "-" + month + "-" + day, Toast.LENGTH_SHORT).show();
98 | }
99 | });
100 |
101 | }
102 |
103 |
104 | private String getYearMonthText(int year, int month){
105 | return new StringBuilder().append(MONTH_NAME[month - 1]).append(", ").append(year).toString();
106 | }
107 |
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/sample/src/main/java/cn/zhikaizhang/calendarviewdemo/Demo1.java:
--------------------------------------------------------------------------------
1 | package cn.zhikaizhang.calendarviewdemo;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import android.widget.ImageView;
7 | import android.widget.RelativeLayout;
8 | import android.widget.TextView;
9 |
10 | import java.util.Calendar;
11 |
12 | import cn.zhangzhikai.demo.R;
13 | import cn.zhikaizhang.calendarview.CalendarView;
14 | import cn.zhikaizhang.calendarview.ICalendarView;
15 |
16 | public class Demo1 extends Activity{
17 |
18 | private CalendarView calendarView;
19 | private RelativeLayout runThisMonthRelativeLayout;
20 | private TextView runThisMonthTextView;
21 | private ImageView runThisMonthImageView;
22 | private View separator;
23 |
24 | private boolean calendarViewFold = false;
25 |
26 | @Override
27 | protected void onCreate(Bundle savedInstanceState) {
28 | super.onCreate(savedInstanceState);
29 | setContentView(R.layout.mode1);
30 | calendarView = (CalendarView)findViewById(R.id.calendarView);
31 | runThisMonthRelativeLayout = (RelativeLayout)findViewById(R.id.run_this_month);
32 | runThisMonthTextView = (TextView)findViewById(R.id.run_this_month_num);
33 | runThisMonthImageView = (ImageView)findViewById(R.id.run_this_month_img);
34 | separator = findViewById(R.id.separator);
35 |
36 | runThisMonthRelativeLayout.setOnClickListener(new View.OnClickListener() {
37 | @Override
38 | public void onClick(View v) {
39 | calendarViewFold = !calendarViewFold;
40 | if(calendarViewFold){
41 | calendarView.setVisibility(View.GONE);
42 | separator.setVisibility(View.GONE);
43 | runThisMonthImageView.setImageResource(R.drawable.right);
44 | }else{
45 | calendarView.setVisibility(View.VISIBLE);
46 | separator.setVisibility(View.VISIBLE);
47 | runThisMonthImageView.setImageResource(R.drawable.down);
48 | }
49 | }
50 | });
51 |
52 | calendarView.setOnRefreshListener(new ICalendarView.OnRefreshListener() {
53 | @Override
54 | public void onRefresh() {
55 | runThisMonthTextView.setText(calendarView.daysCompleteTheTask() + " days");
56 | }
57 | });
58 |
59 | /**
60 | * simulate the process of getting data
61 | * ..
62 | */
63 | int days = calendarView.daysOfCurrentMonth();
64 | boolean data[] = new boolean[days+1];
65 | int today = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
66 | for(int i = 1; i <= days; i++){
67 | if(i <= today){
68 | data[i] = (Math.random() > 0.5);
69 | }else{
70 | data[i] = false;
71 | }
72 | }
73 | calendarView.refresh1(data);
74 |
75 |
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/sample/src/main/java/cn/zhikaizhang/calendarviewdemo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package cn.zhikaizhang.calendarviewdemo;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.view.View;
7 | import android.widget.Button;
8 |
9 | import cn.zhangzhikai.demo.R;
10 |
11 | public class MainActivity extends Activity {
12 |
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 | setContentView(R.layout.activity_main);
17 | Button demo0 = (Button)findViewById(R.id.button0);
18 | Button demo1 = (Button)findViewById(R.id.button1);
19 | demo0.setOnClickListener(new View.OnClickListener() {
20 | @Override
21 | public void onClick(View v) {
22 | Intent intent = new Intent(MainActivity.this, Demo0.class);
23 | startActivity(intent);
24 | }
25 | });
26 | demo1.setOnClickListener(new View.OnClickListener() {
27 | @Override
28 | public void onClick(View v) {
29 | Intent intent = new Intent(MainActivity.this, Demo1.class);
30 | startActivity(intent);
31 | }
32 | });
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-hdpi/down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laserwave/calendar_view/d1bd8457868457fae4f9228ede552c63ba9e6f3a/sample/src/main/res/drawable-hdpi/down.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-hdpi/right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laserwave/calendar_view/d1bd8457868457fae4f9228ede552c63ba9e6f3a/sample/src/main/res/drawable-hdpi/right.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable/bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
17 |
18 |
26 |
27 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/mode0.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
21 |
22 |
30 |
31 |
40 |
41 |
42 |
43 |
44 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/mode1.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
26 |
27 |
35 |
36 |
45 |
46 |
47 |
52 |
53 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laserwave/calendar_view/d1bd8457868457fae4f9228ede552c63ba9e6f3a/sample/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laserwave/calendar_view/d1bd8457868457fae4f9228ede552c63ba9e6f3a/sample/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laserwave/calendar_view/d1bd8457868457fae4f9228ede552c63ba9e6f3a/sample/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laserwave/calendar_view/d1bd8457868457fae4f9228ede552c63ba9e6f3a/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/laserwave/calendar_view/d1bd8457868457fae4f9228ede552c63ba9e6f3a/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 | >
2 |
8 |
9 |
--------------------------------------------------------------------------------
/sample/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 | #ffffff
8 | #d9d9d9
9 |
10 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 16dp
6 |
7 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Calendar
3 | Settings
4 |
5 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/sample/src/test/java/cn/zhangzhikai/calendar/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package cn.zhangzhikai.demo;
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 ':sample', ':library', ':pickerview'
2 |
--------------------------------------------------------------------------------