├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── 1457534764216.gif ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── limxing │ │ └── datepicker │ │ └── MainActivity.java │ └── res │ ├── anim │ ├── activity_tobottom.xml │ └── activity_totop.xml │ ├── drawable │ ├── wheel_bg.xml │ └── wheel_val.xml │ ├── layout │ ├── activity_main.xml │ └── wheel_date_picker.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ ├── styles.xml │ └── themes.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── limxing │ │ └── library │ │ ├── AlertAnimateUtil.java │ │ ├── AlertView.java │ │ ├── AlertViewAdapter.java │ │ ├── LoopView │ │ ├── InertiaTimerTask.java │ │ ├── LoopView.java │ │ ├── LoopViewGestureListener.java │ │ ├── MessageHandler.java │ │ ├── OnItemSelectedListener.java │ │ ├── OnItemSelectedRunnable.java │ │ └── SmoothScrollTimerTask.java │ │ ├── OnConfirmeListener.java │ │ ├── OnDismissListener.java │ │ └── OnItemClickListener.java │ └── res │ ├── anim │ ├── alertview_bgin.xml │ ├── alertview_bgout.xml │ ├── fade_in_center.xml │ ├── fade_out_center.xml │ ├── slide_in_bottom.xml │ └── slide_out_bottom.xml │ ├── drawable │ ├── bg_actionsheet_cancel.xml │ ├── bg_actionsheet_header.xml │ ├── bg_alertbutton_bottom.xml │ ├── bg_alertbutton_left.xml │ ├── bg_alertbutton_none.xml │ ├── bg_alertbutton_right.xml │ ├── bg_alertview_alert.xml │ └── selector_pickerview_btn.xml │ ├── layout │ ├── alertview_data.xml │ ├── include_alertheader.xml │ ├── item_alertbutton.xml │ ├── layout_alertview.xml │ ├── layout_alertview_actionsheet.xml │ ├── layout_alertview_alert.xml │ ├── layout_alertview_alert_horizontal.xml │ └── layout_alertview_alert_vertical.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── integers.xml │ └── strings.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | DatePicker -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 26 | 27 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /1457534764216.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limxing/DatePicker/e5ccc48f917cb3e71c9c3b1f8d1502d1253dd827/1457534764216.gif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DatePicker 2 | 仿iOS的PickerView控件 从底部弹出的日期选择器,底部弹出的选择选择器 3 | 4 | ![Alt text](/1457534764216.gif) 5 | 6 | #### 第二版本更新 7 | 使用view呈现底部弹出的时间选择器,取代了之前用过的Dialog,Popwindow,学习了. 8 | 9 | 这次我使用了 Android-AlertView作为参考, 10 | 向AlertView中添加了从底部弹出的日期选择器; 11 | 12 | #### 使用 13 | git clone作为引用库,还能够自定义一些属性 14 | 15 | 16 | ####可参考原作者 17 | Android-AlertView 18 | androidWheelView -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | applicationId "com.limxing.datepicker" 9 | minSdkVersion 14 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(include: ['*.jar'], dir: 'libs') 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:23.2.0' 26 | compile project(':library') 27 | } 28 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/limxing/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/limxing/datepicker/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.limxing.datepicker; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.widget.TextView; 7 | 8 | import com.limxing.library.AlertView; 9 | import com.limxing.library.OnConfirmeListener; 10 | 11 | 12 | public class MainActivity extends AppCompatActivity implements OnConfirmeListener { 13 | 14 | private TextView text; 15 | 16 | @Override 17 | protected void onCreate(Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_main); 20 | text = (TextView) findViewById(R.id.text); 21 | } 22 | 23 | public void click(View view) { 24 | new AlertView("请选择日期",MainActivity.this,1991,2100,MainActivity.this).show(); 25 | 26 | } 27 | 28 | @Override 29 | public void result(String s) { 30 | text.setText(s); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/res/anim/activity_tobottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/anim/activity_totop.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/wheel_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/wheel_val.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | 21 | 22 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/wheel_date_picker.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 25 | 26 | 31 | 32 | 36 | 37 | 42 | 43 | 48 | 49 | 54 | 55 | 56 | 61 | 62 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limxing/DatePicker/e5ccc48f917cb3e71c9c3b1f8d1502d1253dd827/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limxing/DatePicker/e5ccc48f917cb3e71c9c3b1f8d1502d1253dd827/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limxing/DatePicker/e5ccc48f917cb3e71c9c3b1f8d1502d1253dd827/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limxing/DatePicker/e5ccc48f917cb3e71c9c3b1f8d1502d1253dd827/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limxing/DatePicker/e5ccc48f917cb3e71c9c3b1f8d1502d1253dd827/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | #D0D0D0 7 | #00000000 8 | #ffffff 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | DatePicker 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | -------------------------------------------------------------------------------- /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:2.1.0' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limxing/DatePicker/e5ccc48f917cb3e71c9c3b1f8d1502d1253dd827/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue May 24 09:14:46 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.10-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /library/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /library/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | minSdkVersion 14 9 | targetSdkVersion 23 10 | versionCode 2 11 | versionName "2.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile fileTree(dir: 'libs', include: ['*.jar']) 23 | testCompile 'junit:junit:4.12' 24 | compile 'com.android.support:appcompat-v7:23.3.0' 25 | } 26 | -------------------------------------------------------------------------------- /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 /Users/limxing/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /library/src/main/java/com/limxing/library/AlertAnimateUtil.java: -------------------------------------------------------------------------------- 1 | package com.limxing.library; 2 | 3 | import android.view.Gravity; 4 | 5 | /** 6 | * Created by Sai on 15/8/9. 7 | */ 8 | public class AlertAnimateUtil { 9 | private static final int INVALID = -1; 10 | /** 11 | * Get default animation resource when not defined by the user 12 | * 13 | * @param gravity the gravity of the dialog 14 | * @param isInAnimation determine if is in or out animation. true when is is 15 | * @return the id of the animation resource 16 | */ 17 | static int getAnimationResource(int gravity, boolean isInAnimation) { 18 | switch (gravity) { 19 | case Gravity.BOTTOM: 20 | return isInAnimation ? R.anim.slide_in_bottom : R.anim.slide_out_bottom; 21 | case Gravity.CENTER: 22 | return isInAnimation ? R.anim.fade_in_center : R.anim.fade_out_center; 23 | } 24 | return INVALID; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /library/src/main/java/com/limxing/library/AlertView.java: -------------------------------------------------------------------------------- 1 | package com.limxing.library; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.graphics.Typeface; 6 | import android.view.Gravity; 7 | import android.view.LayoutInflater; 8 | import android.view.MotionEvent; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.view.ViewStub; 12 | import android.view.animation.Animation; 13 | import android.view.animation.AnimationUtils; 14 | import android.widget.AdapterView; 15 | import android.widget.FrameLayout; 16 | import android.widget.LinearLayout; 17 | import android.widget.ListView; 18 | import android.widget.TextView; 19 | 20 | import com.limxing.library.LoopView.LoopView; 21 | import com.limxing.library.LoopView.OnItemSelectedListener; 22 | 23 | import java.util.ArrayList; 24 | import java.util.Arrays; 25 | import java.util.List; 26 | 27 | /** 28 | * Created by Sai on 15/8/9. 29 | * 精仿iOSAlertViewController控件 30 | * 点击取消按钮返回 -1,其他按钮从0开始算 31 | */ 32 | public class AlertView implements OnItemSelectedListener { 33 | private OnConfirmeListener confirmeListener; 34 | private Animation bgAnim; 35 | private Animation bgAnimOut; 36 | private LoopView yearView; 37 | private LoopView monthView; 38 | private LoopView dayView; 39 | private ArrayList dayList; 40 | 41 | /** 42 | * 三个时间的监听 43 | * 44 | * @param view 45 | */ 46 | @Override 47 | public void onItemSelected(LoopView view) { 48 | String year = yearView.getItems().get(yearView.getSelectedItem()); 49 | year = year.substring(0, year.length() - 1); 50 | String month = monthView.getItems().get(monthView.getSelectedItem()); 51 | month = month.substring(0, month.length() - 1); 52 | getDay(Integer.parseInt(year), Integer.parseInt(month)); 53 | dayView.setInitPosition(0); 54 | dayView.setItems(dayList); 55 | 56 | } 57 | 58 | /** 59 | * @param year 60 | * @param month 61 | * @return 62 | */ 63 | 64 | private int getDay(int year, int month) { 65 | int size = dayList.size(); 66 | int day = 30; 67 | boolean flag = false; 68 | switch (year % 4) { 69 | case 0: 70 | flag = true; 71 | break; 72 | default: 73 | flag = false; 74 | break; 75 | } 76 | switch (month) { 77 | case 1: 78 | case 3: 79 | case 5: 80 | case 7: 81 | case 8: 82 | case 10: 83 | case 12: 84 | day = 31; 85 | for (int i = size; i < 31; i++) { 86 | dayList.add(i + 1 + "日"); 87 | } 88 | break; 89 | case 2: 90 | day = flag ? 29 : 28; 91 | for (int i = day; i < size; i++) { 92 | dayList.remove(dayList.size() - 1); 93 | } 94 | if (size == 28 && flag) { 95 | dayList.add(29 + "日"); 96 | } 97 | 98 | break; 99 | default: 100 | day = 30; 101 | for (int i = size; i < 30; i++) { 102 | dayList.add(i + 1 + "日"); 103 | } 104 | if (size == 31) { 105 | dayList.remove(size - 1); 106 | } 107 | break; 108 | } 109 | return day; 110 | } 111 | 112 | public static enum Style { 113 | ActionSheet, 114 | Alert, 115 | Date 116 | } 117 | 118 | private final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( 119 | ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM 120 | ); 121 | public static final int HORIZONTAL_BUTTONS_MAXCOUNT = 2; 122 | public static final String OTHERS = "others"; 123 | public static final String DESTRUCTIVE = "destructive"; 124 | public static final String CANCEL = "cancel"; 125 | public static final String TITLE = "title"; 126 | public static final String MSG = "msg"; 127 | public static final int CANCELPOSITION = -1;//点击取消按钮返回 -1,其他按钮从0开始算 128 | 129 | private String title; 130 | private String msg; 131 | private List mDestructive; 132 | private List mOthers; 133 | private String cancel; 134 | private ArrayList mDatas = new ArrayList(); 135 | 136 | private Context context; 137 | private ViewGroup contentContainer; 138 | private ViewGroup decorView;//activity的根View 139 | private ViewGroup rootView;//AlertView 的 根View 140 | private ViewGroup loAlertHeader;//窗口headerView 141 | 142 | private Style style = Style.Alert; 143 | 144 | private OnDismissListener onDismissListener; 145 | private OnItemClickListener onItemClickListener; 146 | private boolean isDismissing; 147 | 148 | private Animation outAnim; 149 | private Animation inAnim; 150 | private int gravity = Gravity.CENTER; 151 | 152 | public AlertView(String title, String msg, String cancel, String[] destructive, String[] others, Context context, Style style, OnItemClickListener onItemClickListener) { 153 | this.context = context; 154 | if (style != null) this.style = style; 155 | this.onItemClickListener = onItemClickListener; 156 | initData(title, msg, cancel, destructive, others); 157 | initViews(); 158 | init(); 159 | initEvents(); 160 | } 161 | 162 | public AlertView(String title, Context context, int startyear, int endyear, OnConfirmeListener confirmeListener) { 163 | this.title = title; 164 | this.context = context; 165 | this.confirmeListener = confirmeListener; 166 | this.style = Style.Date; 167 | initData(startyear, endyear); 168 | init(); 169 | initEvents(); 170 | } 171 | 172 | /** 173 | * 初始化时间 174 | * 175 | * @param startyear 176 | * @param endyear 177 | */ 178 | private void initData(int startyear, int endyear) { 179 | List yearList = new ArrayList<>(); 180 | List monthList = new ArrayList<>(); 181 | dayList = new ArrayList<>(); 182 | for (int i = startyear; i < endyear + 1; i++) { 183 | yearList.add(i + "年"); 184 | } 185 | for (int i = 1; i < 13; i++) { 186 | monthList.add(i + "月"); 187 | } 188 | for (int i = 1; i < 32; i++) { 189 | dayList.add(i + "日"); 190 | } 191 | initViews(yearList, monthList, dayList); 192 | initLoopViewListener(); 193 | 194 | } 195 | 196 | private void initLoopViewListener() { 197 | yearView.setListener(this); 198 | monthView.setListener(this); 199 | // dayView.setListener(this); 200 | } 201 | 202 | /** 203 | * 自定义的三级选择,联动需要自己设置下一个loopView的内容 204 | * 205 | * @param title 206 | * @param context 207 | * @param year 208 | * @param month 209 | * @param day 210 | * @param confirmeListener 211 | */ 212 | public AlertView(String title, Context context, List year, List month, List day, OnConfirmeListener confirmeListener) { 213 | this.context = context; 214 | this.title = title; 215 | this.style = Style.Date; 216 | this.confirmeListener = confirmeListener; 217 | initViews(year, month, day); 218 | init(); 219 | initEvents(); 220 | } 221 | 222 | private void initViews(List year, List month, List day) { 223 | initViews(); 224 | params.gravity = Gravity.BOTTOM; 225 | contentContainer.setLayoutParams(params); 226 | gravity = Gravity.BOTTOM; 227 | LayoutInflater layoutInflater = LayoutInflater.from(context); 228 | initDateViews(layoutInflater, year, month, day, title); 229 | } 230 | 231 | private void initDateViews(LayoutInflater layoutInflater, List year, final List month, final List day, String titlr) { 232 | ViewGroup viewGroup = (ViewGroup) layoutInflater.inflate(R.layout.alertview_data, contentContainer); 233 | yearView = (LoopView) viewGroup.findViewById(R.id.year); 234 | monthView = (LoopView) viewGroup.findViewById(R.id.month); 235 | TextView tvTitle = (TextView) viewGroup.findViewById(R.id.tvTitle); 236 | viewGroup.findViewById(R.id.btnSubmit).setOnClickListener(new View.OnClickListener() { 237 | @Override 238 | public void onClick(View view) { 239 | dismiss(); 240 | String s = yearView.getItems().get(yearView.getSelectedItem()); 241 | if (month != null) { 242 | s = s + monthView.getItems().get(monthView.getSelectedItem()); 243 | } 244 | if (day != null) { 245 | s = s + dayView.getItems().get(dayView.getSelectedItem()); 246 | } 247 | confirmeListener.result(s); 248 | } 249 | }); 250 | viewGroup.findViewById(R.id.btnCancel).setOnClickListener(new View.OnClickListener() { 251 | @Override 252 | public void onClick(View view) { 253 | dismiss(); 254 | } 255 | }); 256 | tvTitle.setText(title); 257 | dayView = (LoopView) viewGroup.findViewById(R.id.day); 258 | yearView.setItems(year); 259 | if (month == null) { 260 | monthView.setVisibility(View.GONE); 261 | } else { 262 | monthView.setItems(month); 263 | } 264 | if (day == null) { 265 | dayView.setVisibility(View.GONE); 266 | } else { 267 | dayView.setItems(day); 268 | } 269 | 270 | 271 | } 272 | 273 | /** 274 | * 获取数据 275 | */ 276 | protected void initData(String title, String msg, String cancel, String[] destructive, String[] others) { 277 | 278 | this.title = title; 279 | this.msg = msg; 280 | if (destructive != null) { 281 | this.mDestructive = Arrays.asList(destructive); 282 | this.mDatas.addAll(mDestructive); 283 | } 284 | if (others != null) { 285 | this.mOthers = Arrays.asList(others); 286 | this.mDatas.addAll(mOthers); 287 | } 288 | if (cancel != null) { 289 | this.cancel = cancel; 290 | if (style == Style.Alert && mDatas.size() < HORIZONTAL_BUTTONS_MAXCOUNT) { 291 | this.mDatas.add(0, cancel); 292 | } 293 | } 294 | 295 | } 296 | 297 | protected void initViews() { 298 | LayoutInflater layoutInflater = LayoutInflater.from(context); 299 | decorView = (ViewGroup) ((Activity) context).getWindow().getDecorView().findViewById(android.R.id.content); 300 | rootView = (ViewGroup) layoutInflater.inflate(R.layout.layout_alertview, decorView, false); 301 | rootView.setLayoutParams(new FrameLayout.LayoutParams( 302 | ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT 303 | )); 304 | // rootView.setOnTouchListener(new View.OnTouchListener() { 305 | // @Override 306 | // public boolean onTouch(View view, MotionEvent motionEvent) { 307 | // if () { 308 | // dismiss(); 309 | // } 310 | // return false; 311 | // } 312 | // }); 313 | contentContainer = (ViewGroup) rootView.findViewById(R.id.content_container); 314 | contentContainer.setOnTouchListener(new View.OnTouchListener() { 315 | @Override 316 | public boolean onTouch(View view, MotionEvent motionEvent) { 317 | return true; 318 | } 319 | }); 320 | int margin_alert_left_right = 0; 321 | switch (style) { 322 | case ActionSheet: 323 | params.gravity = Gravity.BOTTOM; 324 | margin_alert_left_right = context.getResources().getDimensionPixelSize(R.dimen.margin_actionsheet_left_right); 325 | params.setMargins(margin_alert_left_right, 0, margin_alert_left_right, margin_alert_left_right); 326 | contentContainer.setLayoutParams(params); 327 | gravity = Gravity.BOTTOM; 328 | initActionSheetViews(layoutInflater); 329 | break; 330 | case Alert: 331 | params.gravity = Gravity.CENTER; 332 | margin_alert_left_right = context.getResources().getDimensionPixelSize(R.dimen.margin_alert_left_right); 333 | params.setMargins(margin_alert_left_right, 0, margin_alert_left_right, 0); 334 | contentContainer.setLayoutParams(params); 335 | gravity = Gravity.CENTER; 336 | initAlertViews(layoutInflater); 337 | break; 338 | } 339 | } 340 | 341 | protected void initHeaderView(ViewGroup viewGroup) { 342 | loAlertHeader = (ViewGroup) viewGroup.findViewById(R.id.loAlertHeader); 343 | //标题和消息 344 | TextView tvAlertTitle = (TextView) viewGroup.findViewById(R.id.tvAlertTitle); 345 | TextView tvAlertMsg = (TextView) viewGroup.findViewById(R.id.tvAlertMsg); 346 | if (title != null) { 347 | tvAlertTitle.setText(title); 348 | } else { 349 | tvAlertTitle.setVisibility(View.GONE); 350 | } 351 | if (msg != null) { 352 | tvAlertMsg.setText(msg); 353 | } else { 354 | tvAlertMsg.setVisibility(View.GONE); 355 | } 356 | } 357 | 358 | protected void initListView() { 359 | ListView alertButtonListView = (ListView) contentContainer.findViewById(R.id.alertButtonListView); 360 | //把cancel作为footerView 361 | if (cancel != null && style == Style.Alert) { 362 | View itemView = LayoutInflater.from(context).inflate(R.layout.item_alertbutton, null); 363 | TextView tvAlert = (TextView) itemView.findViewById(R.id.tvAlert); 364 | tvAlert.setText(cancel); 365 | tvAlert.setClickable(true); 366 | tvAlert.setTypeface(Typeface.DEFAULT_BOLD); 367 | tvAlert.setTextColor(context.getResources().getColor(R.color.textColor_alert_button_cancel)); 368 | tvAlert.setBackgroundResource(R.drawable.bg_alertbutton_bottom); 369 | tvAlert.setOnClickListener(new OnTextClickListener(CANCELPOSITION)); 370 | alertButtonListView.addFooterView(itemView); 371 | } 372 | AlertViewAdapter adapter = new AlertViewAdapter(mDatas, mDestructive); 373 | alertButtonListView.setAdapter(adapter); 374 | alertButtonListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 375 | @Override 376 | public void onItemClick(AdapterView adapterView, View view, int position, long l) { 377 | if (onItemClickListener != null) 378 | onItemClickListener.onItemClick(AlertView.this, position); 379 | dismiss(); 380 | } 381 | }); 382 | } 383 | 384 | protected void initActionSheetViews(LayoutInflater layoutInflater) { 385 | ViewGroup viewGroup = (ViewGroup) layoutInflater.inflate(R.layout.layout_alertview_actionsheet, contentContainer); 386 | initHeaderView(viewGroup); 387 | 388 | initListView(); 389 | TextView tvAlertCancel = (TextView) contentContainer.findViewById(R.id.tvAlertCancel); 390 | if (cancel != null) { 391 | tvAlertCancel.setVisibility(View.VISIBLE); 392 | tvAlertCancel.setText(cancel); 393 | } 394 | tvAlertCancel.setOnClickListener(new OnTextClickListener(CANCELPOSITION)); 395 | } 396 | 397 | protected void initAlertViews(LayoutInflater layoutInflater) { 398 | 399 | ViewGroup viewGroup = (ViewGroup) layoutInflater.inflate(R.layout.layout_alertview_alert, contentContainer); 400 | initHeaderView(viewGroup); 401 | 402 | int position = 0; 403 | //如果总数据小于等于HORIZONTAL_BUTTONS_MAXCOUNT,则是横向button 404 | if (mDatas.size() <= HORIZONTAL_BUTTONS_MAXCOUNT) { 405 | ViewStub viewStub = (ViewStub) contentContainer.findViewById(R.id.viewStubHorizontal); 406 | viewStub.inflate(); 407 | LinearLayout loAlertButtons = (LinearLayout) contentContainer.findViewById(R.id.loAlertButtons); 408 | for (int i = 0; i < mDatas.size(); i++) { 409 | //如果不是第一个按钮 410 | if (i != 0) { 411 | //添加上按钮之间的分割线 412 | View divier = new View(context); 413 | divier.setBackgroundColor(context.getResources().getColor(R.color.bgColor_divier)); 414 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams((int) context.getResources().getDimension(R.dimen.size_divier), LinearLayout.LayoutParams.MATCH_PARENT); 415 | loAlertButtons.addView(divier, params); 416 | } 417 | View itemView = LayoutInflater.from(context).inflate(R.layout.item_alertbutton, null); 418 | TextView tvAlert = (TextView) itemView.findViewById(R.id.tvAlert); 419 | tvAlert.setClickable(true); 420 | 421 | //设置点击效果 422 | if (mDatas.size() == 1) { 423 | tvAlert.setBackgroundResource(R.drawable.bg_alertbutton_bottom); 424 | } else if (i == 0) {//设置最左边的按钮效果 425 | tvAlert.setBackgroundResource(R.drawable.bg_alertbutton_left); 426 | } else if (i == mDatas.size() - 1) {//设置最右边的按钮效果 427 | tvAlert.setBackgroundResource(R.drawable.bg_alertbutton_right); 428 | } 429 | String data = mDatas.get(i); 430 | tvAlert.setText(data); 431 | 432 | //取消按钮的样式 433 | if (data == cancel) { 434 | tvAlert.setTypeface(Typeface.DEFAULT_BOLD); 435 | tvAlert.setTextColor(context.getResources().getColor(R.color.textColor_alert_button_cancel)); 436 | tvAlert.setOnClickListener(new OnTextClickListener(CANCELPOSITION)); 437 | position = position - 1; 438 | } 439 | //高亮按钮的样式 440 | else if (mDestructive != null && mDestructive.contains(data)) { 441 | tvAlert.setTextColor(context.getResources().getColor(R.color.textColor_alert_button_destructive)); 442 | } 443 | 444 | tvAlert.setOnClickListener(new OnTextClickListener(position)); 445 | position++; 446 | loAlertButtons.addView(itemView, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 447 | LinearLayout.LayoutParams.WRAP_CONTENT, 1)); 448 | } 449 | } else { 450 | ViewStub viewStub = (ViewStub) contentContainer.findViewById(R.id.viewStubVertical); 451 | viewStub.inflate(); 452 | initListView(); 453 | } 454 | } 455 | 456 | protected void init() { 457 | inAnim = getInAnimation(); 458 | outAnim = getOutAnimation(); 459 | bgAnim = AnimationUtils.loadAnimation(context, R.anim.alertview_bgin); 460 | bgAnimOut = AnimationUtils.loadAnimation(context, R.anim.alertview_bgout); 461 | } 462 | 463 | protected void initEvents() { 464 | } 465 | 466 | public AlertView addExtView(View extView) { 467 | loAlertHeader.addView(extView); 468 | return this; 469 | } 470 | 471 | /** 472 | * show的时候调用 473 | * 474 | * @param view 这个View 475 | */ 476 | private void onAttached(View view) { 477 | decorView.addView(view); 478 | rootView.startAnimation(bgAnim); 479 | contentContainer.startAnimation(inAnim); 480 | } 481 | 482 | /** 483 | * 添加这个View到Activity的根视图 484 | */ 485 | public void show() { 486 | if (isShowing()) { 487 | return; 488 | } 489 | onAttached(rootView); 490 | } 491 | 492 | /** 493 | * 检测该View是不是已经添加到根视图 494 | * 495 | * @return 如果视图已经存在该View返回true 496 | */ 497 | public boolean isShowing() { 498 | View view = decorView.findViewById(R.id.outmost_container); 499 | return view != null; 500 | } 501 | 502 | public void dismiss() { 503 | if (isDismissing) { 504 | return; 505 | } 506 | 507 | //消失动画 508 | outAnim.setAnimationListener(new Animation.AnimationListener() { 509 | @Override 510 | public void onAnimationStart(Animation animation) { 511 | 512 | } 513 | 514 | @Override 515 | public void onAnimationEnd(Animation animation) { 516 | decorView.post(new Runnable() { 517 | @Override 518 | public void run() { 519 | //从activity根视图移除 520 | decorView.removeView(rootView); 521 | isDismissing = false; 522 | if (onDismissListener != null) { 523 | onDismissListener.onDismiss(AlertView.this); 524 | } 525 | } 526 | }); 527 | } 528 | 529 | @Override 530 | public void onAnimationRepeat(Animation animation) { 531 | 532 | } 533 | }); 534 | contentContainer.startAnimation(outAnim); 535 | rootView.startAnimation(bgAnimOut); 536 | isDismissing = true; 537 | } 538 | 539 | public Animation getInAnimation() { 540 | int res = AlertAnimateUtil.getAnimationResource(this.gravity, true); 541 | return AnimationUtils.loadAnimation(context, res); 542 | } 543 | 544 | public Animation getOutAnimation() { 545 | int res = AlertAnimateUtil.getAnimationResource(this.gravity, false); 546 | return AnimationUtils.loadAnimation(context, res); 547 | } 548 | 549 | public AlertView setOnDismissListener(OnDismissListener onDismissListener) { 550 | this.onDismissListener = onDismissListener; 551 | return this; 552 | } 553 | 554 | class OnTextClickListener implements View.OnClickListener { 555 | 556 | private int position; 557 | 558 | public OnTextClickListener(int position) { 559 | this.position = position; 560 | } 561 | 562 | @Override 563 | public void onClick(View view) { 564 | if (onItemClickListener != null) 565 | onItemClickListener.onItemClick(AlertView.this, position); 566 | dismiss(); 567 | } 568 | } 569 | 570 | /** 571 | * 主要用于拓展View的时候有输入框,键盘弹出则设置MarginBottom往上顶,避免输入法挡住界面 572 | */ 573 | public void setMarginBottom(int marginBottom) { 574 | int margin_alert_left_right = context.getResources().getDimensionPixelSize(R.dimen.margin_alert_left_right); 575 | params.setMargins(margin_alert_left_right, 0, margin_alert_left_right, marginBottom); 576 | contentContainer.setLayoutParams(params); 577 | } 578 | 579 | /** 580 | * 设置点击返回键是否关闭对话框 581 | * 582 | * @param isCancelable 583 | * @return 584 | */ 585 | public AlertView setCancelable(boolean isCancelable) { 586 | View view = rootView.findViewById(R.id.outmost_container); 587 | 588 | if (isCancelable) { 589 | view.setOnTouchListener(onCancelableTouchListener); 590 | } else { 591 | view.setOnTouchListener(null); 592 | } 593 | return this; 594 | } 595 | 596 | /** 597 | * Called when the user touch on black overlay in order to dismiss the dialog 598 | */ 599 | private final View.OnTouchListener onCancelableTouchListener = new View.OnTouchListener() { 600 | @Override 601 | public boolean onTouch(View v, MotionEvent event) { 602 | if (event.getAction() == MotionEvent.ACTION_DOWN) { 603 | dismiss(); 604 | } 605 | return false; 606 | } 607 | }; 608 | 609 | /** 610 | * 向外爆喽三个联动View 611 | * 612 | * @return 613 | */ 614 | public LoopView getYearView() { 615 | return yearView; 616 | } 617 | 618 | public LoopView getMonthView() { 619 | return monthView; 620 | } 621 | 622 | public LoopView getDayView() { 623 | return dayView; 624 | } 625 | } 626 | -------------------------------------------------------------------------------- /library/src/main/java/com/limxing/library/AlertViewAdapter.java: -------------------------------------------------------------------------------- 1 | package com.limxing.library; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import android.widget.TextView; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * Created by Sai on 15/8/9. 14 | */ 15 | public class AlertViewAdapter extends BaseAdapter{ 16 | private List mDatas; 17 | private List mDestructive; 18 | public AlertViewAdapter(List datas,List destructive){ 19 | this.mDatas =datas; 20 | this.mDestructive =destructive; 21 | } 22 | @Override 23 | public int getCount() { 24 | return mDatas.size(); 25 | } 26 | 27 | @Override 28 | public Object getItem(int position) { 29 | return mDatas.get(position); 30 | } 31 | 32 | @Override 33 | public long getItemId(int position) { 34 | return position; 35 | } 36 | 37 | @Override 38 | public View getView(int position, View convertView, ViewGroup parent) { 39 | String data= mDatas.get(position); 40 | Holder holder=null; 41 | View view =convertView; 42 | if(view==null){ 43 | LayoutInflater inflater = LayoutInflater.from(parent.getContext()); 44 | view=inflater.inflate( R.layout.item_alertbutton, null); 45 | holder=creatHolder(view); 46 | view.setTag(holder); 47 | } 48 | else{ 49 | holder=(Holder) view.getTag(); 50 | } 51 | holder.UpdateUI(parent.getContext(),data,position); 52 | return view; 53 | } 54 | public Holder creatHolder(View view){ 55 | return new Holder(view); 56 | } 57 | class Holder { 58 | private TextView tvAlert; 59 | 60 | public Holder(View view){ 61 | tvAlert = (TextView) view.findViewById( R.id.tvAlert); 62 | } 63 | public void UpdateUI(Context context,String data,int position){ 64 | tvAlert.setText(data); 65 | if (mDestructive!= null && mDestructive.contains(data)){ 66 | tvAlert.setTextColor(context.getResources().getColor( R.color.textColor_alert_button_destructive)); 67 | } 68 | else{ 69 | tvAlert.setTextColor(context.getResources().getColor( R.color.textColor_alert_button_others)); 70 | } 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /library/src/main/java/com/limxing/library/LoopView/InertiaTimerTask.java: -------------------------------------------------------------------------------- 1 | // Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov. 2 | // Jad home page: http://www.geocities.com/kpdus/jad.html 3 | // Decompiler options: braces fieldsfirst space lnc 4 | 5 | package com.limxing.library.LoopView; 6 | 7 | import java.util.TimerTask; 8 | 9 | // Referenced classes of package com.qingchifan.view: 10 | // LoopView 11 | 12 | final class InertiaTimerTask extends TimerTask { 13 | 14 | float a; 15 | final float velocityY; 16 | final LoopView loopView; 17 | 18 | InertiaTimerTask(LoopView loopview, float velocityY) { 19 | super(); 20 | loopView = loopview; 21 | this.velocityY = velocityY; 22 | a = Integer.MAX_VALUE; 23 | } 24 | 25 | @Override 26 | public final void run() { 27 | if (a == Integer.MAX_VALUE) { 28 | if (Math.abs(velocityY) > 2000F) { 29 | if (velocityY > 0.0F) { 30 | a = 2000F; 31 | } else { 32 | a = -2000F; 33 | } 34 | } else { 35 | a = velocityY; 36 | } 37 | } 38 | if (Math.abs(a) >= 0.0F && Math.abs(a) <= 20F) { 39 | loopView.cancelFuture(); 40 | loopView.handler.sendEmptyMessage(MessageHandler.WHAT_SMOOTH_SCROLL); 41 | return; 42 | } 43 | int i = (int) ((a * 10F) / 1000F); 44 | LoopView loopview = loopView; 45 | loopview.totalScrollY = loopview.totalScrollY - i; 46 | if (!loopView.isLoop) { 47 | float itemHeight = loopView.lineSpacingMultiplier * loopView.maxTextHeight; 48 | if (loopView.totalScrollY <= (int) ((float) (-loopView.initPosition) * itemHeight)) { 49 | a = 40F; 50 | loopView.totalScrollY = (int) ((float) (-loopView.initPosition) * itemHeight); 51 | } else if (loopView.totalScrollY >= (int) ((float) (loopView.items.size() - 1 - loopView.initPosition) * itemHeight)) { 52 | loopView.totalScrollY = (int) ((float) (loopView.items.size() - 1 - loopView.initPosition) * itemHeight); 53 | a = -40F; 54 | } 55 | } 56 | if (a < 0.0F) { 57 | a = a + 20F; 58 | } else { 59 | a = a - 20F; 60 | } 61 | loopView.handler.sendEmptyMessage(MessageHandler.WHAT_INVALIDATE_LOOP_VIEW); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /library/src/main/java/com/limxing/library/LoopView/LoopView.java: -------------------------------------------------------------------------------- 1 | package com.limxing.library.LoopView; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | import android.graphics.Rect; 7 | import android.graphics.Typeface; 8 | import android.os.Handler; 9 | import android.util.AttributeSet; 10 | import android.view.GestureDetector; 11 | import android.view.MotionEvent; 12 | import android.view.View; 13 | 14 | import java.util.List; 15 | import java.util.concurrent.Executors; 16 | import java.util.concurrent.ScheduledExecutorService; 17 | import java.util.concurrent.ScheduledFuture; 18 | import java.util.concurrent.TimeUnit; 19 | 20 | /** 21 | * 使用方法 22 | * LoopView loopView = (LoopView) findViewById(R.id.loopview); 23 | * ArrayList list = new ArrayList<>(); 24 | * for (int i = 0; i < 15; i++) { 25 | * list.add(2000 + i+"年"); 26 | * } 27 | * //设置是否循环播放 28 | * //loopView.setNotLoop(); 29 | * //滚动监听 30 | * loopView.setListener(new OnItemSelectedListener() { 31 | * 32 | * @Override public void onItemSelected(int index) { 33 | * Log.d("debug", "Item " + index); 34 | * } 35 | * }); 36 | * //设置原始数据 37 | * loopView.setItems(list); 38 | * //设置初始位置 39 | * loopView.setInitPosition(5); 40 | * //设置字体大小 41 | * //loopView.setTextSize(20); 42 | * Created by Weidongjian on 2015/8/18. 43 | */ 44 | public class LoopView extends View { 45 | 46 | // private static final float CENTERCONTENTOFFSET = 6; 47 | private float scaleX = 1.05F; 48 | private int widthMeasureSpec; 49 | private float itemHeight; 50 | // private float centerY; 51 | 52 | public enum ACTION { 53 | // 点击,滑翔(滑到尽头),拖拽事件 54 | CLICK, FLING, DAGGLE 55 | } 56 | 57 | Context context; 58 | 59 | Handler handler; 60 | private GestureDetector gestureDetector; 61 | OnItemSelectedListener onItemSelectedListener; 62 | 63 | // Timer mTimer; 64 | ScheduledExecutorService mExecutor = Executors.newSingleThreadScheduledExecutor(); 65 | private ScheduledFuture mFuture; 66 | 67 | Paint paintOuterText; 68 | Paint paintCenterText; 69 | Paint paintIndicator; 70 | 71 | List items; 72 | 73 | int textSize; 74 | int maxTextWidth; 75 | int maxTextHeight; 76 | 77 | int colorGray; 78 | int colorBlack; 79 | int colorLightGray; 80 | 81 | // 条目间距倍数 82 | float lineSpacingMultiplier; 83 | boolean isLoop; 84 | 85 | // 第一条线Y坐标值 86 | float firstLineY; 87 | float secondLineY; 88 | 89 | int totalScrollY; 90 | int initPosition; 91 | private int selectedItem; 92 | int preCurrentIndex; 93 | int change; 94 | 95 | // 显示几个条目 96 | int itemsVisible; 97 | 98 | int measuredHeight; 99 | int measuredWidth; 100 | int paddingLeft = 0; 101 | int paddingRight = 0; 102 | 103 | // 半圆周长 104 | int halfCircumference; 105 | // 半径 106 | int radius; 107 | 108 | private int mOffset = 0; 109 | private float previousY; 110 | long startTime = 0; 111 | 112 | private Rect tempRect = new Rect(); 113 | 114 | public LoopView(Context context) { 115 | super(context); 116 | initLoopView(context); 117 | } 118 | 119 | public LoopView(Context context, AttributeSet attributeset) { 120 | super(context, attributeset); 121 | initLoopView(context); 122 | } 123 | 124 | public LoopView(Context context, AttributeSet attributeset, int defStyleAttr) { 125 | super(context, attributeset, defStyleAttr); 126 | initLoopView(context); 127 | } 128 | 129 | private void initLoopView(Context context) { 130 | this.context = context; 131 | handler = new MessageHandler(this); 132 | gestureDetector = new GestureDetector(context, new LoopViewGestureListener(this)); 133 | gestureDetector.setIsLongpressEnabled(false); 134 | 135 | lineSpacingMultiplier = 1.6F; 136 | isLoop = false; 137 | itemsVisible = 9; 138 | textSize = 0; 139 | colorGray = 0xffafafaf; 140 | colorBlack = 0xff313131; 141 | colorLightGray = 0xffc5c5c5; 142 | 143 | totalScrollY = 0; 144 | initPosition = -1; 145 | 146 | initPaints(); 147 | 148 | setTextSize(20F); 149 | } 150 | 151 | private void initPaints() { 152 | paintOuterText = new Paint(); 153 | paintOuterText.setColor(colorGray); 154 | paintOuterText.setAntiAlias(true); 155 | paintOuterText.setTypeface(Typeface.MONOSPACE); 156 | paintOuterText.setTextSize(textSize); 157 | 158 | paintCenterText = new Paint(); 159 | paintCenterText.setColor(colorBlack); 160 | paintCenterText.setAntiAlias(true); 161 | paintCenterText.setTextScaleX(scaleX); 162 | paintCenterText.setTypeface(Typeface.MONOSPACE); 163 | paintCenterText.setTextSize(textSize); 164 | 165 | paintIndicator = new Paint(); 166 | paintIndicator.setColor(colorLightGray); 167 | paintIndicator.setAntiAlias(true); 168 | 169 | if (android.os.Build.VERSION.SDK_INT >= 11) { 170 | setLayerType(LAYER_TYPE_SOFTWARE, null); 171 | } 172 | } 173 | 174 | private void remeasure() { 175 | if (items == null) { 176 | return; 177 | } 178 | 179 | measureTextWidthHeight(); 180 | //最大Text的高度乘间距倍数得到 可见文字实际的总高度,半圆的周长 181 | halfCircumference = (int) (itemHeight * (itemsVisible - 1)); 182 | // halfCircumference = (int) (maxTextHeight * lineSpacingMultiplier * (itemsVisible - 1)); 183 | measuredHeight = (int) ((halfCircumference * 2) / Math.PI); 184 | radius = (int) (halfCircumference / Math.PI); 185 | // measuredWidth = maxTextWidth + paddingLeft + paddingRight; 186 | measuredWidth = MeasureSpec.getSize(widthMeasureSpec); 187 | //计算两条横线和控件中间点的Y位置 188 | firstLineY = (measuredHeight - itemHeight) / 2.0F; 189 | secondLineY = (measuredHeight + itemHeight) / 2.0F; 190 | // centerY = (measuredHeight + maxTextHeight) / 2.0F - CENTERCONTENTOFFSET; 191 | 192 | // firstLineY = (int) ((measuredHeight - lineSpacingMultiplier * maxTextHeight) / 2.0F); 193 | // secondLineY = (int) ((measuredHeight + lineSpacingMultiplier * maxTextHeight) / 2.0F); 194 | if (initPosition == -1) { 195 | if (isLoop) { 196 | initPosition = (items.size() + 1) / 2; 197 | } else { 198 | initPosition = 0; 199 | } 200 | } 201 | 202 | preCurrentIndex = initPosition; 203 | } 204 | 205 | private void measureTextWidthHeight() { 206 | for (int i = 0; i < items.size(); i++) { 207 | String s1 = items.get(i); 208 | paintCenterText.getTextBounds(s1, 0, s1.length(), tempRect); 209 | int textWidth = tempRect.width(); 210 | if (textWidth > maxTextWidth) { 211 | maxTextWidth = (int) (textWidth * scaleX); 212 | } 213 | paintCenterText.getTextBounds("\u661F\u671F", 0, 2, tempRect); // 星期 214 | int textHeight = tempRect.height(); 215 | if (textHeight > maxTextHeight) { 216 | maxTextHeight = textHeight; 217 | } 218 | } 219 | itemHeight = lineSpacingMultiplier * maxTextHeight; 220 | 221 | } 222 | 223 | void smoothScroll(ACTION action) { 224 | cancelFuture(); 225 | if (action == ACTION.FLING || action == ACTION.DAGGLE) { 226 | // float itemHeight = lineSpacingMultiplier * maxTextHeight; 227 | mOffset = (int) ((totalScrollY % itemHeight + itemHeight) % itemHeight); 228 | if ((float) mOffset > itemHeight / 2.0F) { 229 | mOffset = (int) (itemHeight - (float) mOffset); 230 | } else { 231 | mOffset = -mOffset; 232 | } 233 | } 234 | mFuture = mExecutor.scheduleWithFixedDelay(new SmoothScrollTimerTask(this, mOffset), 0, 10, TimeUnit.MILLISECONDS); 235 | } 236 | 237 | // void smoothScroll() { 238 | // int offset = (int) (totalScrollY % (lineSpacingMultiplier * maxTextHeight)); 239 | // cancelFuture(); 240 | // mFuture = mExecutor.scheduleWithFixedDelay(new SmoothScrollTimerTask(this, offset), 0, 10, TimeUnit.MILLISECONDS); 241 | // } 242 | 243 | protected final void scrollBy(float velocityY) { 244 | cancelFuture(); 245 | // 修改这个值可以改变滑行速度 246 | int velocityFling = 10; 247 | mFuture = mExecutor.scheduleWithFixedDelay(new InertiaTimerTask(this, velocityY), 0, velocityFling, TimeUnit.MILLISECONDS); 248 | } 249 | 250 | public void cancelFuture() { 251 | if (mFuture != null && !mFuture.isCancelled()) { 252 | mFuture.cancel(true); 253 | mFuture = null; 254 | } 255 | } 256 | 257 | public final void setNotLoop() { 258 | isLoop = false; 259 | } 260 | 261 | public final void setTextSize(float size) { 262 | if (size > 0.0F) { 263 | textSize = (int) (context.getResources().getDisplayMetrics().density * size); 264 | paintOuterText.setTextSize(textSize); 265 | paintCenterText.setTextSize(textSize); 266 | } 267 | } 268 | 269 | public final void setInitPosition(int initPosition) { 270 | if (initPosition < 0) { 271 | this.initPosition = 0; 272 | } else { 273 | if (items != null && (items.size() - 1) > initPosition) { 274 | this.initPosition = initPosition; 275 | } 276 | } 277 | } 278 | 279 | public final void setListener(OnItemSelectedListener OnItemSelectedListener) { 280 | onItemSelectedListener = OnItemSelectedListener; 281 | } 282 | 283 | public final void setItems(List items) { 284 | this.items = items; 285 | remeasure(); 286 | invalidate(); 287 | } 288 | 289 | public List getItems() { 290 | return items; 291 | } 292 | 293 | @Override 294 | public int getPaddingLeft() { 295 | return paddingLeft; 296 | } 297 | 298 | @Override 299 | public int getPaddingRight() { 300 | return paddingRight; 301 | } 302 | 303 | // 设置左右内边距 304 | public void setViewPadding(int left, int top, int right, int bottom) { 305 | paddingLeft = left; 306 | paddingRight = right; 307 | } 308 | 309 | public final int getSelectedItem() { 310 | return selectedItem; 311 | } 312 | // 313 | // protected final void scrollBy(float velocityY) { 314 | // Timer timer = new Timer(); 315 | // mTimer = timer; 316 | // timer.schedule(new InertiaTimerTask(this, velocityY, timer), 0L, 20L); 317 | // } 318 | 319 | protected final void onItemSelected() { 320 | if (onItemSelectedListener != null) { 321 | postDelayed(new OnItemSelectedRunnable(this), 200L); 322 | } 323 | } 324 | 325 | @Override 326 | protected void onDraw(Canvas canvas) { 327 | if (items == null) { 328 | return; 329 | } 330 | 331 | String as[] = new String[itemsVisible]; 332 | change = (int) (totalScrollY / (lineSpacingMultiplier * maxTextHeight)); 333 | preCurrentIndex = initPosition + change % (items.size()); 334 | 335 | if (!isLoop) { 336 | if (preCurrentIndex < 0) { 337 | preCurrentIndex = 0; 338 | } 339 | if (preCurrentIndex > items.size() - 1) { 340 | preCurrentIndex = items.size() - 1; 341 | } 342 | } else { 343 | if (preCurrentIndex < 0) { 344 | preCurrentIndex = items.size() + preCurrentIndex; 345 | } 346 | if (preCurrentIndex > items.size() - 1) { 347 | preCurrentIndex = preCurrentIndex - items.size(); 348 | } 349 | } 350 | 351 | int j2 = (int) (totalScrollY % (lineSpacingMultiplier * maxTextHeight)); 352 | // 设置as数组中每个元素的值 353 | int k1 = 0; 354 | while (k1 < itemsVisible) { 355 | int l1 = preCurrentIndex - (itemsVisible / 2 - k1); 356 | if (isLoop) { 357 | while (l1 < 0) { 358 | l1 = l1 + items.size(); 359 | } 360 | while (l1 > items.size() - 1) { 361 | l1 = l1 - items.size(); 362 | } 363 | as[k1] = items.get(l1); 364 | } else if (l1 < 0) { 365 | as[k1] = ""; 366 | } else if (l1 > items.size() - 1) { 367 | as[k1] = ""; 368 | } else { 369 | as[k1] = items.get(l1); 370 | } 371 | k1++; 372 | } 373 | canvas.drawLine(0.0F, firstLineY, measuredWidth, firstLineY, paintIndicator); 374 | canvas.drawLine(0.0F, secondLineY, measuredWidth, secondLineY, paintIndicator); 375 | 376 | int j1 = 0; 377 | while (j1 < itemsVisible) { 378 | canvas.save(); 379 | // L(弧长)=α(弧度)* r(半径) (弧度制) 380 | // 求弧度--> (L * π ) / (π * r) (弧长X派/半圆周长) 381 | float itemHeight = maxTextHeight * lineSpacingMultiplier; 382 | double radian = ((itemHeight * j1 - j2) * Math.PI) / halfCircumference; 383 | // 弧度转换成角度(把半圆以Y轴为轴心向右转90度,使其处于第一象限及第四象限 384 | float angle = (float) (90D - (radian / Math.PI) * 180D); 385 | if (angle >= 90F || angle <= -90F) { 386 | canvas.restore(); 387 | } else { 388 | int translateY = (int) (radius - Math.cos(radian) * radius - (Math.sin(radian) * maxTextHeight) / 2D); 389 | canvas.translate(0.0F, translateY); 390 | canvas.scale(1.0F, (float) Math.sin(radian)); 391 | if (translateY <= firstLineY && maxTextHeight + translateY >= firstLineY) { 392 | // 条目经过第一条线 393 | canvas.save(); 394 | canvas.clipRect(0, 0, measuredWidth, firstLineY - translateY); 395 | canvas.drawText(as[j1], getTextX(as[j1], paintOuterText, tempRect), maxTextHeight, paintOuterText); 396 | canvas.restore(); 397 | canvas.save(); 398 | canvas.clipRect(0, firstLineY - translateY, measuredWidth, (int) (itemHeight)); 399 | canvas.drawText(as[j1], getTextX(as[j1], paintCenterText, tempRect), maxTextHeight, paintCenterText); 400 | canvas.restore(); 401 | } else if (translateY <= secondLineY && maxTextHeight + translateY >= secondLineY) { 402 | // 条目经过第二条线 403 | canvas.save(); 404 | canvas.clipRect(0, 0, measuredWidth, secondLineY - translateY); 405 | canvas.drawText(as[j1], getTextX(as[j1], paintCenterText, tempRect), maxTextHeight, paintCenterText); 406 | canvas.restore(); 407 | canvas.save(); 408 | canvas.clipRect(0, secondLineY - translateY, measuredWidth, (int) (itemHeight)); 409 | canvas.drawText(as[j1], getTextX(as[j1], paintOuterText, tempRect), maxTextHeight, paintOuterText); 410 | canvas.restore(); 411 | } else if (translateY >= firstLineY && maxTextHeight + translateY <= secondLineY) { 412 | // 中间条目 413 | canvas.clipRect(0, 0, measuredWidth, (int) (itemHeight)); 414 | canvas.drawText(as[j1], getTextX(as[j1], paintCenterText, tempRect), maxTextHeight, paintCenterText); 415 | selectedItem = items.indexOf(as[j1]); 416 | } else { 417 | // 其他条目 418 | canvas.clipRect(0, 0, measuredWidth, (int) (itemHeight)); 419 | canvas.drawText(as[j1], getTextX(as[j1], paintOuterText, tempRect), maxTextHeight, paintOuterText); 420 | } 421 | canvas.restore(); 422 | } 423 | j1++; 424 | } 425 | } 426 | 427 | // 绘制文字起始位置 428 | private int getTextX(String a, Paint paint, Rect rect) { 429 | paint.getTextBounds(a, 0, a.length(), rect); 430 | // 获取到的是实际文字宽度 431 | int textWidth = rect.width(); 432 | // 转换成绘制文字宽度 433 | textWidth *= scaleX; 434 | return (measuredWidth - textWidth) / 2; 435 | } 436 | 437 | @Override 438 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 439 | this.widthMeasureSpec = widthMeasureSpec; 440 | remeasure(); 441 | setMeasuredDimension(measuredWidth, measuredHeight); 442 | } 443 | 444 | @Override 445 | public boolean onTouchEvent(MotionEvent event) { 446 | boolean eventConsumed = gestureDetector.onTouchEvent(event); 447 | float itemHeight = lineSpacingMultiplier * maxTextHeight; 448 | 449 | switch (event.getAction()) { 450 | case MotionEvent.ACTION_DOWN: 451 | startTime = System.currentTimeMillis(); 452 | cancelFuture(); 453 | previousY = event.getRawY(); 454 | break; 455 | 456 | case MotionEvent.ACTION_MOVE: 457 | float dy = previousY - event.getRawY(); 458 | previousY = event.getRawY(); 459 | 460 | totalScrollY = (int) (totalScrollY + dy); 461 | 462 | // 边界处理。 463 | if (!isLoop) { 464 | float top = -initPosition * itemHeight; 465 | float bottom = (items.size() - 1 - initPosition) * itemHeight; 466 | 467 | if (totalScrollY < top) { 468 | totalScrollY = (int) top; 469 | } else if (totalScrollY > bottom) { 470 | totalScrollY = (int) bottom; 471 | } 472 | } 473 | break; 474 | 475 | case MotionEvent.ACTION_UP: 476 | default: 477 | if (!eventConsumed) { 478 | float y = event.getY(); 479 | double l = Math.acos((radius - y) / radius) * radius; 480 | int circlePosition = (int) ((l + itemHeight / 2) / itemHeight); 481 | 482 | float extraOffset = (totalScrollY % itemHeight + itemHeight) % itemHeight; 483 | mOffset = (int) ((circlePosition - itemsVisible / 2) * itemHeight - extraOffset); 484 | 485 | if ((System.currentTimeMillis() - startTime) > 120) { 486 | // 处理拖拽事件 487 | smoothScroll(ACTION.DAGGLE); 488 | } else { 489 | // 处理条目点击事件 490 | // smoothScroll(ACTION.CLICK); 491 | } 492 | } 493 | break; 494 | } 495 | 496 | invalidate(); 497 | return true; 498 | } 499 | } 500 | -------------------------------------------------------------------------------- /library/src/main/java/com/limxing/library/LoopView/LoopViewGestureListener.java: -------------------------------------------------------------------------------- 1 | // Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov. 2 | // Jad home page: http://www.geocities.com/kpdus/jad.html 3 | // Decompiler options: braces fieldsfirst space lnc 4 | 5 | package com.limxing.library.LoopView; 6 | 7 | import android.view.MotionEvent; 8 | 9 | // Referenced classes of package com.qingchifan.view: 10 | // LoopView 11 | 12 | final class LoopViewGestureListener extends android.view.GestureDetector.SimpleOnGestureListener { 13 | 14 | final LoopView loopView; 15 | 16 | LoopViewGestureListener(LoopView loopview) { 17 | loopView = loopview; 18 | } 19 | 20 | @Override 21 | public final boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 22 | loopView.scrollBy(velocityY); 23 | return true; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /library/src/main/java/com/limxing/library/LoopView/MessageHandler.java: -------------------------------------------------------------------------------- 1 | // Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov. 2 | // Jad home page: http://www.geocities.com/kpdus/jad.html 3 | // Decompiler options: braces fieldsfirst space lnc 4 | 5 | package com.limxing.library.LoopView; 6 | 7 | import android.os.Handler; 8 | import android.os.Message; 9 | 10 | // Referenced classes of package com.qingchifan.view: 11 | // LoopView 12 | 13 | final class MessageHandler extends Handler { 14 | public static final int WHAT_INVALIDATE_LOOP_VIEW = 1000; 15 | public static final int WHAT_SMOOTH_SCROLL = 2000; 16 | public static final int WHAT_ITEM_SELECTED = 3000; 17 | 18 | final LoopView loopview; 19 | 20 | MessageHandler(LoopView loopview) { 21 | this.loopview = loopview; 22 | } 23 | 24 | @Override 25 | public final void handleMessage(Message msg) { 26 | switch (msg.what) { 27 | case WHAT_INVALIDATE_LOOP_VIEW: 28 | loopview.invalidate(); 29 | break; 30 | 31 | case WHAT_SMOOTH_SCROLL: 32 | loopview.smoothScroll(LoopView.ACTION.FLING); 33 | break; 34 | 35 | case WHAT_ITEM_SELECTED: 36 | loopview.onItemSelected(); 37 | break; 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /library/src/main/java/com/limxing/library/LoopView/OnItemSelectedListener.java: -------------------------------------------------------------------------------- 1 | // Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov. 2 | // Jad home page: http://www.geocities.com/kpdus/jad.html 3 | // Decompiler options: braces fieldsfirst space lnc 4 | 5 | package com.limxing.library.LoopView; 6 | 7 | 8 | public interface OnItemSelectedListener { 9 | void onItemSelected(LoopView view); 10 | } 11 | -------------------------------------------------------------------------------- /library/src/main/java/com/limxing/library/LoopView/OnItemSelectedRunnable.java: -------------------------------------------------------------------------------- 1 | // Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov. 2 | // Jad home page: http://www.geocities.com/kpdus/jad.html 3 | // Decompiler options: braces fieldsfirst space lnc 4 | 5 | package com.limxing.library.LoopView; 6 | 7 | // Referenced classes of package com.qingchifan.view: 8 | // LoopView, OnItemSelectedListener 9 | 10 | final class OnItemSelectedRunnable implements Runnable { 11 | final LoopView loopView; 12 | 13 | OnItemSelectedRunnable(LoopView loopview) { 14 | loopView = loopview; 15 | } 16 | 17 | @Override 18 | public final void run() { 19 | loopView.onItemSelectedListener.onItemSelected(loopView); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /library/src/main/java/com/limxing/library/LoopView/SmoothScrollTimerTask.java: -------------------------------------------------------------------------------- 1 | // Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov. 2 | // Jad home page: http://www.geocities.com/kpdus/jad.html 3 | // Decompiler options: braces fieldsfirst space lnc 4 | 5 | package com.limxing.library.LoopView; 6 | 7 | import java.util.TimerTask; 8 | 9 | final class SmoothScrollTimerTask extends TimerTask { 10 | 11 | int realTotalOffset; 12 | int realOffset; 13 | int offset; 14 | final LoopView loopView; 15 | 16 | SmoothScrollTimerTask(LoopView loopview, int offset) { 17 | this.loopView = loopview; 18 | this.offset = offset; 19 | realTotalOffset = Integer.MAX_VALUE; 20 | realOffset = 0; 21 | } 22 | 23 | @Override 24 | public final void run() { 25 | if (realTotalOffset == Integer.MAX_VALUE) { 26 | realTotalOffset = offset; 27 | } 28 | realOffset = (int) ((float) realTotalOffset * 0.1F); 29 | 30 | if (realOffset == 0) { 31 | if (realTotalOffset < 0) { 32 | realOffset = -1; 33 | } else { 34 | realOffset = 1; 35 | } 36 | } 37 | if (Math.abs(realTotalOffset) <= 0) { 38 | loopView.cancelFuture(); 39 | loopView.handler.sendEmptyMessage(MessageHandler.WHAT_ITEM_SELECTED); 40 | } else { 41 | loopView.totalScrollY = loopView.totalScrollY + realOffset; 42 | loopView.handler.sendEmptyMessage(MessageHandler.WHAT_INVALIDATE_LOOP_VIEW); 43 | realTotalOffset = realTotalOffset - realOffset; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /library/src/main/java/com/limxing/library/OnConfirmeListener.java: -------------------------------------------------------------------------------- 1 | package com.limxing.library; 2 | 3 | /** 4 | * Created by limxing on 16/5/24. 5 | */ 6 | public interface OnConfirmeListener { 7 | void result(String s); 8 | } 9 | -------------------------------------------------------------------------------- /library/src/main/java/com/limxing/library/OnDismissListener.java: -------------------------------------------------------------------------------- 1 | package com.limxing.library; 2 | 3 | /** 4 | * Created by Sai on 15/8/9. 5 | */ 6 | public interface OnDismissListener { 7 | public void onDismiss(Object o); 8 | } 9 | -------------------------------------------------------------------------------- /library/src/main/java/com/limxing/library/OnItemClickListener.java: -------------------------------------------------------------------------------- 1 | package com.limxing.library; 2 | 3 | /** 4 | * Created by Sai on 15/8/9. 5 | */ 6 | public interface OnItemClickListener { 7 | public void onItemClick(Object o, int position); 8 | } 9 | -------------------------------------------------------------------------------- /library/src/main/res/anim/alertview_bgin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /library/src/main/res/anim/alertview_bgout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /library/src/main/res/anim/fade_in_center.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /library/src/main/res/anim/fade_out_center.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /library/src/main/res/anim/slide_in_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | -------------------------------------------------------------------------------- /library/src/main/res/anim/slide_out_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | -------------------------------------------------------------------------------- /library/src/main/res/drawable/bg_actionsheet_cancel.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /library/src/main/res/drawable/bg_actionsheet_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /library/src/main/res/drawable/bg_alertbutton_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /library/src/main/res/drawable/bg_alertbutton_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /library/src/main/res/drawable/bg_alertbutton_none.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /library/src/main/res/drawable/bg_alertbutton_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /library/src/main/res/drawable/bg_alertview_alert.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /library/src/main/res/drawable/selector_pickerview_btn.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /library/src/main/res/layout/alertview_data.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 |